【是否原创】是
【首发渠道】TiDB 社区
【首发渠道链接】其他平台首发请附上对应链接
【正文】
背景介绍
和每个技术公司类似,当一个公司的业务和数据高速增长的时候,是最考验技术部门的时候了,2021年中的时候,百融云创的SaaS端数据分析和AI业务快速发展,给我们的技术平台带来了新的挑战。我们云端运行的几个主要的数据分析和AI业务的子系统A,B,C,D,E都是以Hadoop + MySQL + ElasticSearch体系为主的存储架构,当时面临几个问题:
- A系统是目前数据量和增长量最大的系统,在当初架构设计的时候已经做过一次分库,单表的数据量最大达到3亿,每个月预估以1个亿左右的速度增长。这个系统的QPS目前也是最高的,数据库的QPS+OPS合计达到3万,我们预估半年后可能达到6万以上。
- B系统则是2021年我们新研发的中台系统,数据日处理量非常大,单表每日最大增长达到1亿以上的数据量,同时有大量的统计类实时查询需求,经过读写分离后,仍然会产生大量的慢查询,在MySQL + ElasticSearch的存储架构下,优化过多轮,但是效果并不明显。
- C,D,E系统都是业务增长比较快的AI业务子系统,我们设计的架构都是比较相似的:有分表分库,横向扩展分库的成本都比较高,不便于后期进行数据库分库扩容。
基于上面这些问题,我们经过几轮内部的评估,得出的结论是一年内我们在不做大规模的分库重构下,MySQL应该还能支撑住,但是到2022年中的时候,上述这些业务特别是A,B业务将会有严重的性能影响。在这个情况下,百融的产品研发部、基础架构部和运维部联合发起了对分布式数据库的调研,经过技术委员会的几轮讨论,大家的焦点集中在这几个点:
- 大家都达成一致的是:2022年数据库的存储、处理速度会面临巨大挑战,我们必须提前1年开始考虑怎么应对这些问题。
- 大家不完全一致的是:我们是继续对MySQL数据库进行扩容并且对系统进行大的重构,继续进行分库,把存储和访问压力分布到多个集群上去,还是考虑从MySQL存储体系完全升级到分布式数据库架构体系?
- 如果升级到分布式数据库,如何选型,是否满足我们的业务形态?
既然问题提出来了,我们面临的是如何选择,如何证明分布式数据库存储比我们现在使用的MySQL体系更合适?
技术选型
在经过多轮内部PK之后,我们又达成一个共识:大家都一致认为对系统进行重大的MySQL分库重构是不可行的,技术人员会花费大量的时间在这种不断的重构中,而且这种体系是有瓶颈的,我们不可能无限进行分库的,每次上线都要对历史数据进行迁移,是一个非常麻烦而且低效的事情。剩下的意见就是我们选择一种合适的存储架构来应对我们不断增长的存储和处理速度需求,研发人员可以专注在产品研发的工作上,而数据库的扩容可以几乎无限的快速扩容,不影响业务的发展,也不会让研发人员花费额外的时间去处理数据库扩容升级的事情。结论也应运而生:我们需要分布式数据库体系。很快我们对市面上的一些分布式数据库进行了调研:
- 首选TiDB,国内已经有不少大厂开始使用了TiDB,积累了不少的经验,我们可以参考。有社区版本可以使用,技术社区比较大,PingCAP公司支持也还不错。
- 同时还研究了OceanBase,但是找不到太多的使用资料和最佳实践经验,所以没有做太多调查就放弃OB了。
- 还有阿里云的PolarDB,是云原生关系型数据库,我们的业务需求不能接受云数据库,所以就没有详细去研究了。
最后大家的结论达成一致是选择TiDB作为我们升级的分布式数据库,技术委员会讨论后也给出了几个指标调研的要求:
- TiDB的性能指标
- TiDB对比MySQL数据库的性能分析
- TiDB集群的服务器数量
对于问题a,DBA和测试部门给出了压测报告,下面表1是TPS/QPS随着压测线程增加的变化趋势:
表1 - TiDB双机房压测结果
压测TiDB集群服务器使用了6台服务器,配置如下:
下图是TPS和QPS随数据线线程数量的变化趋势:
从压测结果来看:
- 通过观察TPS的趋势图,在100-1400的线程中,TPS随着线程数的增加呈递增趋势,并且有五处线程段的TPS峰值,300线程内,290线程TPS出现峰值为3696.94,所测全部数据中1400线程内,1200线程TPS出现峰值为4119.23。
- 性能测试中有后台报错经运维排查是内存问题,tikv内存默认为占用总内存空间的40%,有4台tikv服务器时在TPS较大时内存将超100%导致各类服务器问题。经过将内存调整为原来的一半后。问题解决。
- 1400线程测试中有700线程不限制请求事务数,700线程每秒事务数15次。模拟正常业务场景。
综上:TPS峰值最高为4119,QPS最高峰值为82384, 1200线程的并发执行未发现异常,能满足业务需要。所以对于a问题,目前根据6台集群的TiDB能达到这个性能,已经超过我们的预期了,完全可以支持我们未来的业务发展需求,所以这个问题大家一致通过。同时在压测过程中,DBA也发现不少有意思的问题,比如V4.0.12版本的TiDB有不少的bug,V4.0.13版本相对稳定很多,最后我们选择了V4.0.13的版本。还有一些内存报错的问题,也是发现并解决了。
对于问题b,主要考虑的是切换从MySQL切换到TiDB以后对我们的业务处理速度是否会下降,大家会有疑问,因为TiDB由于是分布式部署架构,天然支持无感的水平扩容来应对业务的增长,但是单个的查询、插入和更新操作对比MySQL是否有优势呢?同样我们做了一轮对比MySQL和TiDB的压测对比测试,下图是测试对比环境:
下面是DBA和测试部门给出的压力测试结果:
从测试得出的结论是:
- 并发低于50时,MySQL在TPS,QPS和响应时间上,都优于TiDB
- 并发高于50时,TiDB的性能逐步上升,TPS,QPS和响应时间都优于MySQL
- MySQL在并发达到100时,TPS不再上升,并发达到300时,响应时间出现明显下降,并发达到800时,报错退出
- TiDB通过持续扩容能够获得更好的性能和更大的数据容量,MySQL由于单机限制,性能达到一定程度后无法继续提升
我们目前的情况是对于A,B,C业务,并发远高于50,最高能达到500以上,2022年甚至能到1000以上。在TiDB上将获得长久的TPS、QPS获益,对于响应时间而言,TiDB比MySQL有差异,这个是显而易见的,毕竟分布式的数据库肯定会牺牲单个操作的响应时间,但是这点对我们业务形态而言是可以接受的。同时,我们还对一些比较复杂的统计类SQL在MySQL和TiDB上做了对比测试,效果也很惊人,TiDB的查询速度比MySQL快5倍以上,这个对我们是个惊喜,以前30秒能统计的业务需求,在TiDB上6秒就能出来。
为了进一步验证,我们还做了TiDB的疲劳测试,长时间运行的情况下看性能是否有显著下降,测试报告如下:
测试结论是长时间测试过程中,性能没有明显下降,TPS和QPS波动比较小。
最终问题b也得到了一致通过,可以推动进一步调研我们的TiDB集群架构设计了。经过大家的讨论,我们的初步方案如下:
整个TiDB初始集群一共有10台物理机,4个TiDB server 服务器,6个TiKV服务器,3个PD混合部署在一起,有一个MySQL接管机,和TiDB集群保持数据完全同步,能随时接管TiDB。
整体技术选型和调研花费了我们2个月的时间,其中我们还请过PingCAP的技术专家们给我们进行咨询,提出了一些架构方面的意见。
升级过程
技术选型完毕后,技术委员会一致通过了技术方案,运维部门在准备TiDB集群的同时,交给研发部门的一个最主要的问题是升级到TiDB的兼容性,PingCAP的官网介绍和各种技术文档都提到的TiDB基本100%建议MySQL的迁移升级。但是到真正操作的时候,还是有不少兼容性的改造的,我们遇到的主要的几个改造问题如下:
- 因为有一些系统的表里面,不是所有的表的ID都是使用发号器发号生成的,有不少表使用了自增ID的方式,这带来了许多的问题,TiDB是分布式的数据库,自增ID不能保证是连续自增的,每台机器产生一批自增ID(默认是30000一批),使用完后跳转到新的ID范围,导致ID的顺序并不一定随时间增加而增大,这样如果代码里面有依赖ID的自增逻辑的话,上线后肯定出现不可预估的问题
- 索引优化的问题,实际测试过程中我们发现TiDB对索引的选取逻辑和MySQL有一些差异,对多索引的命中逻辑不一致,需要进行优化
- TiDB的数据访问热点问题,在高并发批量更新、插入操作时,是比较关注的一方面。因为TiDB为一款分布式数据库,它的结构决定了会有这一问题。单机数据库是不会存在热点问题,性能的上限就是物理机器的上限。而分布式的结构为集群模式,存在多个节点。为了达到存储、读写能力可随时拓展的目的上,希望的是能较好的均匀分摊在每个节点上。当表主键为连续的时候,批量更新和插入会出现性能急剧下降。由于PD的热点调度只能以Region为最小单位,小表通常在一个Region上或者一段数据范围在一个Region上,PD这时就无能为力了。目前TiDB4.0大幅度优化了AutoRandom、新热点调度器、热点可视化,还在整个社区的帮助下、不断改进和探索。
- 慢查询的发现和预判也很重要,慢查询可以和QA同学一起协助来发现,预判对于研发人员则要求较高一些。首先要了解业务、业务代码逻辑、代码操作数据源的方式,其次要了解TiDB的基本原理和特性,最后需要使用经验来补充。
- 在迁移过程中发现TiDB与MySql数据库变量值不一致的问题,例如参数“max_allowed_packet”,“only_full_group_by”等等。类似这些参数在升级过程中需要注意一下,否则影响业务。
- 数据库连接地址后面的参数(例如jdbc:mysql://[host:port]/[database][?参数名1][=参数值1][&参数名2][=参数值2]…),在迁移过程中要以原MySql的参数为基础进行调试,不可直接换掉或者抛弃某些参数。例如:rewriteBatchedStatements和allowMultiQueries需要同时使用,否则批量更新的时候会报错。
- 事务检查,查看项目中是否存在大方法在一个数据库事务里,或者一个事务处理的数据量特别大,尽量将大事务拆分成小事务,减少前序执行耗时(由于锁冲突或错误,计划可能会执行失败并重试执行多次,该时间是不包含最后一次执行的前序执行自然时间)和发送结果的耗时(发送 SQL 语句执行结果给客户端的耗时)。
- 切换后前期需要持续性SQL调优。
这些改造点都是根据同行不少技术人员给出的建议和我们实践的实际经验得出的,非常宝贵,给我们后续更多应用的迁移带来了不少的帮助,但是实际上线后还遇到了一些其他问题,后面也会阐述。这是百融云创第一次使用准备TiDB,我们讨论后采用了分步的升级过程:8月份开始升级B,C业务系统,3个月的线上运行,运行稳定后升级A业务系统。
兼容性的代码改造并不复杂,针对上述几个问题集中兼容改造测试后面临比较重要的问题是升级过程,如何无缝切换到MySQL,不会影响线上业务,出现问题后如何快速回滚到原MySQL,数据一致性的检查。切换的执行方案如下图所示:
(1)切换前应用服务连接MySQL集群,数据通过DM保持和TiDB集群保持同步
(2)切换后通过域名切换到TiDB集群,这时候通过TICDC保持数据和接管的MySQL库同步数据
如果发生回退,应用直接切换到接管的MySQL集群,保证数据一致性没有问题
其中我们用到了TiDB的两个工具:
第一个是TiDB Data Migration (DM),将MySQL数据迁移到TiDB集群,使用这个工具可以提前将MySQL数据全部实时同步到TiDB上,保证迁移时数据一致。
第二个是TiCDC,通过拉取TIKV的日志来同步TiDB的数据到MySQL,确保托管的MySQL数据库能和TiDB数据保持一致。
为了稳定升级,我们将整个过程分解到3个阶段:
- 第1阶段:兼容性代码的改造,改造完毕后在MySQL环境下进行线上运行,确保兼容改造在MySQL上是运行稳定的。
- 第2阶段:由于考虑到TiDB是否在应对业务高峰的时候不会带来意外,我们将读写分离中的读业务切换到TiDB,然后对TiDB进行慢查询和性能进行观察,确保运行稳定。
- 第3阶段:最后将主要的写业务切换到TiDB数据库,同时切换完毕准备压力测试,如果性能不达标,立即进行回滚,回滚到使用上述TICDC同步的MySQL接管库,确保数据不会丢失。
升级过程比较顺利,但是值得一提的是,TiDB的单机热点update语句比MySQL慢一些,在大量数据形成单机热点update的时候还是能体现出来性能差异,如果是对update时间要求非常严格的业务,切换到TiDB要谨慎考虑。整个改造升级过程持续了3个月时间,终于在2022年1月份,我们主要的几个业务子系统A,B,C,D,E全部迁移到TiDB上了。
有一点的需要补充的是,为了应对TiDB数据库在实际运行过程中遇到不可恢复的问题,我们可能随时要切换回MySQL集群,为此我们做了切换的演练,从TiDB无缝切换到MySQL集群,然后又切换回TiDB集群,切换过程能发现一些想不到的问题,比如两边索引不一致的小问题可能导致线上出现大问题,只有经过真实的演练才能确保出现问题后切换方案是可行的。
线上遇到的问题
在迁移完毕后,带来的显著的好处是TPS和QPS的提升,根据目前的线上情况预估,QPS在达到10万的时候TiDB仍然压力不大,就算不能应对时,动态扩容也很容易,在以前的MySQL集群的情况下单机扩容基本已经到瓶颈,QPS在3万的时候CPU使用率超过70%。另外的好处是研发人员不再担心业务压力造成数据库瓶颈,底层架构对研发人员更加透明。同时我们也遇到了一些问题,和大家分享下:
- 最大的问题是索引的问题,在MySQL上以前执行非常快的查询,在TiDB上会突然发现出现慢查询,仔细分析后发现要么就是没有命中索引或者选择的索引不是最优的,这个问题反馈给社区后,基本得出的结论是TiDB选择索引的算法和MySQL有一些微小的差异。典型的问题是MySQL中,如果主键ID是Primary Key并且ID有NULL值的情况下,根据ID查询索引可以命中,速度非常快,但是在TiDB里面不能命中索引,只能全表扫描,导致出现慢查询,解决的办法是只能处理数据,处理掉NULL值,这应该是MySQL兼容NULL值索引,TiDB没有。同时查询字段与查询值的数据类型不匹配,会导致索引失效。
- 索引还有一些问题,联合索引的选择逻辑和MySQL不一样,导致选择了更慢的一些索引,处理办法是优化索引,调整字段顺序或者使用强制索引来处理。 (当select查询条件的字段为联合索引的非首字段时,tidb也支持走索引,但是mysql不会走索引)
-还有一些表的索引在切换后需要重新ANALYZE TABLE索引才能生效。 (tidb的执行计划类似于oracle,定时任务时间段内统计,如果表在白天变化较大,可能会触发错误的执行计划,这时需要手动analyze处理解决)
-热点问题,主键为连续的值,多并发写入会出现排队的情况,因为同时写入到一个region里,无法发挥分布式并发的特性,官方推荐解决方法是主键采用auto_random随机数,或者业务采用发号器生成随机数。 - TIDB选择索引问题,即使是完全相同的sql,只是修改了查询条件等号后面的值,会选择不同的索引。这种情况出现在查询条件字段为其他联合索引中的一个字段,后来经过专门创建联合索引解决。
- TiDB主键问题,其他合作部门会操作我们的com表,执行插入操作后出现主键ID特别大。因为创建分表会取com表的主键Id作为根表依据,Sharding-JDBC的algorithmExpression参数(分片算法行表达式)。如果com表主键大于了algorithmExpression表达式的范围(例如{1…10000})会报错。
- 出现SQL执行效率变差是由于统计信息不准造成的,通过手动统计信息之后得到了正确的执行计划。创建联合索引可以更大的降低扫描数据量,进一步提升性能。在性能已经满足业务的情况下,联合索引会有额外的成本。
后续展望
2021年是百融云创的SaaS产品使用TiDB的实践元年,在这一年中,百融云创多个技术团队:包含产品研发部、运维部、基础架构部和测试部门联合进行探索、调研到升级、迁移,让我们的产品和系统也进入了一个新的数据存储架构中,产品本身的稳定性和性能也带来了比较大的变化,技术团队在应对未来业务发展有了更强有力的工具,进一步积累了百融云创的技术范畴。我们相信在未来的几年中,以PingCAP TiDB为代表的分布式数据库将会在更多的公司和业务领域发挥更大的作用和价值。同时我们也在后续准备了一些新的计划:
- 多机房多活TiDB集群方案,为了保证公司的数据更加的安全和稳定,多机房多活TiDB集群势在必行,下一步我们也将研究这种架构,投入到我们的产品上。
- TiFlash的使用,满足公司基于列存储的一些业务场景。
百融云创技术团队将会持续根据公司业务发展的需求,在目前的基础上,引入适合自己的技术体系,让技术服务于产品和业务。后续我们也会继续更新我们新的实践经验,敬请期待!
百融云创研发技术平台
2022年1月