做者:何志勇 本文转载自公众号「平安科技数据库产品团队」。mysql
2019 年 5 月 9 日,平安科技数据库产品资深工程师何志勇在第十届数据库技术大会 DTCC 上分享了《TiDB 在平安核心系统的引入及应用》,经过对 TiDB 进行 POC 测试,详细解析如何选择适用于金融行业级别的开源分布式数据库,以及平安“财神节”活动中引入 TiDB 的全流程应用实践案例分享。本文根据演讲内容整理。redis
<center>何志勇 平安科技数据库产品团队 资深工程师</center>spring
做为一名运维人员,引入一个新的数据库产品前必需要明确几点:sql
从业务的角度,引入的产品可否知足业务基本需求和使用场景。数据库
从运维管理角度看,这产品必须是可运维、可管理的,而且咱们须要对其相应的功能与特性,要有一个很好的了解。编程
产品性能稳定。服务器
因此在咱们引入前从如下六个方面分别对 TiDB 进行测试验证,其中功能与架构、配置与管理、备份与恢复都是针对咱们运维管理,SQL 特性、基准测试、应用场景测试则是应对业务需求和业务场景的。多线程
TiDB 事务隔级别为 SI,支持 Spark 生态,支持动态扩容,跨数据中心部署。架构
这是 TiDB 官网最新的架构图:并发
从左至右看,能够经过 MySQL 或 MySQL 客户端接入 TiDB,TiDB 有 TiDB、PD、TiKV 三个组件,组件之间功能相互独立,需独立部署,分别负责计算、调度、存储功能;同时又相互协做,共同完成用户请求处理。在 TiKV 层各节点是使用 Raft 协议保证节点间数据的一致性,同时它还提供 Spark 接口供大数据分析。
从上往下看,可经过 Data Miaration 工具从 MySQL 迁移到 TiDB,同时提供备份恢复功能、内部性能监控监测及诊断、支持容器化部署。
TiDB 从架构及生态上基本上具有了传统数据库应有的功能。
兼容 mysql 语法,2.0 版本不支持窗口函数、分区表、视图、trigger 等。
支持在线 DDL,2.0 只支持串行的 DDL、不支持并发,在优化器上支持 RBO 与 CBO,能对单会话进行管理,能够支持复杂的 SQL。
备份恢复工具均为开源,支持多线程备份恢复,当前版本不支持物理备份,loader 恢复时间偏长。
TiDB 在单条 SQL 的性能较好,高并发场景下性能较稳定,但 DML 事务大小有限制。
支持标量子查询,能支持很是复杂的查询,查询引擎可朔性强。
这个应用场景是咱们的产险的实际分析场景,表数据量不大可是 SQL 较为复杂,是典型的星型查询。在 Oracle 用了 134 秒,可是 TiDB 用了 50 分钟,咱们以为很诧异,与 TiDB 的同事咨询后,他们经过现场支持咱们优化底层代码后 34 秒能够跑出来。
“财神节”是中国平安综合性年度线上金融狂欢节。2019 年平安集团“财神节”活动于 1 月 8 日正式启动,涉及寿险、产险、银行、养老险、健康险、普惠、证券、基金、健康互联、陆金所、壹钱包、互娱、不动产等多个领域,活动参与的 BU 数量与推广的力度是历年之最。单日成交额超过 1000 亿,在单日交易额破千亿背后是几百个后台数据库实例的运维保障。
咱们看下活动业务场景的特色:
参与门槛低:暖宝保这个业务保费价格低至 19.9,因此人人均可以参与。
咱们的推广力度很大:以微服务的方式对接如平安健康、好福利、平安银行、陆金所等全部 APP 端,同时配合各类合做伙伴的宣传。
典型的互联网活动形式:如秒杀、红包雨,因此对数据库的要求是高并发、低延迟、高响应、高可用,2-5 年在线数据存储量预计达到 20~50TB,而这些只是预估,有可能远远大于以上评估值。
平安在用的开源数据库有不少,那在这么多数据库中,咱们选择什么数据库呢?
综合对比考量最终咱们选择 TiDB,在选择的同时也面临着挑战:
时间紧迫
2018 年 12 月 17 日~2019 年 1 月 7 日,20 天时间内完成开发测试到生产上线,时间短,风险大
开发零使用经验
现有开发大都是基于传统 Oracle 保险业务,对于 TiDB 没有使用经验
并发量与扩容
互联网业务并发需求前期不可彻底需求,前期不能很好的以实际压力进行测试,与资源准备
DB 运维管理
TiDB 还处于生产落地阶段,一类系统还没有使用过 TiDB,没有大规模应用运维经验
基于以上挑战,咱们在 9 台 PC 服务器上作了验证测试,测试工具是 jmeter,TiKV 节点数咱们是逐步增长的,具体的测试过程以下:
总结一下,就是:
TiDB 吞吐:在 select 中即 point select,TiDB 的吞吐比较好。
弹性扩容:在 insert 场景下随着节点数的增长,TPS 也会相应的增长,每增长 3 个节点 TPS 可提高 12%~20% 左右,同时在相同 TiKV 节点数下,TPS 与响应时间,此消彼长。
批量提交性能尤佳:业务中一个保单须要同时写 7 个表,7 个表同时 commit 比单表 commit TPS 高,相同 TPS 场景下延迟更小。
初始化 region 分裂耗时长:因在测试时没有预热数据(表为空表),对空表写入前几分钟,响应时间会比较大,约 5~8 分钟后响应时间趋于稳定。在前几分钟内响应时间大,是由于每一个表初始化完都是一个 region,大量 insert 进来后须要进行分裂,消耗时间比较大。
Raftstore cpu 高问题:因为 Raftstore 仍是单线程,测试中从监控指标看到 CPU 达到瓶颈是raftrestore 线程。
TiKV 性能中的“木桶原理”:TiKV 中一个节点的写入性能变慢会影响到整个集群的 TPS 与响应时间。
上线时咱们作了如下两方面改善:
1. 优化表的定义与索引
表定义:不使用自增加列(自增加的 rowid)做为主键,避免大量 INSERT 时把数据集中写入单个 Region,形成写入热点。
索引:使用有实际含义的列做为主键,同时减小表没必要要的索引,以加快写入的速度。
2. 对表的 region 进行强制分裂
查找表对应的 region:curl http://$tidb_ip:$status_port /tables/$schema/$table_name/regions
使用 pd-ctl 工具 split 对应表的 region:operator add split-region $region_id
打散表的隐式 id,打散表的数据分布:alter table $table_name shard_row_id_bits=6;
咱们使用了 25 台机器,后面还临时准备了 10 台机器去应对高并发的不时之需。
在使用过程当中遇到以下问题:
(1) 2.0.10 版本下 in 不能下推到表过渡问题
你们看到咱们两个相同的表结构,同时写入一些数据,在两个表进行关联的时候,发现过滤条件 t1.id=1 时,上面那个执行计划能够下推到两个表进行过滤,两个表能够彻底精准的把数据取出来,可是下面把等号后改为 in 的时候,对 t2 表进行全表扫描,若是 t2 表数据量很大时就会很慢,这是 TiDB 的一个 bug,解决方案就是不要用 in,在 2.1 版本修复了这个 bug。
(2) 2.0.10 下时区设置致使客户端不能连
咱们在跑命令的时候没有问题,而且结果是能够的,可是跑完后就断掉了,从后台看也是有问题的,重启 TiDB 组件也不行,后来找到代码咱们发现这是一个 bug。
缘由:这个 bug 会在你链接时 check 这个时区,致使用户不能链接。
解决办法:咱们找研发同事从新编译一个 tidb-server 登入服务器,把时区设置为正确的,而后使用最初的 TiDB 组件登陆,2.1 版本后这个 bug 修复。
(3) Spring 框架下 TiDB 事务
这个问题是比较重要的问题,有个产品须要生成一个惟一的保单号,业务是批量生成的,当时在 TiDB 中咱们建了一个表,表中只有一条数据,可是咱们发现会有重复保单号出来。
缘由:TiDB 使用乐观事务模型,在高并发执行 Update 语句对同一条记录更新时,不一样事务拿的版本值多是相同的,因为不一样事务只有在提交时,才会检查冲突,而不是像 Oracle、MySQL、PG 那样,使用锁机制来实现对一记录的串行化更改。
解决办法:Spring 开发框架下,对事务的管理是使用注解式的,没法捕获到 TiDB commit 时的返回状态。所以须要将 spring 注解式事务改为编程式事务,并对 commit 状态进行捕获,根据状态来决定是重试机制,具体步骤:
利用 redis 实现分布式锁,执行 SQL。
捕获事务 commit 状态,并判断更新成功仍是失败:
失败:影响行数为 0 || 影响行数为 1 && commit 时出现异常。
成功:影响行数为 1 && commit 时无异常。