{
    "componentChunkName": "component---src-templates-blog-blog-detail-tsx",
    "path": "/blog/tidb-source-code-reading-2",
    "result": {"pageContext":{"blog":{"id":"Blogs_230","title":"TiDB 源码阅读系列文章（二）初识 TiDB 源码","tags":["TiDB 源码阅读","社区"],"category":{"name":"产品技术解读"},"summary":"本文为 TiDB 源码阅读系列文章的第二篇，第一篇文章介绍了 TiDB 整体的架构，本篇文章是一篇入门文档 enjoy~","body":"本文为 TiDB 源码阅读系列文章的第二篇，[第一篇文章](https://pingcap.com/zh/blog/tidb-source-code-reading-1)介绍了 TiDB 整体的架构，知道 TiDB 有哪些模块，分别是做什么的，从哪里入手比较好，哪些可以忽略，哪些需要仔细阅读。\n\n这篇文章是一篇入门文档，难度系数比较低，其中部分内容可能大家在其他渠道已经看过，不过为了内容完整性，我们还是会放在这里。\n\n## TiDB 架构\n\n![TiDB 架构](https://img1.www.pingcap.com/prod/1_1c599fdd36.png)\n\n<div class=\"caption-center\">TiDB 架构</div>\n\n本次 TiDB 源码之旅从这幅简单的架构图开始，这幅图很多人都看过，我们可以用一句话来描述这个图：『TiDB 是一个支持 MySQL 协议，以某种支持事务的分布式 KV 存储引擎为底层存储的 SQL 引擎』。从这句话可以看出有三个重要的事情，第一是如何支持 MySQL 协议，与 Client 交互，第二是如何与底层的存储引擎打交道，存取数据，第三是如何实现 SQL 的功能。本篇文章会先介绍一些 TiDB 有哪些模块及其功能简要介绍，然后以这三点为线索，将这些模块串联起来。\n\n## 代码简介\n\nTiDB 源码完全托管在 Github 上，从[项目主页](https://github.com/pingcap/tidb \"项目主页\")可以看到所有信息。整个项目使用 Go 语言开发，按照功能模块分了很多 Package，通过一些依赖分析工具，可以看到项目内部包之间的依赖关系。\n\n大部分包都以接口的形式对外提供服务，大部分功能也都集中在某个包中，不过有一些包提供了非常基础的功能，会被很多包依赖，这些包需要特别注意。\n\n项目的 main 文件在 tidb-server/main.go，这里面定义了服务如何启动。整个项目的 Build 方法可以在 [Makefile](https://github.com/pingcap/tidb/blob/source-code/Makefile#L140) 中找到。\n\n除了代码之外，还有很多测试用例，可以在 xx\\_test.go 中找到。另外 `cmd` 目录下面还有几个工具包，用来做性能测试或者是构造测试数据。\n\n## 模块介绍\nTiDB 的模块非常多，这里做一个整体介绍，大家可以看到每个模块大致是做什么用的，想看相关功能的代码是，可以直接找到对应的模块。\n\n| Package | Introduction |\n| ------------- | :-------------: |\n| ast | 抽象语法树的数据结构定义，例如 `SelectStmt` 定义了一条 Select 语句被解析成什么样的数据结构 |\n| cmd/benchdb | 简单的 benchmark 工具，用于性能优化 |\n| cmd/benchfilesort | 简单的 benchmark 工具，用于性能优化 |\n| cmd/benchkv | Transactional KV API benchmark 工具，也可以看做 KV 接口的使用样例 |\n| cmd/benchraw | Raw KV API benchmark 工具，也可以看做不带事务的 KV 接口的使用样例 |\n| cmd/importer | 根据表结构以及统计信息伪造数据的工具，用于构造测试数据 |\n| config | 配置文件相关逻辑 |\n| context | 主要包括 Context 接口，提供一些基本的功能抽象，很多包以及函数都会依赖于这个接口，把这些功能抽象为接口是为了解决包之间的依赖关系 |\n| ddl | DDL 的执行逻辑 |\n| distsql | 对分布式计算接口的抽象，通过这个包把 Executor 和 TiKV Client 之间的逻辑做隔离 |\n| domain | domain 可以认为是一个存储空间的抽象，可以在其中创建数据库、创建表，不同的 domain 之间，可以存在相同名称的数据库，有点像 Name Space。一般来说单个 TiDB 实例只会创建一个 Domain 实例，其中会持有 information schema 信息、统计信息等。 |\n| executor | 执行器相关逻辑，可以认为大部分语句的执行逻辑都在这里，比较杂，后面会专门介绍 |\n| expression | 表达式相关逻辑，包括各种运算符、内建函数 |\n| expression/aggregation | 聚合表达式相关的逻辑，比如 Sum、Count 等函数 |\n| infoschema | SQL 元信息管理模块，另外对于 Information Schema 的操作，都会访问这里 |\n| kv | KV 引擎接口以及一些公用方法，底层的存储引擎需要实现这个包中定义的接口 |\n| meta | 利用 structure 包提供的功能，管理存储引擎中存储的 SQL 元信息，infoschema/DDL 利用这个模块访问或者修改 SQL 元信息 |\n| meta/autoid | 用于生成全局唯一自增 ID 的模块，除了用于给每个表的自增 ID 之外，还用于生成全局唯一的 Database ID 和 Table ID |\n| metrics | Metrics 相关信息，所有的模块的 Metrics 信息都在这里 |\n| model | SQL 元信息数据结构，包括 DBInfo / TableInfo / ColumnInfo / IndexInfo 等 |\n| mysql | MySQL 相关的常量定义 |\n| owner | TiDB 集群中的一些任务只能由一个实例执行，比如异步 Schema 变更，这个模块用于多个 tidb-server 之间协调产生一个任务执行者。每种任务都会产生自己的执行者。 |\n| parser | 语法解析模块，主要包括词法解析 (lexer.go) 和语法解析 (parser.y)，这个包对外的主要接口是 Parse()，用于将 SQL 文本解析成 AST |\n| parser/goyacc | 对 GoYacc 的包装 |\n| parser/opcode | 关于操作符的一些常量定义 |\n| perfschema | Performance Schema 相关的功能，默认不会启用 |\n| plan | 查询优化相关的逻辑 |\n| privilege | 用户权限管理接口|\n| privilege/privileges | 用户权限管理功能实现 |\n| server | MySQL 协议以及 Session 管理相关逻辑 |\n| sessionctx/binloginfo | 向 Binlog 模块输出 Binlog 信息 |\n| sessionctx/stmtctx | Session 中的语句运行时所需要的信息，比较杂 |\n| sessionctx/variable | System Variable 相关代码 |\n| statistics | 统计信息模块 |\n| store | 储存引擎相关逻辑，这里是存储引擎和 SQL 层之间的交互逻辑 |\n| store/mockoracle | 模拟 TSO 组件 |\n| store/mockstore | 实例化一个 Mock TiKV 的逻辑，主要方法是 NewMockTikvStore，把这部分逻辑从 mocktikv 中抽出来是避免循环依赖 |\n| store/mockstore/mocktikv | 在单机存储引擎上模拟 TiKV 的一些行为，主要作用是本地调试、构造单元测试以及指导 TiKV 开发 Coprocessor 相关逻辑 |\n| store/tikv | TiKV 的 Go 语言 Client |\n| store/tikv/gcworker | TiKV GC 相关逻辑，tidb-server 会根据配置的策略向 TiKV 发送 GC 命令 |\n| store/tikv/oracle | TSO 服务接口 |\n| store/tikv/oracle/oracles | TSO 服务的 Client |\n| store/tikv/tikvrpc | TiKV API 的一些常量定义 |\n| structure | 在 Transactional KV API 上定义的一层结构化 API，提供 List/Queue/HashMap 等结构 |\n| table | 对 SQL 的 Table 的抽象|\n| table/tables | 对 table 包中定义的接口的实现 |\n| tablecodec | SQL 到 Key-Value 的编解码，每种数据类型的具体编解码方案见 `codec` 包 |\n| terror | TiDB 的 error 封装 |\n| tidb-server | 服务的 main 方法 |\n| types | 所有和类型相关的逻辑，包括一些类型的定义、对类型的操作等 |\n| types/json | json 类型相关的逻辑 |\n| util | 一些实用工具，这个目录下面包很多，这里只会介绍几个重要的包 |\n| util/admin | TiDB 的管理语句（ `Admin` 语句）用到的一些方法 |\n| util/charset | 字符集相关逻辑 |\n| util/chunk | Chunk 是 TiDB 1.1 版本引入的一种数据表示结构。一个 Chunk 中存储了若干行数据，在进行 SQL 计算时，数据是以 Chunk 为单位在各个模块之间流动 |\n| util/codec | 各种数据类型的编解码 |\n| x-server | X-Protocol 实现|\n\n## 从哪里入手\n\n粗看一下 TiDB 有 80 个包，让人觉得无从下手，不过并不是所有的包都很重要，另外一些功能只会涉及到少量包，从哪里入手去看源码取决于看源码的目的。\n\n如果是想了解某一个具体的功能的实现细节，那么可以参考上面的模块简介，找到对应的模块即可。\n\n如果想对源码有全面的了解，那么可以从 tidb-server/main.go 入手，看 tidb-server 是如何启动，如何等待并处理用户请求。再跟着代码一直走，看 SQL 的具体执行过程。另外一些重要的模块，需要看一下，知道是如何实现的。辅助性的模块，可以选择性的看一下，有大致的印象即可。\n\n## 重要模块\n\n在全部 80 个模块中，下面几个模块是最重要的，希望大家能仔细阅读。\n\n- plan\n- expression\n- executor\n- distsql\n- store/tikv\n- ddl\n- tablecodec\n- server\n- types\n- kv\n- tidb\n\n## 辅助模块\n\n除了重要的模块之外，余下的是辅助模块，但并不是说这些模块不重要，只是说这些模块并不在 SQL 执行的关键路径上，我们也会用一定的篇幅描述其中的大部分包。\n\n## SQL 层架构\n\n![SQL 层架构](https://img1.www.pingcap.com/prod/2_a7f34487c3.png)\n\n<div class=\"caption-center\">SQL 层架构</div>\n\n这幅图比上一幅图详细很多，大体描述了 SQL 核心模块，大家可以从左边开始，顺着箭头的方向看。\n\n### Protocol Layer\n\n最左边是 TiDB 的 Protocol Layer，这里是与 Client 交互的接口，目前 TiDB 只支持 MySQL 协议，相关的代码都在 `server` 包中。\n\n这一层的主要功能是管理客户端 connection，解析 MySQL 命令并返回执行结果。具体的实现是按照 MySQL 协议实现，具体的协议可以参考 [MySQL 协议文档](https://dev.mysql.com/doc/internals/en/client-server-protocol.html)。这个模块我们认为是当前实现最好的一个 MySQL 协议组件，如果大家的项目中需要用到 MySQL 协议解析、处理的功能，可以参考或引用这个模块。\n\n连接建立的逻辑在 server.go 的 [Run()](https://github.com/pingcap/tidb/blob/source-code/server/server.go#L236) 方法中，主要是下面两行：\n\n\t236:         conn, err := s.listener.Accept()\n\t\n\t258:         go s.onConn(conn)\n\n单个 Session 处理命令的入口方法是调用 clientConn 类的 [dispatch 方法](https://github.com/pingcap/tidb/blob/source-code/server/conn.go#L465)，这里会解析协议并转给不同的处理函数。\n\n### SQL Layer\n\n大体上讲，一条 SQL 语句需要经过，语法解析--\\>合法性验证--\\>制定查询计划--\\>优化查询计划--\\>根据计划生成查询器--\\>执行并返回结果 等一系列流程。这个主干对应于 TiDB 的下列包：\n\n| Package |  作用 |\n| ------------- | ------------- |\n| tidb | Protocol 层和 SQL 层之间的接口|\n| parser | 语法解析 |\n| plan |  合法性验证 +  制定查询计划 + 优化查询计划 |\n| executor | 执行器生成以及执行 |\n| distsql | 通过 TiKV Client 向 TiKV 发送以及汇总返回结果 |\n| store/tikv | TiKV Client |\n\n### KV API Layer\nTiDB 依赖于底层的存储引擎提供数据的存取功能，但是并不是依赖于特定的存储引擎（比如 TiKV），而是对存储引擎提出一些要求，满足这些要求的引擎都能使用（其中 TiKV 是最合适的一款）。\n\n最基本的要求是『带事务的 Key-Value 引擎，且提供 Go 语言的 Driver』，再高级一点的要求是『支持分布式计算接口』，这样 TiDB 可以把一些计算请求下推到 存储引擎上进行。\n\n这些要求都可以在 `kv` 这个包的[接口](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go)中找到，存储引擎需要提供实现了这些接口的 Go 语言 Driver，然后 TiDB 利用这些接口操作底层数据。\n\n对于最基本的要求，可以重点看这几个接口：\n\n* [Transaction](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L121)：事务基本操作\n\n* [Retriever ](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L75)：读取数据的接口\n\n* [Mutator](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L91)：修改数据的接口\n\n* [Storage](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L229)：Driver 提供的基本功能\n\n* [Snapshot](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L214)：在数据 Snapshot 上面的操作\n\n* [Iterator](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L255)：`Seek` 返回的结果，可以用于遍历数据\n\n有了上面这些接口，可以对数据做各种所需要的操作，完成全部 SQL 功能，但是为了更高效的进行运算，我们还定义了一个高级计算接口，可以关注这三个 Interface/struct :\n\n* [Client](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L150)：向下层发送请求以及获取下层存储引擎的计算能力\n\n* [Request](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L176): 请求的内容\n\n* [Response](https://github.com/pingcap/tidb/blob/source-code/kv/kv.go#L204): 返回结果的抽象\n\n## 小结\n\n至此，读者已经了解了 TiDB 的源码结构以及三个主要部分的架构，更详细的内容会在后面的章节中详细描述。\n\n> 点击查看更多 [TiDB 源码阅读系列文章](https://pingcap.com/zh/blog/?tag=TiDB%20%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB)","date":"2018-03-02","author":"申砾","fillInMethod":"writeDirectly","customUrl":"tidb-source-code-reading-2","file":null,"relatedBlogs":[]}}},
    "staticQueryHashes": ["1327623483","1820662718","3081853212","3430003955","3649515864","4265596160","63159454"]}