做者:何志勇
本文转载自公众号「平安科技数据库产品团队」。mysql
2019 年 5 月 9 日,平安科技数据库产品资深工程师何志勇在第十届数据库技术大会 DTCC 上分享了《TiDB 在平安核心系统的引入及应用》,经过对 TiDB 进行 POC 测试,详细解析如何选择适用于金融行业级别的开源分布式数据库,以及平安“财神节”活动中引入 TiDB 的全流程应用实践案例分享。本文根据演讲内容整理。
<center>何志勇 平安科技数据库产品团队 资深工程师</center>redis
做为一名运维人员,引入一个新的数据库产品前必需要明确几点:spring
因此在咱们引入前从如下六个方面分别对 TiDB 进行测试验证,其中功能与架构、配置与管理、备份与恢复都是针对咱们运维管理,SQL 特性、基准测试、应用场景测试则是应对业务需求和业务场景的。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 亿,在单日交易额破千亿背后是几百个后台数据库实例的运维保障。
咱们看下活动业务场景的特色:
平安在用的开源数据库有不少,那在这么多数据库中,咱们选择什么数据库呢?
综合对比考量最终咱们选择 TiDB,在选择的同时也面临着挑战:
2018 年 12 月 17 日~2019 年 1 月 7 日,20 天时间内完成开发测试到生产上线,时间短,风险大
现有开发大都是基于传统 Oracle 保险业务,对于 TiDB 没有使用经验
互联网业务并发需求前期不可彻底需求,前期不能很好的以实际压力进行测试,与资源准备
TiDB 还处于生产落地阶段,一类系统还没有使用过 TiDB,没有大规模应用运维经验
基于以上挑战,咱们在 9 台 PC 服务器上作了验证测试,测试工具是 jmeter,TiKV 节点数咱们是逐步增长的,具体的测试过程以下:
总结一下,就是:
上线时咱们作了如下两方面改善:
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 状态进行捕获,根据状态来决定是重试机制,具体步骤:
捕获事务 commit 状态,并判断更新成功仍是失败: