databend源码阅读系列:开篇

Databend Databend     2022-12-02     501

关键词:

前言

Databend 在 2021 年开源后,陆续受到了很多社区同学的关注。Databend 使用了 Rust 编程语言。为了吸引更多的开发者,特别是没有 Rust 开发经验的新同志,我们设计了 Rust 相关课程,同时建立了多个 Rust 兴趣小组。
Databend 在 issue 中还引入了“Good First issue”的 label 来引导社区新同学参与第一次贡献,目共有超过一百多位 contributors,算是一个不错的成果。
但 Databend 也在过去的一年中经历了数次迭代,代码日渐复杂。目前代码主干分支有 26 w 行 rust 代码,46 个 crate,对于新接触 Databend 的技术爱好者来说,贡献门槛越来越高。即使是熟悉 rust 的同学,clone 代码后,面对着茫茫码海,竟不知如何读起。在多个社区群中,也有朋友数次提到什么时候能有一个 Databend 源码阅读系列文章,帮助大家更快熟悉 Databend 代码。
因此,我们接下来会开展“Databend 源码阅读”系列文章,主要受众是社区技术开发者,希望通过源码阅读,来加强和社区的技术交流,引发更多思维碰撞。Databend 的故事

Databend 的故事

很多同学都问过我们一个问题:为什么你们要用 Rust 从零构建一个数据库?其实这个问题可以分为两个子问题:

1.为什么选择的是 Rust?

答:我们早期的成员大多是 ClickHouse、tidb 、tokudb 等知名数据库的贡献者,从技术栈来说更熟悉的是 C++ 和 Go。虎哥@bohutang 在疫情期间也使用 Go 实现了一个小的数据库原型 vectorsql有同学表示 vectorsql 的架构非常优雅,值得学习借鉴。


语言本没有孰劣之分,要从面向的场景来聊聊。目前大多的 DMBS 使用的是 C++/Java,新型的 NewSQL 更多使用的是 Go。在以往的开发经验来看,C/C++ 已经是高性能的代名词,开发者更容易写出高运行效率的代码,但 C++ 的开发效率实在不忍直视,工具链不是很完善,开发者很难一次性写出内存安全,并发安全的代码。而 Go 可能是另外一个极端,大道至简,工具链完善,开发效率非常高,不足之处在于泛型的进度太慢了,在 DB 系统上内存不能很灵活的控制,且难于达到前者的运行性能,尤其使用 SIMD 指令还需要和汇编代码交互等。我们需要的是兼具 开发效率(内存安全,并发安全,工具链完善)& 运行效率 的语言,当时看来,Rust 可能是我们唯一的选择了,历经尝试后,我们也发现,Rust 不仅能满足我们的需求,而且很酷!

2.为什么要从零构建一个数据库系统?

总体来说,路线无非就以下两条:

  • 基于知名的开源数据库做二次开发优化

这条路线可能更多人会选择,因为有一个好的数据库底座,无需再做一些重复性的工作,在上面做二次开发的话能省不少力气,团队专注做优化改进重构,能更早推动版本,落地商业化。缺点是 fork 后的版本难于再次回馈到社区,相当于另外一套独立的系统,如 PG 下的各个子流派。

  • 从零构建一套新的数据库系统

这条路线走起来比较艰难,因为数据库系统实在太庞大了,一个子方向都足够专业人士深入研究十几年。这个方向虽然没能直接站在已有的底座上,但会让设计者更加灵活可控,无需关注太多历史的包袱。Databend 在设计之初面向的是云原生数仓的场景,和传统的数据库系统有很大的区别,如果基于传统数据库系统来做,改造代码的成本和从零做的成本可能差不多,因此我们选择的是这条路来从零打造一个全新的云数仓。

Databend 的架构

画虎画皮难画骨,我们先从 Databend 的“骨”聊起

虽然我们是使用 Rust 从零开始实现的,但不是完全闭门造轮子,一些优秀的开源组件或者生态也有在其中集成。如:我们兼容了 Ansi-SQL 标准,提供了 MySQL/ClickHouse 等主流协议的支持,拥抱了万物互联的 Arrow 生态,存储格式基于大数据主流的 Parquet 格式等。我们不仅会积极地回馈了贡献给上游,如 Arrow2/Tokio 等开源库,一些通用的组件我们也抽成独立的项目开源在 Github(openraft, opendal, opencache, opensrv 等)。

Databend 定义为云原生的弹性数据库,在设计之初我们不仅要做到计算存储分离,每一层的极致的弹性都是设计主要考量点。Databend 主要分为三层:MetaService Layer,Query Layer,Storage Layer,这三层都是可以弹性扩展的,意味着用户可以为自己的业务选择最适合的集群规模,并且随着业务发展来伸缩集群。

下面我们将从这三层来介绍下 Databend 的主要代码模块

Databend 的模块

  • MetaService Layer

MetaService 主要用于存储读取持久化的元数据信息,比如 Catalogs/Users 等。

