直播回顾 | 困扰多年的分库分表问题终于解决了
腾讯云数据库国产数据库专题线上技术沙龙正在火热进行中,3月17日郑寒的分享已经结束,没来得及参与的小伙伴不用担心,以下就是直播的视频和文字回顾。
关注“腾讯云数据库”公众号,回复“0317郑寒”,即可下载直播分享PPT。
话不多说,我们正式进入今天的分享。今天分享的主题是“亿级流量场景下的平滑扩容:TDSQL水平拓展方案实践”。
今天的分享我会主要包含这四部分:
第一部分首先介绍水平扩容的背景,主要介绍为什么要水平扩容,主要跟垂直扩容进行对比,以及讲一下一般我们水平扩容会碰到的问题。
第二部分会简单介绍TDSQL如何做水平扩容,让大家有一个直观的印象。
第三部分会详细介绍TDSQL水平扩容背后的设计原理,主要会跟第一部分进行对应,看一下TDSQL如何解决一般水平扩容碰到的问题。
第四部分会介绍实践中的案例。
一、数据库水平扩容的背景和挑战
首先我们看水平扩容的背景。扩容的原因其实非常直观,一般来说主要是随着业务的访问量,或者是需要的规模扩大,而现有的容量或者性能满足不了业务的需求,主要表现在TPS、QPS不够或者时延超过了业务的容忍范围,或者是现有的容量不能满足要求了,后者主要是指磁盘或者网络带宽。一般碰到这种问题,我们就要扩容。扩容来说,其实比较常见的就是两种方式,一种是垂直扩容,一种是水平扩容。这两种有不同的特点,优缺点其实也非常明显。
1.1 水平扩容 VS 垂直扩容
首先我们看一下垂直扩容。垂直扩容,主要是提高机器的配置,或者提高实例的配置。因为,我们知道,大家在云上购买一个数据库或者购买一个实例,其实是按需分配的,就是说对用户而言,可能当前的业务量不大,只需要两个CPU或者是几G的内存;而随着业务的增长,他可能需要对这个实例进行扩容,那么他可能当前就需要20个CPU,或者是40G的内存。
这个时候,在云上我们是可以通过对资源的控制来动态地调整,让它满足业务的需求——就是说可以在同一台机器上动态增加CPU。这个扩容的极限就是——当整台机器的CPU和内存都给它,如果发现还不够的话,就需要准备更好的机器来进行扩容。这个在MySQL里面可以通过主备切换:通过先选好一台备机,然后进行数据同步;等数据同步完成以后,进行主备切换,这样就能利用到现在比较好的那台机器。
大家可以看到,这整个过程当中,对业务来说基本上没有什么影响——进行主备切换,如果换IP的话,其实是通过前端的或者VIP的方式,对业务来说基本上没有什么影响。那么它一个最大的不好的地方就是,它依赖于单机资源:你可以给它提供一个更好的机器,从而满足一定量的要求。而随着业务更加快速的发展,你会发现现在能提供的最好的机器,可能还是满足不了,相当于扩不下去了。因此,垂直扩容最大的缺点就是,它依赖于单机的资源。
1.2 水平扩容
跟垂直扩容对比,另外一种方式我们叫水平扩容。水平扩容最大的优点是解决了垂直扩容的问题——理论上水平扩容可以进行无限扩容,它可以通过增加机器的方式来动态适应业务的需求。
水平扩容和垂直扩容相比,它可以解决垂直扩容的问题,但是会引入一些其他的问题。因为水平扩容比垂直扩容更加复杂,下面我们分析下可能遇见的问题,以及后面我们会介绍TDSQL的解决方案:
首先,在垂直扩容里面,系统经过扩容以后,其实数据总体来说还是存在一个节点,一主多备架构中,备机上也存储着所有数据。而水平扩容过程中数据会进行拆分,面临的第一个问题是,数据如何进行拆分?因为如果拆分不好,当出现热点数据时,可能结果就是,即使已经把数据拆分成很多份了,但是存储热点数据的单独节点会成为性能瓶颈。
第二点,在整个水平扩容过程中,会涉及到数据的搬迁、路由的改变。那么整个过程中能否做到对业务没有感知?或者是它对业务的侵入性大概有多少?
第三,在整个扩过程中,因为刚才有这么多步骤,如果其中一步失败了,如何能够进行回滚?同时,在整个扩容过程中,如何能保证切换过程中数据高一致性?
再者,在扩容以后,由于数据拆分到了各个节点,如何能保证扩容后的性能?因为理论上来说,我们是希望我随着机器的增加,性能也能做到线性提升,这是理想的状态。实际上在整个水平扩容的过程中,不同的架构或者不同的方式,对性能影响是比较大的。有时候会发现,可能扩容了很多,机器已经增加了,但是性能却很难做到线性扩展。
同样的,当数据已经拆分成多份,我们如何继续保证数据库分布式的特性?在单机架构下,数据存储一份,类似MySQL支持本地做到原子性——可以保证在一个事物中数据要么全部成功,要么全部失败。在分布式架构里,原子性则只能保证在单点里面数据是一致性的。因此,从全局来说,由于数据现在跨节点了,那么在跨节点过程中怎么保证全局的一致性,怎么保证在多个节点上数据要么全部写成功,要么全部回滚?这个就会涉及到分布式事务。
所以大家可以看到,水平扩容的优点很明显,它解决了垂直扩容机器的限制。但是它更复杂,引入了更多的问题。接下来大家带着这些问题,下面我会介绍TDSQL如何进行水平扩容,它又是如何解决刚才说的这些问题的。
二、TDSQL水平扩容实践
2.1 TDSQL架构
首先我们看一下TDSQL的架构。TDSQL简单来说包含几部分:
第一部分是SQL引擎层:主要是作为接入端,屏蔽整个TDSQL后端的数据存储细节。对业务来说,业务访问的是SQL引擎层。
接下来是由多个SET组成的数据存储层:分布式数据库中,数据存储在各个节点上,每个SET我们当做一个数据单元。它可以是一主两备或者一主多备,这个根据业务需要来部署。有些业务场景对数据安全性要求很高,可以一主三备或者一主四备都可以。这个是数据存储。
还有一个是Scheduler模块,主要负责整个系统集群的监控、控制。在系统进行扩容或者主备切换时,Scheduler模块相当于是整个系统的大脑一样的控制模块。对业务来说其实只关注SQL引擎层,不需要关注Scheduler,不需要关注数据是怎么跨节点,怎么分成多少个节点等,这些对业务来说是无感知的。
2.2 TDSQL水平扩容过程
整个扩容流程大家可以看一下:一开始数据都放在一个Set上,也就是在一个节点里面。那么扩容其实就是会把数据扩容到——这里面有256个Set,会扩容到256台机器上。整个扩容大家可以看到有几个要点:
一开始虽然数据是在一个节点上,在一台机器上,但是其实数据已经进行了拆分,图示的这个例子来说是已经拆分成了256份。
水平扩容,简单来说就是把这些分片迁移到其他的Set上,也就是其他的节点机器上,这样就可以增加机器来为提供系统性能。
总结起来就是说,数据一开始已经切分好了,扩容过程相当于把分片迁到新的节点,整个扩容过程中,节点数是增加的,可以从1扩到2扩到3,甚至扩到最后可以到256,但是分片数是不变的。一开始256个分片在一个节点上,扩成两个节点的话,有可能是每128个分片在一个节点上;扩到最后,可以扩到256个节点上,数据在256台机器,每台机器负责其中的一个分片。因此整个扩容简单来说就是搬迁分片。具体细节我们后面会讲到。
在私有云或者是公有云上,对整个扩容TDSQL提供了一个统一的前台页面,用户在使用的过程中非常方便。
我们看一下这个例子。现在这个案例中有两个Set,也就是两个节点,每一个节点负责一部分的路由,第一个节点负责0-31,另一个名字是3,负责的路由信息是32-63。现在是两个节点,如果要进行扩容,在前台页面上我们会有一个“添加Set”的按纽,点一下“添加Set”,就会弹出一个对话框,里面默认会自动选择之前的一个配置,用户可以自己自定义,包括现在这个Set,需要多少资源以及内存、磁盘的分配等。
此外,因为扩容要进行路由切换,我们可以手动选择一个时间,可以自动切换,也可以由业务判断业务的实际情况,人工操作路由的切换。这些都可以根据业务的需要进行设置。
第一步创建好以后,刚才说大脑模块会负责分配各种资源,以及初始化,并进行数据同步的整个逻辑。最后,大家会看到,本来第一个节点——原来是两个节点,现在已经变成三个节点了。扩容之前,第一个节点负责是0-31,现在它只负责0-15,另外一部分路由由新的节点来负责。所以整个过程,大家可以看到,通过网页上点一下就可以快速地从两个节点添加到三个节点——我们还可以继续添加Set,继续根据业务的需要进行一键扩容。
三、TDSQL水平扩容背后的设计原理
3.1 设计原理:分区键选择如何兼顾兼容性与性能

其实我们也可以做到用户创建表的时候不指定shardkey,由我们底层这边随机选择一个键做数据的拆分,但这个会影响后续的使用效率,比如不能特别好地发挥分布式数据库的使用性能。我们认为,业务层如果在设计表结构时能有少量参与的话,可以带来非常大的性能优势,让兼容性和性能得到平衡。除此之外,如果由业务来选择shardkey——分区键,在业务设计表结构的时候,我们可以看到多个表,可以选择相关的那一列作为shardkey,这样可以保证数据拆分时,相关的数据是放在同一个节点上的,这样可以避免很多分布式情况下的跨节点的数据交互。
3.2设计原理:扩容中的高可用和高可靠性

数据同步
数据校验
路由更新
删除冗余数据
3.3设计原理:分布式事务

原子性、去中心化、性能线性增长
3.4设计原理:如何实现扩容中性能线性增长
垂直扩容中一般是通过更换更好的CPU或者类似的方法,来实现性能线性增加。水平扩容而言,因为数据拆分到多个节点上去,如何才能很好地利用起拆分下去的各个节点,进行并行计算,,真正把水平分布式数据库的优势发挥出来,需要大量的操作、大量的优化措施。TDSQL做了这样一些优化措施。

我们简单看一个聚合——TDSQL是如何做到水平扩容以后,对业务基本无感知,使用方式跟使用单机MySQL一样的。对业务来说,假设有7条数据,业务不用管这个表具体数据是存在一个节点还是多个节点,只需要插7条数据。系统会根据传过来的SQL进行语法解析,并自动把这条数据进行改写。7条数据,系统会根据分区键计算,发现这4个要发到第一个节点,另外3个发到第二个节点,然后进行改写,改写好之后插入这些数据。对用户来说,就是执行了这么一条,但是跨节点了,我们这边会用到两阶段提交,从而变成多条SQL,进而保证一旦有问题两边会同时回滚。


