The Way to TiDB 3.0 and Beyond (上篇)

我司 Engineering VP 申砾在 TiDB DevCon 2019 上分享了 TiDB 产品进化过程当中的思考与将来规划。本文为演讲实录上篇,重点回顾了 TiDB 2.1 的特性,并分享了咱们对「如何作一个好的数据库」的见解。

<center>我司 Engineering VP 申砾</center>数据库

感谢这么多朋友的到场,今天我会从咱们的一些思考的角度来回顾过去一段时间作了什么事情,以及将来的半年到一年时间内将会作什么事情,特别是「咱们为何要作这些事情」安全

TiDB 这个产品,咱们从 2015 年年中开始作,作到如今,三年半,将近四年了,从最先期的 Beta 版的时候就开始上线,到后来 RC 版本,最后在 2017 年终于发了 1.0,开始铺了一部分用户,到 2.0 的时候,用户数量就开始涨的很是快。而后咱们最近发了 2.1,在 2.1 以后,咱们也和各类用户去聊,跟他们聊一些使用的体验,有什么样的问题,包括对咱们进行吐嘈。咱们就在这些实践经验基础之上,设计了 3.0 的一些特性,以及咱们的一些工做的重点。如今咱们正在朝 3.0 这个版本去演进,到今天早上已经发了 3.0 Beta 版本网络

TiDB 2.1

首先咱们来说 2.1,2.1 是一个很是重要的版本,这个版本咱们吸收了不少用户的使用场景中看到的问题,以及特别多用户的建议。在这里我跟你们聊一聊它有哪些比较重要的特性。并发

<center>图 1 TiDB 2.1 新增重要功能</center>负载均衡

首先咱们两个核心组件:存储引擎和计算引擎,在这两方面,咱们作了一些很是重要的改进,固然这些改进有多是用户看不到的。或者说这些改进其实咱们是不但愿用户能看到的,一旦你看到了,注意到这些改进的话,说明你的系统遇到这些问题了。框架

1. Raft

1.1 Learner

你们都知道 Raft 会有 Leader 和 Follower 这两个概念,Leader 来负责读写,Follower 来做为 Backup,而后随时找机会成为新的 Leader。若是你想加一个新的节点,好比说在扩容或者故障恢复,新加了一个 Follower 进来,这个时候 Raft Group 有 4 个成员, Leader、Follower 都是 Voter,都可以在写入数据时候对日志进行投票,或者是要在成员变动的时候投票的。这时一旦发生意外状况,好比网络变动或者出现网络分区,假设 2 个被隔离掉的节点都在一个物理位置上,就会致使 4 个 Voter 中 2 个不可用,那这时这个 Raft Group 就不可用了。分布式

你们可能以为这个场景并不常见,可是若是咱们正在作负载均衡调度或者扩容时,一旦出现这种状况,就颇有可能影响业务。因此咱们加了 Learner 这个角色,Learner 的功能也是咱们贡献给 etcd 这个项目的。有了 Learner 以后,咱们在扩容时不会先去加一个 Follower(也就是一个 Voter),而是增长一个 Learner 的角色,它不是 Voter,因此它只会同步数据不会投票,因此不管在作数据写入仍是成员变动的时候都不会算上它。当同步完全部数据时(由于数据量大的时候同步时间会比较长),拿到全部数据以后,再把它变成一个 Voter,同时再把另外一个咱们想下线的 Follower 下掉就行了。这样就能极大的缩短同时存在 4 个 Voter 的时间,整个 Raft Group 的可用性就获得了提高。工具

<center>图 2 TiDB 2.1 - Raft Learner</center>测试

其实增长 Learner 功能不仅是出于提高 Raft Group 可用性,或者说出于安全角度考虑,实际上咱们也在用 Learner 来作更多的事情。好比,咱们能够随便去加 Learner,而后把 Learner 变成一个只读副本,不少很重的分析任务就能够在 Learner 上去作。TiFlash 这个项目其实就是用 Learner 这个特性来增长只读副本,同时保证不会影响线上写入的延迟,由于它并不参与写入的时候投票。这样的好处是第一不影响写入延迟,第二有 Raft 实时同步数据,第三咱们还能在上面快速地作很复杂的分析,同时线上 OLTP 业务有物理上的隔离。优化

1.2 PreVote

除了 Learner 以外,咱们 2.1 中默认开启了 PreVote 这个功能。

