股份制银行互联网理财场景中 TiDB 的选型和应用适配实战

百家 作者:PingCAP 2020-05-27 19:39:23

作者简介:邹建伟,北京开科唯识技术有限公司 技术专家。


一、互联网理财的兴起


在经济和科技飞速发展的趋势下,相比于以前传统的线下理财模式,互联网理财的模式,因其入围门槛相对较低,选择范围广,加上随时随地用电脑或者手机就能够进行理财,导致便捷性和灵活性的提升,从而让越来越的人们开始接受理财、乐于理财,理财的意识和投入的形态也越来越多。但随着监管制度的管控、用户规模、渠道规模、业务形态、高并发业务请求的不断增长和变化,传统的理财 IT 基础设施建设已经无法满足用户的使用体验,基于分布式系统建设新的业务系统必将破浪前行。
这次我们在中国某大型股份制银行—— G 行的互联网理财系统建设中,也是采用了分布式的数据库系统来取代传统 Oracle 数据库系统,在使用分布式数据库 TiDB 时,遇到了新技术适配的一些问题,通过迁移、开发改造和联调优化,积累了互联网理财场景中的一些分布式数据库 TiDB 的经验。本篇文章分享下在建设中遇到的问题和最终的解决方案,希望对所有准备建设和正在建设互联网理财系统的的用户有所帮助。

二、互联网理财业务简介


互联网理财最早于 2003 年就已经开展业务,主要承载基金代销、理财销售等线上业务,2018 年 4 月随着“资管新规”的发布,银行理财产品起售点由 5 万下调至 1 万,大大促进了银行资管理财业务的发展,更加激发了客户购买理财产品的热情,部分明星热销产品,更是吸引了大量客户集中抢购。
G 行互联网理财系统主要涉及两大类业务场景:
  • 联机交易场景 :处理开户申请请求,对单笔交易的响应时间有较高的要求;
  • 批量任务场景 :处理理财批量业务,属于计算密集型的工作,对数据库大数据量下的吞吐能力要求较高。



2.1 业务功能拓扑


互联网理财系统主要包含文件传输、实时开户、交易确认、份额登记、收益结转、产品管理、产品运营等功能,拓扑图如下:
业务对数据库处理能力提出了明确的技术指标要求:
  • 批量任务:要求数据库提供在 2h 内对 5000w 笔交易记录,能够跑完夜间批量任务的能力。
  • 联机任务:要求数据库提供事务平均响应延时不超过 100ms 的能力。


2.2 数据存储拓扑


同城两中心

整套集群服务器使用接近 30 台物理服务器,每台物理服务器均配置 4 块 NVMe 盘、2 个万兆网卡、2 个千兆网卡、72vcore、512G 内存,预期可以保留 3 个月的在线数据。

三、选型之路



3.1 背景与依据


在传统理财业务系统使用集中式的 IOE 架构,原有传统数据库 Oracle 数据库遇到支撑的瓶颈,已无法适应互联网+理财业务模式的发展需求, 取而代之的是通过开源自主可控、分布式数据库的技术方案来支撑当下的互联网技术模式的系统建设, 现有 Oracle 主要遇到亟待解决的的问题如下:
1. 容量上限不能扩展 (存不下、查不出来,索引优化已没有用)。
2. 分布式改造和适配如何取舍。
在当前分布式数据库解决方案领域内,可以聚焦的数据库选择范围就剩下分库分表方案 和 NewSQL 原生分布式方案(顺带的说明下,这里我们不争论分库分表究竟算不算分布式架构,我们相信技术是为场景存在的)。
选型我们主要考虑三点:首先是数据库功能,例如括高可用性、SQL 兼容、横向扩展、扩容等等;其次是技术架构的前瞻性、发展潜力、社区活跃度;最后是大数据量下的数据库性能最为看重。前期我们与候选的数据库厂家的工程师合作模拟了 daemon 业务程序,来验证数据库的性能,主要两个部分内容:
1. 数据初始化能力
来自互联网渠道的理财数据,预估每小时至少千万级别,在 1 个小时内我们有一系列的批量任务,留给数据库入库的时间最多 10 分钟。
2. 业务性能测试
理财业务具有多任务并存的特点,大方向说包括联机交易任务和跑批任务两部分,跑批任务包括日间任务和夜间任务以及数仓 edw 任务。联机任务要求事务平均响应延时不超过 100ms,批量任务即使并存时也不可以超过总体执行时间。
经过多轮的测试、评审,分库分表对业务设计上的不解决够优雅,由于拆分字段的规则限制了业务实现的一些方式,不能灵活进行业务处理,并且在批量的复杂逻辑SQL 处理上性能无法满足业务要求,最终我们选择 TiDB 来进行分布式数据库的建设。
验证下来,完全满足业务数据初始化效率、提升联机交易和批量处理响应能力、缩短批量处理时间周期,而且也无需限制业务场景的处理逻辑,根据压力需求灵活的进行在线扩展和在线收缩。上线前的非功能测试中,联机交易部分:在并发用户 30 下,数据库处理能力为 536 笔/s,响应时间为 0.0558s,满足预期 200TPS。批量入库:64 并发下,5kw 数据入库 9.7min,当然这并非极限值。


3.2 TiDB 的特性优势


水平弹性扩展
这里说的水平扩展包括两方面:计算能力和存储能力。TiDB Server 负责处理 SQL 请求,随着业务的增长,可以简单的添加 TiDB Server 节点,提高整体的处理能力,提供更高的吞吐。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点解决数据 Scale 的问题。
高可用
TiDB 集群核心三大组件:TiDB/TiKV/PD 都能容忍部分实例失效,不影响整个集群的可用性。TiDB 本身是无状态的,支持动态的增加删除。TiKV/PD 采用 Raft 协议,在大多数存活的前提集群便是可用的。
数据强一致
TiDB 的分布式算法使用 Raft,其事务可以跨分片、跨节点执行,并且强一致。
生态强大
这个特点应该毋庸置疑,说是“风口的猪”也不过分。TiDB 分布式数据库从 2015 年 4 月份开源以来,有来自社区的开发者、用户、布道师、设计师等不同角色的贡献者们的细心呵护,也有来自 PingCAP 持续不断的资源投入,截止到 2020 年 3 月,TiDB 社区项目已经聚集了来自全球的 760 多位 Contributor,100 多位核心用户,30000+ GitHub Stars 支持,TiDB 现已被近 1000 家不同行业的领先企业应用在实际生产环境。
TiDB 详细的架构和原理可以参照官网(不再赘述):
https://pingcap.com/docs-cn/stable/architecture/

四、开发改造中的思考&问题


G 行采用的 TiDB 版本是 3.0 早期版本,仅提供乐观锁机制, 这个问题在 TiDB 3.0.8 后引入了悲观锁后得到了解决。作为一名“重度”悲观锁使用者,TiDB的乐观锁是我刚开始接触 TiDB,所认为的开发改造过程中最大“阻碍”。但实际开发过程中,这里的碰到的问题其实很少,更多是认知理解的过程。整个改造过程中主要遇到了以下几个方面的问题,也都通过 TiDB 提供的最佳开发实践获得了很好的处理效果。


问题 1:热点账户更新

select for update 语句是悲观锁机制下热点账户更新场景常被利用的机制,Oracle 数据库中,这个语句的作用是:
The FOR UPDATE clause lets you lock the selected rows so that other users cannot lock or update the rows until you end your transaction.
也就是说利用它可以实现数据行的锁定,阻塞其它事务对该行数据的 DML 操作。
TiDB 也支持这个语句,不过在乐观锁机制下,这个语句不会在事务开启就锁住数据,而是其他事务在提交的时候进行冲突检查,如有冲突,会进行回滚。


问题 2:Rows Affected 不可信

悲观锁机制下,显式事务每条 DML 语句执行完成后数据库会返回影响行数:affect rows,业务会利用 affect rows 实际值不同进行不同的逻辑处理,这个是没问题的。不过 TiDB 乐观锁机制,显示事务每条 SQL 执行完成后返回的 affect rows 是不可信,究其根本原因,悲观锁是先加锁再更新,而乐观锁机制下,行冲突检测和数据上锁是放在事务提交时检测的,这里举一个例子:
对于事务 B 来说,update 语句执行后数据库返回 1 row affected,不过显而易见,这个语句提交时并没有发生更新,也即此时的 Affected rows 是不可信的。
如果业务还希望使用 affected rows 来做程序执行逻辑的判断条件,可行的方式是:显示事务下,先判断事务成功的条件,然后再根据 affected rows 进行逻辑处理。而隐示事务下,可以直接使用 affected rows 进行逻辑处理。


