编者按:本文由微众银行数据库负责人胡盼盼撰写,介绍了微众银行自 2014 年以来从传统 RDBMS 到 NewSQL 的架构演进,以及 TiDB 在微众银行核心批量场景的应用。
转眼间,已在微众工作近七载。这期间,一直负责微众银行数据库平台的建设和运营。微众银行在成立之初,IT 基础建设就没有选择传统的 IOE 集中式架构路线,转而选择采用了基于单元化的分布式架构。在这种大的背景下,微众银行的数据库的架构演进,也是走出了一条不同寻常的路线。
一、2014 ~ 2016,两地三中心时代
在微众银行 IT 建设的第一阶段,基于成本和效率的考虑,IDC 的建设采用了两地三中心的架构(简称 IDC 1.0 架构)。 两个同城数据中心作为生产中心,一个异地容灾中心作为灾备。
IDC 1.0 架构
在 IDC 1.0 架构的基础上,我行设计了基于 DCN 的单元化分布式架构(DCN,即 Data Center Node 的简称)。一个 DCN,可以理解为一个从应用层到中间件层,到数据库层的完整的自包含的逻辑单位。
不同的业务产品被归类到不同类型的产品 DCN;同一个业务产品,再通过一定的计算规则(比如客户号的 hash),分配到每一个小的 DCN 产品单元中;每一个 DCN 单元会有一个核定的用户承载量;当一个 DCN 的用户承载量用满时,便可以发起新的 DCN 单元扩容,以此来实现 水平扩展 的特性。
在实际两地三中心的部署架构中,每个 DCN 都会有同城主 DCN、同城备 DCN、异地备 DCN 三种角色,即每个 DCN 也都实现了两地三中心的架构。同时,不同的 DCN 主分片,在同城的两个 IDC 之间是交叉部署的,以此可以实现 DCN 单元粒度上的同城双活。
DCN 主备交叉部署架构
那么,基于这种 IDC 和 DCN 架构的前提下,数据库如何选型?架构如何设计呢?
客观的讲,在 2014 的时候,满足金融级要求的国产分布式数据库产品并不多,可选范围也非常有限。经过充分的调研也评估,微众最终选择了腾讯的数据库产品 TDSQL,作为 DCN 架构下的核心数据库。
基于 TDSQL,我们设计了如下的数据库部署架构:
两地三中心的数据库部署架构
可以看到,TDSQL 的部署架构也遵循了两地三中心的原则,分为同城主数据库 SET,同城备数据库 SET 和异地备数据库 SET。同城主数据库 SET 和同城备数据库 SET 由三个数据副本构成(一主二备),异地备数据库 SET 由两个数据副本构成(一主一备)。
SET 内部基于 TDSQL 的主备强一致数据同步功能,可以实现数据的高可靠和零丢失。
二、2016 ~ 2018,同城多活架构改造
IDC 1.0 时代的架构基本满足了我行的业务发展需求,但还是存在以下几个问题:
- 同城双中心之间的数据库同步是 准实时 的,在极端场景下是有可能出现数据丢失的(同城 RPO 不为 0)
- 只实现了 DCN 分片单元粒度的多活,还没有实现真正意义上的应用跨同城数据中心多活;
- 在单个 DCN 或者 IDC 出现故障时,需要做人工的同城容灾切换,耗时太久(RTO 约二小时)
- 同城有 6 份数据库副本,资源成本较高。
既然有问题,那就得继续优化架构。所以我们提出了第二阶段的架构优化目标:
- 实现应用系统的同城跨数据中心多活 ;
- 数据库同城 RPO = 0,同城 RTO 接近于 0 ;
- 降低数据库副本数,减少成本 。
首先,我们在同城新增了一个数据中心,由同城的两中心,变为了同城三中心(IDC 2.0),这是实现同城应用多活架构的前提。
IDC 2.0 架构图
基于 IDC 2.0,我们设计了同城三中心多活方案,应用层和数据库的架构都做了相应的调整。
同城多活架构
数据库层面,由原来的双中心主备 SET 的架构模式,调整为单 SET 三副本跨三中心部署的模式,主节点可以进行读写,备节点只读,可以实现数据库层面的同城跨 IDC 的 RPO = 0,RTO 达到秒级。
以此为前提,应用层就可以实现真正的跨同城数据中心多活。也就是应用层可以在同城的三个数据中心内各部署一套对等的应用系统,接入业务流量,经过接入层转发,最终到数据库的主节点上(开启读写分离的情况下,读流量可以转发到备节点上)。
同城应用多活的架构改造, 进一步提升了整体的可用性,简化了容灾架构,同时也将数据库的六副本缩减为三副本,极大的降低了资源成本,可以说很好的完成了架构优化目标 。
三、2018 ~ 2020,引入 NewSQL 数据库
随着业务的快速发展,DCN 的数量也在快速增加,DCN 的水平扩展特性很好的支撑了业务的快速增长。但在某些 非 DCN 架构 的中后台业务场景中,单实例架构的数据库逐渐遇到了容量或者性能上的瓶颈。
一个比较典型的场景就是安全存证类的数据存储。这个场景属于中后台业务,需要持续存储交易行为类的数据,以供随时审计或者举证,所以一般是不能删除的。随着业务规模增涨,存证数据也会持续的增涨。
然而对于单实例的数据库来说,是要求不能超过 3 TB 的存储容量的,一个原因是硬件层面的限制(SSD 的单盘容量),另一个原因是单实例过大的容量,会带来数据库性能上的不确定性和运维的复杂性。
按照比较传统的解决方案,可以选择基于中间件的分库分表方案来解决这个问题。
然而分库分表事实上是对业务开发和 DBA 都不太友好的一种方案。对业务开发来说,因为分库分表一般在语法和 SQL 使用层面都会有一些限制和限定,所以一般需要重构代码和 SQL,以适配分库分表环境下的数据库使用;对于 DBA 来说,分库分表的扩展性不是那么灵活,DDL 等日常操作也比较得复杂,使得整体的运维工作量增加。
我们不想走回分库分表的老路,所以也在探寻有没有更优雅、更先进的解决方案。2018 年下半年开始,NewSQL 的概念逐渐兴起,带来了一种 全新的 Share Nothing 的分布式架构的数据库(基本上是以 Google Spanner 分布式架构为原型) 。
经过充分的调研和评估,我们最终选取国产开源的 NewSQL 数据库产品 TiDB 进行尝试。TiDB 主要有以下几个特性吸引了我们:
- TiDB 采用了标准的 Share Nothing 架构,计算与存储分离,并且都可以做到水平扩展,且对业务层透明。
- TiDB 采用 MySQL 协议体系,与我们当前的协议体系兼容度高,降低业务的开发和迁移成本以及接入门槛。
- TiDB 采用开源的模式进行运营,社区较为活跃,版本迭代较快,并且已有一部分的互联网用户开始使用。
TiDB 整体架构
可以说,TiDB 的特性可以很好的解决我们的需求和瓶颈,但当时 TiDB 还是属于一个非常新兴的数据库产品,稳定性和成熟性不够,所以我们也是非常谨慎的进行充分的测试和验证,在生产上首先选取的比较边缘的业务场景进行灰度,并且准实时同步一份数据到 TDSQL 进行兜底。
TiDB 在微众的部署架构也类似于 TDSQL,利用同城三机房的硬件优势,采用同城三副本跨三中心部署,可以 有效的支持应用同城多活架构 。
TiDB 部署架构
经过近两年多的运营,我们已将 TiDB 应用在安全、智能监控、数据归档、反欺诈、反洗钱、历史交易明细查询等各类中后台业务中。随着 TiDB 的版本逐渐成熟,整体的 稳定性和可运维性 也提升了不少。
回头来看,虽然我们冒着吃螃蟹的风险,采用了 NewSQL 的方案而放弃了分库分表的方案,但带来的收益也是巨大的。
目前, TDSQL 继续作为核心数据库,承载 DCN 架构下的核心系统 ;TiDB 作为补充,承载非 DCN 架构下的、对容量和扩展性要求较高的中后台系统。TiDB 作为微众整个单化元架构的补充,很好的补齐了数据库层面的短板。
四、2020 ~ 2021,NewSQL 在核心批量场景的应用
经过两年多对 TiDB 数据库的使用,踩了不少坑,也积累了不少经验。TiDB 本身随着版本迭代也更加成熟稳定,逐渐形成企业级的数据库产品。
2020 年初,我们收到了贷款科技部门针对贷款核心的日终批量系统的优化需求。
当时,贷款核心系统的日终批量系统是部署在业务 DCN 内部的,和联机系统复用 DCN 内的 TDSQL 数据库资源。随着交易数据的日积月累,贷款核心系统的批量面临着以下几个问题:
- 批量的耗时持续增涨(优化前已近三小时),如果因为某种原因批量需要重跑,有比较大的超时风险。
- 批量系统和联机系统都在 DCN 内部署,批量系统带来的数据库高负载,会对联机系统产生影响。
- 受限于 MySQL 的主备复制的原理限制以及单实例的性能瓶颈,无法继续通过提高应用层并发来提升批量效率。
- 批量效率逐渐成为单个 DCN 的用户容量瓶颈,而非实际的用户量。
贷款核心批量架构(优化前)
基于以上问题,业务部门也提出了优化目标:
- 将整个批量系统重构(包括应用层和数据库层),核心业务微粒贷的整体批量耗时缩短到半小时内以(在限定的资源内)。
- 将批量系统的资源和联机系统完全解耦(包括应用层和数据库层)
- 批量系统的数据库需要具备可水平伸缩的特性。
最初看到这个优化目标,感觉还有挑战的。特别是每天数亿条帐务的批量计算处理,需要优化到半小时以内完成,应该没有那么容量。
经过评估,我们最终决定尝试用 NewSQL 数据库 TiDB 来承载贷款核心的批量系统(优化后的架构如下图)。批量数据每天通过 DCN 内的 TDSQL 近实时的同步到 TiDB 集群进行汇总,然后由批量应用程序在 TiDB 集群进行批量计算和加工。经过近一年的持续优化、调整和灰度验证,最终项目顺利上线,并且完全达到了既定的优化目标。
贷款核心批量架构(优化后)
下表是微众 5 个主要贷款业务的核心批量优化前后的耗时对比,优化效果非常明显。
在整个项目的实施的过程中,踩坑不少,也总结了不少的优化经验和教训,主要有以下几点:
- 应用 SQL 模型的整体重构和优化
- 针对批量应用的 SQL,进行 SQL batch 化的改造,提升单个 SQL 的效率;
- 对于频繁访问的热点静态数据进行缓存,减少 SQL 的请求次数;
- 对复杂 SQL 进行内存占用优化、执行计划优化等,降低 SQL 的耗时。
- 基于 TiDB 的热点数据打散机制优化
在 Share Nothing 架构的数据库中, 数据热点是经常会遇到的一个问题,如果分片规则或者应用的写入的规则不合理,很容易就形成针对某一个数据库分片的热点,导致数据库响应变慢,甚至假死。
贷款核心的批量数据表,都是数亿级别的数据量导入,热点问题更加明显。针对这种超大表的数据导入,我们联合数据库厂商,开发了数据表预打散的功能,完全避免了热点问题。
- TDSQL 到 TiDB 数据同步的一致性校验机制优化
贷款核心批量的数据正确性至关重要。在优化后的架构,批量数据表需要从多个 TDSQL 源近实时的汇总同步到一个 TiDB 集群中,并进行合表处理。为了保证数据同步的可靠性和准确性,我们在三个层面做了优化:
- 对数据同步工具做了高可用架构优化,确保没有单点问题,并且在某个同步节点故障后,可以自动进行替换和恢复;
- 对数据同步增加全方位的监控,包括同步状态、同步延迟、数据源存活状态、目标端存活状态等;
- 在应用层增加数据分片同步的实时校验。针对每一个数据分片,应用层都会计算一个 CRC 校验值,并由上游的 TDSQL 同步到下游的 TiDB,待此分片数据同步完后,在下游再进行一次 CRC 计算,并和上游同步过来的 CRC 值进行比对;除了分片校验,还会有数据行数的最终一致性检验。
- 故障 SOP 预案和兜底机制的建立和演练
- 针对日常的服务器故障,或者数据库 bug,导致的批量中断,准备了批量断点续跑的预案,并在生产环境定期演练;
- 针对可能的数据错乱导致批量需要重跑的场景,通过批前的 rename 备份表的方式,可以实现快速的批量重跑。
- 针对极端的灾难场景下,需要重建数据库进行批量重跑的场景,通过批前的冷备数据,进行快速的数据库重建和导入,从而实现批量重跑。
TiDB 数据库在贷款核心批量系统的应用,是对微众整个单元化架构的又一次补充和完善。我们经常说,数据库没有银弹,没有一种数据库能够适用所有的业务场景。针对每个场景,用最适合的数据库产品和数据库架构,才是价值的最大化。
除了关系数据库产品,我们也大量使用了 Redis 来适合大部分需要高并发、低延迟响应的读场景。在尽量保证架构一致性的前提下,我们根据业务的实际需求,也少量引入了 Monggo DB、PostgreSQL、Oracle 等数据库产品。
未来,我们也将在数据库的云原生、数据库的智能运维、数据库的硬件国产化、HTAP 场景的应用实践等方向继续探索,不断提升和完善我们的架构,为国产数据库在金融场景的应用实践贡献自己的一份力量。