看 PingCAP 如何用 TiDB 解决分布式数据库水平扩展难题?

百家 作者:PingCAP 2017-06-16 11:10:45

近日,我司联合创始人崔秋受邀参加拓扑社第 54 期拓扑秀 “ FreesData ” 线上技术分享活动。以下是活动分享实录,大约 7000 字,enjoy~ ?

很高兴跟大家做分享和交流,今天的主题是云数据库 TiDB 的大数据场景应用。我先简单介绍下我自己,我是 PingCAP 的联合创始人崔秋,之前在搜狗,豌豆荚一直做广告系统 infra 相关的设计和研发工作。

 15 年初,我们看到了当前数据库方面遇到的各种问题,同时也看到了学术界和工业界最前沿的一些发展方向,所以和刘奇( PingCAP 联合创始人、CEO )、黄东旭( PingCAP 联合创始人、CTO ) 一拍即合,一起创立了 PingCAP,致力于打造一款改变未来的开源数据库。很多人都听过我们做的事情,我们做的分布式数据库叫 TiDB,之前一直有人“八卦”为什么叫 TiDB ,这里也稍微解释下,Ti(钛)是一种贵重的航空金属,通过名字就大概可以理解我们的愿景——要把 TiDB 打造成最安全最可靠的数据库。当然 TiDB 提供的价值不止于此,我会进一步展开分享。

我要介绍的内容主要包括四个部分:第一部分主要和大家聊一聊整个数据库的发展历史;第二部分介绍一下 TiDB 和现在已有的 NoSQL 和 MySQL Proxy 方案的异同和它特点;第三部分讲一下大概什么场景和具体怎样去使用 TiDB ;第四部分,分享一下 TiDB 的发展计划。

数据库的发展历史

这是关于数据库发展历史介绍的设计图:

一般会把数据库分成三个阶段:最早的起源于 20 世纪 70 年代的单机型数据库;2010 年到 2015 年这个阶段出现的 NoSQL 、MySQL Proxy 和中间件相关的一些数据库;以及从 2015 年开始的 NewSQL 数据库。

我们先从单机型数据库开始,它起源于 20 世纪 70 年代,当时的数据量也没有现在这么大,基本上一台服务器就能把数据很好地存储下来,也基本不涉及到分布式的问题;当时的业务场景也没有现在这么复杂。所以当时数据库的主要作用有两点,第一是把数据很好地存储下来,第二是从存储的数据里面比较高效快速地读取所需要的信息。比较有代表性的关系型数据库有商业的 Oracle 、DB2 ,开源的 MySQL 和 PostgreSQL 还有一个微软的 SQL Server 。在很长一段时间里,因为数据量和业务模型没有现在这么复杂,所以单机数据库一直可以很好地工作。

进入到 21 世纪的时候,情况有了很大的变化。随着移动互联网、智能硬件以及云技术相关技术的成熟,数据规模呈现了爆发式增长,单机数据库已经不能存储下全部的数据。所以学术界和工业界开始探索如何解决海量数据的存储问题。主要有几种不同的解决思路,我们分别介绍下:

首先,我们来看看 NoSQL 它解决了什么问题,也同样的引来了什么问题。


说到 NoSQL,就要提到 Google BigTable 和 Amazon Dynamo 为代表的新一代数据库。在开源领域一般大家讨论比较多的主要有三种,主要以 HBase,Cassandra 和 MongoDB 作为典型代表。我们不去讨论具体的不同数据库的优劣,主要看一下 NoSQL 这个群体带来的一些解决方案上的变化。

NoSQL 所处的技术环境下,技术人员发现很难在保证传统 ACID 事务和 SQL 支持的基础上解决数据库的扩展性问题。当时首要的问题还是先解决数据的分布式存储问题,把数据存下来,至于其他问题,等以后再慢慢解决,或者通过应用层配合来解决。另外对于有些业务场景,比如下载排行榜这类比较简单的业务,确实 NoSQL 已经可以很好地解决问题了,所以当时大家认为好像发现了一条特别清晰的、值得探索的道路,是不是真的如此呢?实践证明并不是。本身因为缺少事务以及相关的 SQL 支持,所以在涉及订单、支付等核心交易场景下,NoSQL 是没有办法提供很好的解决方案的,特别是限制了在严肃业务场景下的使用。相应的,如果应用层需要事务或者需要一个关联查询,这些工作全部转嫁给了应用开发人员,由应用的开发人员来保证逻辑的正确性,这样做反而增加了出错的可能性。而好处是 NoSQL 确实解决了Scale 扩展性的问题。