问题 3:大事务

熟悉 MySQL 的同学会对事务大小设计比较熟悉,开发规范中会尽可能拆分大事务为多个小事务。TiDB 对大事务也有类似的要求,并给出了限定具体限定标准:
  • 每个事务内的 SQL 数量不超过 5000 条(可配置)。
  • 每个键值对不超过 6MB。
  • 键值对的总大小不超过 100MB。
  • 键值对的总数不超过 300,000。
开发使用过程中,体会最多的限制是键值对的总数不超过 300,000,老系统稍不注意就超出了这个限制,造成处理失败。这里要着重说明,键值对数与行数不等价。举例说明:一行数据是一个键值对,一行索引也是一个键值对,当一张表只有 9 个索引时,每 insert 一行数据会写入 10 个键值对。这里的原因涉及到 TiKV 使用的存储格式,感兴趣的同学可以搜索 TiDB 相关文章进一步阅读。


问题 4:WRITE CONFLICT

WRITE CONFLICT 是开发中碰到的频率最多的问题之一,报错示例信息:

Err:[kv:9007]Write conflict, txnStartTS=411771139330670593, conflictStartTS=411754809751764993, conflictCommitTS=0, key={tableID=698, handle=391317290} primary={tableID=698, indexID=5, indexValues={0, 391317246, }} [try again later], ErrCount:313, SnapshotVersion:411752587989614594

问题的成因这里不赘述,感兴趣的同学可以搜索相关文档查看。TiDB 默认针对这个错误不会进行事务重试,由参数 tidb_disable_txn_auto_retry 控制,3.0 版本默认值是 1,而在更早的 2.1 版本里没有这个参数,默认行为是会自动重试,默认值更改的原因是优化事务处理逻辑,适应更多场景。

五、总结


目前互联网理财业务系统稳定的运行在 TiDB 3.0 版本乐观锁下,TiDB 4.0 马上要 GA 了,我们当初能赶上基于 4.0 的改造该有多好啊,据说 4.0 版本有了更多的新特性,让后续迁移到 TiDB 数据库的同学会更加的通用、易用。比如:


4.0 有了大事务

对于开发人员说,TiDB 4.0 以前事务的限制始终有点「达摩克利斯之剑」的意味,总是担心一个不留心就撞墙。4.0 版本开始,对事务的限制松绑很多,键值对的总大小允许 10GB 以内。


有了悲观锁

相比大事务带来的别扭,悲观锁个人觉得是最期待的特性。最早在 TiDB 3.0.8 版本引入,4.0 版本开始默认开启悲观锁。悲观事务模型是对于金融场景非常重要的一个特性,有了悲观锁我相信 TiDB 才会走的更高更远。


新特性很期待

TiDB 4.0 GA 版本即将发布,除了本文涉及的大事务、悲观锁 等等还有很多新特性,例如 Sequence、Key VisualizerFollower Read 等等,有兴趣的同学可以官网查看相关文章。





典型实践

网易互娱 |  数据库选型和 TiDB 应用实践

360 | 360 智能商业业务线 TiDB 写热点调优实战

知乎 | 万亿量级业务数据下的实践和挑战

平安科技 | 核心系统的引入及应用

北京银行 | 1. 两地三中心实践 2. 在线缩容迁移 3.金融场景那些事儿

微众银行 | 数据库架构演进及 TiDB 实践经验

华泰证券 | TiDB 在华泰证券的探索与实践

丰巢 | 支付平台百亿级数据

美团点评 深度实践之旅

贝壳金服 | 在线跨机房迁移实践

易果生鲜 | 实时数仓

小红书 | 从 0 到 200+ 节点的探索和应用

小米 | TiDB 在小米的应用实践

58 集团 | 应用与实践

爱奇艺 边控中心/视频转码/用户登录信息系统

Shopee | 东南亚领先电商 Shopee 业务升级

转转二手交易网 | TiDB 在转转的应用实践

同程艺龙 | 1. 票务项目  2.自研 TiDB 运维工具 Thor 

今日头条 | 核心 OLTP 系统

摩拜单车 | 1. 深度实践及应用 2. 在线数据业务

马上消费金融 | 核心账务系统归档及跑批业务

更多:https://pingcap.com/cases-cn/




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

[广告]赞助链接:

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

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