包名 作用
metasrv MetaService 服务,作为独立进程部署,可部署多个组成集群,底层使用 Raft 做分布式共识,Query 以 Grpc 和 MetaService 交互。
common/meta/types 定义了各类需要保存在 MetaService 的结构体,由于这些结构体最终需要持久化,所以涉及到数据序列化的问题,当前使用 Protobuf 格式来进行序列化和反序列化操作,这些类型相关的 Rust 结构体与 Protobuf 的相互序列化规则代码定义在 common/proto-conv 子目录中。
common/meta/sled-store 当前 MetaService 使用 sled 来保存持久化数据,这个子目录封装了 sled 相关的操作接口。
common/meta/raft-store openraft 用户层需要实现 raft store 的存储接口用于保存数据,这个子目录就是 MetaService 实现的 openraft 的存储层,底层依赖于 sled 存储,同时这里还实现了 openraft 用户层需要自定义的状态机。
common/meta/api 对 query 暴露的基于 KVApi 实现的用户层 api 接口。
common/meta/grpc 基于 grpc 封装的 client,MetaService 的客户端使用这里封装好的 client 与 MetaService 进行通信交互。
raft https://github.com/datafuselabs/openraft,从 async-raft 项目中衍生改进的全异步 Raft 库。
  • Query Layer

Query 节点主要用于计算,多个 query 节点可以组成 MPP 集群,理论上性能会随着 query 节点数水平扩展。SQL 在 query 中会经历以下几个转换过程

从 SQL 字符串经过 Parser 解析成 AST 语法树,然后经过 Binder 绑定 catalog 等信息转成逻辑计划,再经过一系列优化器处理转成物理计划,最后遍历物理计划构建对应的执行逻辑。query 涉及的模块有:

包名 作用
query Query 服务,整个函数的入口在 bin/databend-query.rs其中包含一些子模块,这里介绍下比较重要的子模块:1.api:对外暴露给外部的 HTTP/RPC 接口2.catalogs:catalogs 管理,目前支持默认的 catalog(存储在 metaservice)以及 hive catalog (存储在 hive meta store)3.Clusters:query 集群信息4.Config:query 的配置相关5.databases:query 支持的 database engine 相关6.evaluator:表达式计算工具类7.Interpreters:SQL 执行器,SQL 构建出 Plan 后,通过对应执行器去做物理执行8.pipelines:实现了物理算子的调度框架9.Servers:对外暴露的服务,有 clickhouse/mysql/http 等10. Sessions:session 管理相关11. Sql:包含新的 planner 设计,新的 binder 逻辑,新的 optimizers 设计12. Storages:表引擎相关,最常用为 fuse engine13. table_functions:表函数相关,如 numbers
common/ast 基于 nom_rule 实现的新版 sql parser
common/datavalues 各类 Column 的定义,表示数据在内存上的布局, 后续会逐步迁移到 common/expressions
common/datablocks Datablock 表示 Vec<Column> 集合,里面封装了一些常用方法,  后续会逐步迁移到 common/expressions
common/functions 标量函数以及聚合函数等实现注册
common/hashtable 实现了一个线性探测的 hashtable,主要用于 group by 聚合函数以及 join 等场景
common/formats 负责数据对外各类格式的 序列化反序列化,如 CSV/TSV/Json 格式等
opensrv https://github.com/datafuselabs/opensrv
  • Storage Layer

Storage 主要涉及表的 Snapshots,Segments 以及索引信息等管理,以及和底层 IO 的交互。Storage 目前一大亮点是基于 Snapshot 隔离 实现了类似 Iceberge 方式的 Increment view,  我们可以对表在任意历史状态下进行 time travel 访问。

后续规划

源码阅读系列刚刚开始撰写,后续预计将按照介绍各个模块的方式进行逐步讲解,输出主要以文章为主,一些比较重要且有趣的模块设计可能会以视频直播的方式和大家一起交流。
目前只是一个初步的规划,在这个过程中会接受大家的建议做一些时间内容调整。无论如何,我们都期待通过这个系列的活动,让更多志同道合的人参与到 Databend 的开发中来,一起学习交流成长。关于 Databend关于 DatabendDatabend 是一款开源、弹性、低成本,基于对象存储也可以做实时分析的新式数仓。期待您的关注,一起探索云原生数仓解决方案,打造新一代开源 Data Cloud。

关于 Databend

Databend 是一款开源、弹性、低成本,基于对象存储也可以做实时分析的新式数仓。期待您的关注,一起探索云原生数仓解决方案,打造新一代开源 Data Cloud。


文章首发于公众号:Databend

源码中的设计模式--开篇

...式的文章以及书籍,想看完全可以从网上去看,但真正从源码上去分析设计模式的实属不多,我之所以选定这样一个角度去研究设计模式,一则是因为自己平时会看一不部分源码一个爱写文章的程序员,欢迎关注我的公众号“北... 查看详情

androidjetpack从使用到源码深耕开篇