除了 NoSQL 的另外一种流派是怎么做的呢?这种流派就是在传统的关系型数据库的基础上去探索基于Proxy或者中间件的方案。下面所有这些就统称为 Proxy了,这是一类的分库分表的方案。

它相比 NoSQL 放弃了一些传统数据库的特性,传统的数据库领域的开发者也在摸索怎么通过尽量保持原有特性的方式解决这个问题,有两个比较重要的方向,一个是 Scale Up,一个是 Scale Out。

说到 Scale Up,就不得不提 Oracle,Oracle 典型的方案是 Oracle RAC 。通过共享存储的硬件方案解决集群问题,也就是大家常说的 Scale Up 方案,这种方案除了比较大的成本问题,扩展方面也不是太灵活,需要提前预估好大概的容量,以及今后的可能增长的容量,而且节点数太多的时候会带来比较严重的征用问题。

那么在 MySQL 这个相比于 Oracle 更活跃的开源社区的话,他们是怎么做的呢?MySQL Proxy 和中间件 Middleware ,严格来说这也是一种分布式的方案,也就是大家经常讨论的 Scale Out 的方案,只不过这种分布式方案带有一定妥协,主要的原理是通过业务上指定的Sharding Key ,当然这个 Sharding Key 是可以组合的。将数据进行分片,国内在这个领域有过很多闭源和开源的项目,甚至每家比较大的公司都会自己搞一套,比如阿里的Cobar、TDDL,后来社区基于 Cobar 改进的 MyCAT ,360 开源的 Atlas,金山的 Kingshard, Youtube 的 Vitess 等都属于这一类,基本上可以认为是 NewSQL 类产品出现之前业界最好的解决方案了,包括 Google 在很长一段时间,其广告系统也采用的是 MySQL Proxy 的方案。

但是这种方案也不是最完美的,它也有很多的问题,从两个方面来看:

首先是数据分布问题,前面已经说了,MySQL Proxy 会通过 Sharding Key 把数据进行 Hash,存储在不同的数据库分片上,这个方案的假设就是,我的 Sharding Key 维度之间是相互独立的,举一个电商的例子如果以卖家 UserID 作为 Sharding Key,存储卖家购买商品的信息,MySQL Proxy 的方案希望 User 和 User 之间是相互独立的,没有依赖关系。这种做法实际上限制了业务场景,比如说我们可能有一个需求,统计下当天既买了分片 1 上面的卖家 A 又买了分片 3 上面卖家 B 的买家信息,这种业务需求就涉及到横跨不同数据库分片,需要进行一些聚合操作,MySQL Proxy 的方案就不能很好地支持了。

还有一个问题是跨不同数据库分片的分布式事务问题,简单来说,就是要么保证所有的数据库分片要么全部成功,要么全部失败。典型的比如转账操作,比如说我转给谁多少钱,如果中间出现了我的钱少了,他的钱没加,或者说其他的不同的情况,都是错误的情况。因为 MySQL  Proxy 底层数据真正存储的实际上是不同的 MySQL 实例,很难去保证跨不同数据库分片之间一致性的操作的问题。这种方案在解决分布式事务方面是有问题的,当然可以通过外部增加类似一个事务管理器的方式,但又会引入额外的问题,这里不展开讨论。当然这个方法最大的问题就是很难保证不停机操作,特别是在扩容的过程中,如果遇到分片数据校验失败或者某个节点出现 Crash 等异常场景,就会处于一个非常糟糕的中间状态,让运维变得非常的复杂,甚至容易出错,增加了很多的新的负担。

从另外一个维度去看这个架构的问题,讨论完数据分布,我们再来看看数据复制方面的情况。有一句话说的比较中肯,在分布式领域里面,最核心的问题就是数据的一致性问题。MySQL Proxy 这个方案里面,其实最直观的体现就是在数据复制方面。MySQL Proxy 主要解决的问题就是数据分片的逻辑管理问题。我们也提到了最底层的数据分片还是存储在 MySQL 数据库实例中,使用的是传统的 Master-Slave 的主从复制方式。这种数据复制方式默认是异步的方式,当然可以选择使用半同步的数据复制方式,但也没有解决所有的问题。如果业务并发量比较大,同步的流量比较大,依然会退化成异步的复制方式。为了让大家更好的理解这个问题,做了一个图:

Master 和 Slave 分别代表 MySQL 数据库,默认的情况下,客户端写入一个数据,Master 会把数据同步到 Slave 。在异常的场景下,当数据压力比较大的情况下,半同步退化成了异步的方式,我们看图左边的部分,这个时候写入一个数据 A ,但是返回给客户端成功之后,在同步给 Slave 之前,Master 节点 Crash 掉了,变的不可用了。

在右边的图里面,外面的监控系统发现了这个问题,把其中一个 Slave 提升成了 Master , 对外提供服务,这个时候我们想想会出现什么问题呢?在客户端读的时候,发现刚才写入的数据A 不见了,这个就是传统数据库复制方案里面很糟糕的事情,特别是如果写入的数据量很大,并且这些数据是核心数据,那就是一个非常严重的事故了。这种架构还有一个潜在的问题,看外部的监控系统,首先来说它也是一个单点,另外,他怎么能确认你的 Master 真正的挂掉了呢?我们知道网络是有三个状态的,要么能 ping 通,要么 ping 不通,还一种情况就是超时。在这个复杂的网络条件下,你怎么能把 Slave 提升成 Master ,以及如果之前的 Master 又活了,你怎么能解决他和新的 Master 之间数据一致性问题等。

所以我们从这些角度来看的话,如果把这些操作全部交给运维人员来做,就会非常容易出现一些奇怪的问题。这也是我们之前在真实的业务、生产环境里面,遇到的一些实实在在的问题。基于此,那么新一代的数据库必须是可以自恢复的。如果把所有这些操作交给运维去做的话,其实很容易造成非常严重的影响。

顺着数据库发展的历史来看,终于到了 NewSQL 的这个时代。NewSQL 其实就是在传统的数据库基础上增加了扩容 Scale 的能力,而同时又保证之前的 ACID 事务和 SQL 支持。

到了 NewSQL 的时代,经过了一段时间的发展,工业界终于有了重大的突破,那就是 Google Spanner 和 Google F1 。它们的特性主要有几个方面:

① SQL 支持;② 分布式 ACID 事务;③ 在线弹性伸缩能力;④ 自动的故障恢复;⑤ 跨洲际机房的数据安全。

从 Google 的 Spanner/F1 来看,结合刚才提到的问题,Google F1 提供了分布式数据库的基本上所需要的全部特性。当然最重要的是 Google 的 Spanner/F1 已经在 Google 的内部运行了一段非常长的时间。我们可以认为它是第一个在生产环境里面稳定运行的 NewSQL 数据库。

说起 Google,在云计算领域,基本上大家都是怀着朝圣的心态来看待的。整个 Hadoop 生态,都是建立在 Google 的GFS  、BigTable 和 MapReduce 三篇 paper 的基础上。在 Google 内部,经历了 BigTable —— Megstore —— Spanner/F1 的技术和架构演进,也就意味着, Spanner/F1 是 Google 当前最先进的数据存储技术的解决方案。大量的业务已经从原来的 BigTable 切换到 Spanner/F1 上,而且 Google 对外也高调地发布了Google Cloud Spanner 的基础云服务。我相信未来几年,就像当年的 Hadoop 一样,Spanner/F1 必然开启一个新的技术时代,包含着巨大的机会。目前,Google Spanner/F1 的开源实现主要有两个,一个是在美国纽约的 CockroachDB,一个就是我们的 TiDB。

TiDB 与 NoSQL、MySQL Proxy 方案的异同及其特点

TiDB 主要参考了 Google Spanner/F1 ,但严格来说又有些不同(图中标红的地方),最大的不同就在于 TiDB 是完整的兼容 MySQL 协议的。主要的原因是现在的市场上, MySQL 实在是太受欢迎了。所以大家都期望尽量在少改动业务代码的基础上可以用分布式数据库来解决数据库存储的问题。下面的一些特性,包括在线弹性扩展以及分布式的事务、在线的 DDL 和自动的故障处理,都是和 Spanner/F1 完全一样的;其他两点不同就是 TiDB 非常注重他周边 Ecosystem 的工具,以及 TiDB 一直在探索 Cloud 的方向,侧重点与 Google 也大有不同。

这是 TiDB 的整个架构:

相比 CockroachDB 把 SQL 和 KV 集成在一个实例中,TiDB 本质上是一个更加纯正的 Spanner/F1 分层实现。提到 TiDB 架构的时候大家总是有点奇怪,为什么还有一个 TiKV,甚至还有一个 PD 模块。这里面稍微解释下,其中主要原因是 TiDB 既是产品名称,又是 GitHub 上面的项目名称。从架构图上面大家可以看到,TiDB 数据库整个产品是分层的,上层无状态的计算层 TiDB 包括 SQL 解析、查询、优化执行、DDL 操作等方面;还有一层有状态的存储层 TiKV,提供分布式事务、多版本记录、一致性数据复制等功能。