咱们考虑一种意外状况,就是在 Raft group 中出现了网络隔离,有 1 个节点和另外 2 个节点隔离掉了,而后它如今发现「我找不到 Leader 了,Leader 可能已经挂掉了」,而后就开始投票,不断投票,可是由于它和其余节点是隔离开的,因此没有办法选举成功。它每次失败,都会把本身的 term 加 1,每次失败加 1,网络隔离发生一段时间以后,它的 term 就会很高。当网络分区恢复以后,它的选举消息就能发出去了,而且这个选举消息里面的 term 是比较高的。根据 Raft 的协议,当遇到一个 term 比较高的时候,可能就会赞成发起选举,当前的 Leader 就会下台来参与选举。可是由于发生网络隔离这段时间他是没有办法同步数据的,此时它的 Raft Log 必定是落后的,因此即便它的 term 很高,也不可能被选成新的 Leader。因此这个时候通过一次选举以后,它不会成为新 Leader,只有另外两个有机会成为新的 Leader。

你们能够看到,这个选举是对整个 Raft Group 形成了危害:首先它不可能成为新的 Leader,第二它把原有的 Leader 赶下台了,而且在这个选举过程当中是没有 Leader 的,这时的 Raft Group 是不能对外提供服务的。虽然这个时间会很短,但也可能会形成比较大的抖动。

<center>图 3 TiDB 2.1 - Raft PreVoter</center>

因此咱们有了 PreVote 这个特性。具体是这样作的(如图 3):在进行选举以前,先用 PreVote 这套机制来进行预选举,每一个成员把本身的信息,包括 term,Raft Log Index 放进去,发给其它成员,其它成员有这个信息以后,认为「我能够选你为 Leader」,才会发起真正的选举。

有了 PreVote 以后,咱们就能够避免这种大规模的一个节点上不少数据、不少 Raft Group、不少 Peer 的状况下忽然出现网络分区,在恢复以后形成大量的 Region 出现选举,致使整个服务有抖动。 所以 PreVote 能极大的提高稳定性。

2. Concurrent DDL Operation

固然除了 Raft 这几个改进以外,TiDB 2.1 中还有一个比较大的改进,就是在 DDL 模块。这是咱们 2.1 中一个比较显著的特性。

<center>图 4 TiDB 2.1 以前的 DDL 机制</center>

在 2.1 以前的 DDL 整套机制是这样的(如图 4):用户将 DDL 提交到任何一个 TiDB Server,发过来一个 DDL 语句,TiDB Server 通过一些初期的检查以后会打包成一个 DDL Job,扔到 TiKV 上一个封装好的队列中,整个集群只有一个 TiDB Server 会执行 DDL,并且只有一个线程在作这个事情。这个线程会去队列中拿到队列头的一个 Job,拿到以后就开始作,直到这个 Job 作完,即 DDL 操做执行完毕后,会再把这个 Job 扔到历史队列中,而且标记已经成功,这时 TiDB Sever 能感知到这个 DDL 操做是已经结束了,而后对外返回。前面的 Job 在执行完以前,后面的 DDL 操做是不会执行的,于是会形成一个状况: 假设前面有一个 AddIndex,好比在一个百亿行表上去 AddIndex,这个时间是很是长的,后面的 Create Table 是很是快的,但这时 Create Table 操做会被 AddIndex 阻塞,只有等到 AddIndex 执行完了,才会执行 Create Table,这个给有些用户形成了困扰,因此咱们在 TiDB 2.1 中作了改进。

<center>图 5 TiDB 2.1 - DDL 机制</center>

在 TiDB 2.1 中 DDL 从执行层面分为两种(如图 5)。一种是 AddIndex 操做,即回填数据(就是把全部的数据扫出来,而后再填回去),这个操做耗时是很是长的,并且一些用户是线上场景,并发度不可能调得很高,由于在回写数据的时候,可能会对集群的写入形成压力。

另一种是全部其余 DDL 操做,由于无论是 Create Table 仍是加一个 Column 都是很是快的,只会修改 metadata 剩下的交给后台来作。因此咱们将 AddIndex 的操做和其余有 DDL 的操做分红两个队列,每种 DDL 语句按照分类,进到不一样队列中,在 DDL 的处理节点上会启用多个线程来分别处理这些队列,将比较慢的 AddIndex 的操做交给单独的一个线程来作,这样就不会出现一个 AddIndex 操做阻塞其余全部 Create Table 语句的问题了。

这样就提高了系统的易用性,固然咱们下一步还会作进一步的并行, 好比在 AddIndex 时,能够在多个表上同时 AddIndex,或者一个表上同时 Add 多个 Index。咱们也但愿可以作成真正并行的一个 DDL 操做。

3. Parallel Hash Aggregation

除了刚刚提到的稳定性和易用性的提高,咱们在 TiDB 2.1 中,也对分析能力作了提高。咱们在聚合的算子上作了两点改进。  第一点是对整个聚合框架作了优化,就是从一行一行处理的聚合模式,变成了一批一批数据处理的聚合模式,另外咱们还在哈希聚合算子上作了并行。

<center>图 6 TiDB 2.1 - Parallel Hash Aggregation</center>

为何咱们要优化聚合算子?由于在分析场景下,有两类算子是很是重要的,是 Join 和聚合。Join 算子咱们以前已经作了并行处理,而 TiDB 2.1 中咱们进一步对聚合算子作了并行处理。在哈希聚合中,咱们在一个聚合算子里启用多个线程,分两个阶段进行聚合。这样就可以极大的提高聚合的速度。

<center>图 7 TiDB 2.0 与 TiDB 2.1 TPC-H Benchmark 对比</center>

图 7 是 TiDB 2.1 发布的时候,咱们作了一个 TPC-H Benchmark。实际上全部的 Query 都有提高,其中 Q17 和 Q18 提高最大。由于在 TiDB 2.0 测试时,Q1七、Q18 仍是一个长尾的 Query,分析以后发现瓶颈就在于聚合算子的执行。整个机器的 CPU 并不忙,但就是时间很长,咱们作了 Profile 发现就是聚合的时间太长了,因此在 TiDB 2.1 中,对聚合算子作了并行,而且这个并行度能够调节。

4. Ecosystem Tools

TiDB 2.1 发布的时咱们还发布了两个工具,分别叫 TiDB-DM 和 TiDB-Lightning。

TiDB-DM 全称是 TiDB Data Migration,这个工具主要用来把咱们以前的 Loader 和以及 Syncer 作了产品化改造,让你们更好用,它可以作分库分表的合并,可以只同步一些表中的数据,而且它还可以对数据作一些改写,由于分库分表合并的时候,数据合到一个表中可能会冲突,这时咱们就须要一种很是方便、可配置的工具来操做,而不是让用户手动的去调各类参数。

TiDB-Lightning 这个工具是用来作全量的数据导入。以前的 Loader 也能够作全量数据导入,可是它是走的最标准的那套 SQL 的流程,须要作 SQL 的解析优化、 两阶段提交、Raft 复制等等一系列操做。可是咱们以为这个过程能够更快。由于不少用户想迁移到 TiDB 的数据不是几十 G 或者几百 G,而是几 T、几十 T、上百 T 的数据,经过传统导入的方式会很是慢。如今 TiDB-Lightning 能够直接将本地从 MySQL 或者其余库中导出的 SQL 文本,或者是 CSV 格式的文件,直接转成 RocksDB 底层的 SST file ,而后再注入到 TiKV 中,加载进去就导入成功了,可以极大的提高导入速度。固然咱们还在不断的优化,但愿这个速度能不断提高,将 1TB 数据的导入,压缩到一两个小时。这两个工具,有一部分用户已经用到了(而且已经正式开源)。

How to build a good database?

咱们有至关多的用户正在使用 TiDB,咱们在不少的场景中见到了各类各样的 Case,甚至包括机器坏掉甚至连续坏掉的状况。见了不少场景以后,咱们就在想以后如何去改进产品,如何去避免在各类场景中遇到的「坑」,因而咱们在更深刻地思考一个问题:如何作一个好的数据库。由于作一个产品其实挺容易的,一我的两三个月也能搞一套数据库,无论是分库分表,仍是相似于在 KV 上作一个 SQL,甚至作一个分布式数据库,都是可能在一个季度甚至半年以内作出来的。可是要真正作一个好的数据库,作一个成熟的数据库,作一个能在生产系统中大规模使用,而且可以让用户本身玩起来的数据库,其实里面有很是多工做要作。

首先数据库最基本的是要「有用」,就是能解决用户问题。而要解决用户问题,第一点就是要知道用户有什么样的问题,咱们就须要跟各种用户去聊,看用户的场景,一块儿来分析,一块儿来得到使用场景中真实存在的问题。因此最近咱们有大量的同事,无论是交付的同事仍是研发的同事,都与用户作了比较深刻的访谈,聊聊用户在使用过程当中有什么的问题,有什么样的需求,用户也提供各类各样的建议。咱们但愿 TiDB 可以很好的解决用户场景中存在的问题,甚至是用户本身暂时尚未察觉到的问题,进一步的知足用户的各类需求。

第二点是「易用性」。就好像一辆车,手动挡的你们也能开,但其实你们如今都想开自动挡。咱们但愿咱们的数据库是一辆自动挡的车,甚至将来是一辆无人驾驶的车,让用户不须要关心这些事情,只须要专一本身的业务就行了。因此咱们会不断的优化现有的解决方案,给用户更多更好的解决方案,下一步再将这些方案自动化,让用户用更低的成本使用咱们的数据库。

最后一点「稳定性」也很是重要,就是让用户不会用着用着担惊受怕,好比半夜报警之类的事情。并且咱们但愿 TiDB 能在大规模数据集上、在大流量上也能保持稳定。

未完待续...

下篇将于明日推送,重点介绍 TiDB 3.0 Beta 在稳定性、易用性和功能性上的提高,以及 TiDB 在 Storage Layer 和 SQL Layer 方面的规划。

相关文章
相关标签/搜索