对于比较复杂的一些SQL,比如多表或者是更多的子查询,大家有兴趣的话可以关注我们后面的分享——SQL引擎架构和引擎查询实战。
四、水平扩容实践案例
第四章,我们简单来介绍一些实践和案例。
4.1 实践:如何选择分区键

如果是面向用户的互联网应用,我们可以用用户对应的字段,比如用户ID,来做分区键。这样保证在拥有大量用户时,可以根据用户ID将数据拆分到各个后端节点。
这个大家可以看到,如果水平扩容到更多——从一个节点扩到256个节点,那某一条SQL写不好的话,可能需要做256个节点全部的数据的聚合,这时性能就不会很好。
4.2 实践:什么时候扩容?


下面再看几个云上的集群案例。这个大家看到,这个集群有4个SET,每个SET负责一部分的shardkey,这个路由信息是0-127,意思是它最后能扩到128个节点,所以能扩128倍。这个“128”可以由初始化的业务预估先定下来。因为如果池子太大的话,的确最后可以扩到几千台,但是数据将比较散了。事实上今天每台云上的或者实际的机器性能已经非常好,不需要几千台的规格。

今天我的分享主要是这些内容,大家如果有什么问题欢迎评论留言。
五、Q&A:
特惠体验云数据库
转载自:https://juejin.cn/post/6844904112501293064