这样的好处显而易见:首先,用户可以根据自身的业务,动态调整计算和存储节点,上层计算能力不够的添加 TiDB 节点,底层存储能力不够的添加 TiKV 节点,这样的架构处理业务会更加的灵活;第二点是分层有助于分模块测试,滚动升级以及并行开发,结合我们具体的实践来看,也确实获得了实实在在的好处。

TiDB 还有一个额外的模块叫 Placement Driver ,简称 PD ,主要提供时间戳分配、数据库与数据路由的管理以及数据的自动负载均衡调度,是一个非常重要的模块。

进一步看下 TiKV 的架构图,我们从 MySQL Proxy 遇到的问题来入手分析。

首先,在数据存储方面,TiDB 的数据存储是按照 Region 来组织的,也就是在 TiKV 这层我们不需要关心实际上到底存储的是什么数据,这样对于数据的力度管理会更精细,以及数据的迁移都非常的友好。这种设计的好处是对于上层的 SQL 来说是完全透明的,用户可以完全无感知地使用 Join、Group By 和 Sort 等操作。所以从这个层面来看,对于用户的使用是非常简单和方便的。在很多业务场景下,如果之前使用的是 MySQL 数据库,基本上不需要修改一行业务代码,就可以直接使用 TiDB。

其次,在分布式事务方面,TiDB 采用的是 Percolator 的事务模型,可以认为是 2PC 分布式事务的一个优化实现,参考的也是来自于 Google 的 paper ,TiDB 在工程实现上做了大量的优化来提升效率。这个在后面的 PPT 里面有一些补充材料,大家感兴趣的可以作为参考。

刚才也提到了 DDL 的问题,这个算法同样来自于 Google ,是 F1 团队和威斯康星数据库实验室合作开发的,TiDB 同样实现了这个算法,并且添加了更多的 DDL 语法支持,以及分布式优化加速。所以,TiDB 可以保证在大规模的分布式集群场景下,针对海量数据的表的 DDL 操作也不会阻塞线上的数据库服务。从数据分布的层面来看, TiDB 基本上解决了 MySQL Proxy 遇到的所有问题。

再来看一下的数据的复制问题。在之前我们提到分布式系统里面最核心的问题主要是数据一致性问题,这个时候我们终于要讨论一下具有里程碑意义的一致性算法—— Raft 。

在现代的分布式系统中,基本上都能看到使用 Paxos 或者 Raft 来解决数据的强一致问题。关于 Paxos 和 Raft 算法相关的问题,我们的 Blog 里面都有介绍。这里大家可以先有个直观的印象,就是他们都是一致性算法, Paxos 是鼻祖, Raft 是 Paxos 的一个等价实现,但是更容易理解,更容易测试和更容易工程化。Raft更像是一个自适应的多副本的主从复制协议。对于每一次写请求, Raft 都会保证 Leader 写成功,这个图里面我们是标含了一个 Leader ,两个 follower其中一个写成功,它就认为大多数写成功并完全写成功。此时才会返回客户端,即使 Raft Group 的 Leader 挂掉了,在一个有限的时间范围内,会很快地选出一个新的 Leader 出来,继续提供服务。

有一个有意思的问题就是,它不同于刚才 Master Slave 的复制方案,他的 follower 之间可以选择一个任意的比较快的网络的副本,可以任意的进行写入,所以是一个自适应的复制方案。Raft 协议本身支持 Config Change ,增加一个新的节点,可以很容易地做副本数据分布的变更,而不需要停止任何服务。再结合 PD 对于全局路由信息和 TiKV 存储节点信息的管理,就可以选出合适的 TiKV 存储节点进行资源调度和自动故障恢复。所以从这个层面来看,基本上以 Spanner/F1 和 TiDB 为代表的 NewSQL 基本上解决了我们刚才提到的 MySQL Proxy 所提到的基本上所有的问题。

这是一个总结,供大家参考。

什么场景下会选择使用 TiDB?

记住一点,就是你的数据量不是特别大的话,一台服务器也能全部的装下,除非你需要能保证你的数据的跨数据中心的数据安全,否则你不一定会选择 TiDB 的。你的业务场景需要强一致,并且需要分布式的事务,还想减轻你的运维的负担,希望数据库能够在线的进行扩展,在线的处理故障恢复和在线的进行 DDL 操作的话,数据达到一定量级,那么选择 TiDB 就是一个非常好的解决方案。

整个 TiDB 是分布式的,所以它不仅能处理在线的交易数据,还能处理一部分的业务场景。如果你不想使用 Hadoop 和 Spark 这样的数据分析的引擎,也不想通过 DDL 把数据库进行同步的话,选择 TiDB 的话也可能是一个非常好的解决方案。