...AndroidJetpack小编一直在用,但是从未对于其中的某些组件源码,进行过深入的探索、学习。今年2023疫情过去了,借这个机会,我们在接下来的系列文章中,旨在从使用入手,深入理解、阅读、分析Jetpack各个经典组件的源码,了... 查看详情

spring实战----开篇(包含系列目录链接)

...应用mango为例,来分析Spring各个模块的技术,包括源码解析等,谨以此记!!! 【Spring实战】----开发环境配置【Spring实战】----Spring配置文件的解析【Spring实 查看详情

spring源码学习笔记

 Spring源码学习笔记(五)  前言--    最近花了些时间看了《Spring源码深度解析》这本书,算是入门了Spring的源码吧。打算写下系列文章,回忆一下书的内容,总结代码的运行流程。推荐那些和我一样没接触过SSH框架... 查看详情

spring源码学习笔记

Spring源码学习笔记(七)  前言--    最近花了些时间看了《Spring源码深度解析》这本书,算是入门了Spring的源码吧。打算写下系列文章,回忆一下书的内容,总结代码的运行流程。推荐那些和我一样没接触过SSH框架源码... 查看详情

databend存储架构总览

目的通过本篇文章带大家理解一下Databend的存储结构。Databend内置的Table引擎为Fusetableengine,也是接下来要花重点篇幅讲的。另外,Databend还支持外置的Hivetable及IcebregTable(即将到来)。Fusetable是Databend直接把数据存储到S3类对... 查看详情

带着问题读tidb源码:hive元数据使用tidb启动报错

《带着问题读源码系列》-开篇在TiDB社区活跃较久的伙伴们应该知道,过去我们有被称为24章经的《TiDB源码阅读系列文章》,也有面向TiKV的《TiKV源码解析系列文章》以及《DeepDiveTiKV系列文章》。这些系列文章的内容非常... 查看详情

elasticstack系列之十六&elasticsearch5.xindex/create和update源码分析

...性能更加好的。准备  使用IntellijIDEA来阅读ElasticSearch源码,操作相 查看详情

问答形式阅读jquery源码

笔者阅读了园友艾伦Aaron的系列博客《jQuery源码分析系列》,主要是阅读的jQuery的原理,然后跑园友的代码,真正对jQuery源码的阅读并不多。主要是直接阅读jQuery源码,一次能读懂的部分并不多,不如先阅读源码解析的文章,然... 查看详情

wpfstepbystep系列-开篇

WPF系列包含的内容 WPF基础知识介绍WPF布局介绍WPF控件介绍(包含第三方控件)WPF自定义模板WPF依赖属性、路由事件WPF的MVVM编程WPF开发框架PrismWPF开发框架WAFWPF开发框架CaliburnWPF为什么我们选择? 介绍     &n... 查看详情

vue3源码阅读分析系列文章(持续更新中...)

...明:以下所有文章,均为原创,是在阅读(抄)源码过程中的点滴记录,文笔有限,只是个人记录,分享出来希望有所用处。抄写的仓库:https://github.com/gcclll/stb-vue-next.git该仓库为学习时&#x 查看详情

[eshoponcontainers学习系列]-index-开篇索引

【资料】 学习资料来源于 eShopOnContainerswiki 以及 微软官方微服务架构指南    查看详情

tensorflow源码解析系列文章索引

文章索引framework解析resourceallocatortensoropnodekernelgraphdevicefunctionshape_inferencecommon_runtime解析devicesessiongraph_optimizerexecutor-1executor-2direct_session后记关于起源阅读tensorflow源码时,为了敦促自己主动思考,把阅读的笔 查看详情

算法系列教程01-开篇(代码片段)

...没有更新文章了,对不起大家。今天开始,我要写另一个系列教程:算法。开篇语为什么要写算法系列教程呢?因为最近刚看完《Algorithms,4thEdition》这本经典算法书(电子书,中英版网上都有下载),有了些新收获,觉得那些零... 查看详情

nodejs系列-01-开篇

1.解决什么问题1.并发连接举个例子,想象一个场景,我们在银行排队办理业务,我们看看下面两个模型。(1)系统线程模型:这种模型的问题显而易见,服务端只有一个线程,并发请求(用户)到达只能处理一个,其余的要先... 查看详情

jdk1.9集合框架源码阅读——map系列——有趣的问题及源码解答

...不存在该key,第二种是该key对应的值就是null。解答官方源码注释给出了解决方法:意思是说,当出现这种情况时,我们可以通过containsKey方法来区分这两种 查看详情

阅读源码(iv)

往期系列:《由阅读源码想到》《由阅读源码想到|下篇》《阅读源码(III)》  Eric S.Raymond的写于2014年的《Howtolearn hacking》是一篇出色的谈论如何阅读源码的文章。(Eric这里的hacking技术,指的是开源项目里的一种ane... 查看详情

javascript系列:函数式编程(开篇)

前言:上一篇介绍了函数回调,高阶函数以及函数柯里化等高级函数应用,同时,因为正在学习JavaScript·函数式编程,想整理一下函数式编程中,对于我们日常比较有用的部分。 为什么函数式编程很重要?   学习... 查看详情