怎么使用 TiDB 进行你的业务的迁移呢?这个问题对用户来说也比较重要,因为一个好的周边生态工具,对于你业务的高可用以及安全性的保证来说是非常重要的。这里主要是通过三个工具来实现的:

第一个工具叫做 Syncer,它可以伪装成一个 MySQL slave 这样一个实例。这样的好处就是可以在线的同步 MySQL 的 Binlog 数据,同步到后端的 TiDB 集群里面。

第二个工具是 TiDB-Binlog,这个工具和第一个作用正好完全相反。它的主要功能是可以把TiDB 数据同步成一个 Binlog ,然后输出到其他的存储引擎里面,包括另外一个 TiDB 的集群,或者 MySQL ,或者其他第三方的一些应用。

第三个工具是图里面提到的配套工具 Mydumper 和 Loader 。Mydumper 主要的好处是可以支持多线程。TiDB 在 Myloader 的基础上做了一些优化,主要基于两点,第一点就是让它的存储格式更好的适配 TiDB ,增加更好的并发力度,第二就是可以做故障恢复和断点续传。我们的应用场景里面 TiDB 面对的都是非常大数据量的业务,所以在导数据的时候如果不支持断点续传的话,会非常影响用户的体验。

下面举一个例子说明如何能够做从已有的 MySQL 到 TiDB 的迁移:

首先,目前用户的所有业务都是在 MySQL 的集群之上,然后通过 Mydumper 、TiDB 的 loader 将 MySQL 的镜像数据导入到集群里面去。

然后 TiDB 这边通过 Syncer 把 MySQL 的增量数据实时同步到用户的集群。此时,用户的写入是在 MySQL 基础上,用户的读取可以直接通过 TiDB ,这样的好处就是 TiDB 的 OLAP (联机分析处理)能力可以直接给用户带来直观的价值,对于复杂场景有了一个非常高效的查询引擎。还有一个问题,就是如果这个时候,用户发现 TiDB 集群有问题的时候,他可以直接下线到 TiDB 的集群,对整个线上的业务是没有感知的,把读的流量切回到 MySQL 集群就可以了。

第三步把读写流量全部迁移到 TiDB 集群,通过 TiDB 的 binglog 反向的去把TiDB 的数据同步到 MySQL 的集群,同样 TiDB 有问题的话,还可以切回到之前的 MySQL 集群。不会有任何的数据一致的问题。

第四步把 MySQL 集群完全下线掉,直接用 TiDB 集群提供在线的服务。在整个帮助用户去上线 TiDB 的问题上,我们花了大量的精力来提供周边的工具。


最后提一下 Cloud ,TiDB 的特点已经非常适合 Cloud 的环境了。首先,TiDB 是可以弹性扩容的,这一点就和 Cloud非常的匹配;另外一点就是 TiDB 本身适用于大数据量的场景,那么对于 Cloud 来说,你可以在底层只部署一套或者有限的几套集群,就可以在上面提供非常多的用户的访问需求,这样整个云厂商可以将服务器的资源利用得更好,用户对于这些没有太大的感知,在技术实现上是通过Kubernetes来实现的。

当然如果要上云的话,多租户的问题也很麻烦,如果要做到非常细粒度的资源隔离是非常困难的事情。我们也是通过权限和容器来做这方面的支持,也在做进一步的探索。

TiDB 的未来规划

关于 TiDB,今后还有一些需要继续做的工作:

第一点是 JSON 和 document store 的支持,这也是 MySQL 新的版本的特性,好处就是在  MongoDB 上比较松散的存储业务也可以直接迁移到 TiDB 上来。

第二个比较大的改变是 TiDB 在 AP 能力方面的增强,会和 Spark 有一个深度整合,大概在七月初就会有一个 TiSpark 版本,可以让用户在 TiDB 基础上体验运行 Spark 。

第三个,刚才也提到,所谓 OLTP 和 OLAP 的融合,可以让用户只存储一份数据的基础上,提供分析查询的能力,实际上TiSpark也是这种融合数据库的一个探索。

第四个,最近的新闻大家也看到,通过 AI 算法来做 MySQL 数据库的参数调优,我们可能做的更彻底,除了参数调优方面,我们整个的数据的分布即 PD 模块也需要动态调用,我们会通过深度学习改进这方面的自适应调优。

第五,会把 DB 作为一个 Service 。

这是 PingCAP 的一些相关资料的获取地址:


崔秋——重度开源爱好者,曾任职于搜狗、豌豆荚,长期从事广告系统基础组件相关的研究,现主要从事开源 NewSQL 数据库 TiDB/TiKV 相关的设计和研发工作。


长按关注

新型分布式 NewSQL 数据库

微信号:pingcap2015


关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接