写点什么

探寻腾讯金融数据库 TDSQL 的十年之路

  • 2016-11-03
  • 本文字数:6300 字

    阅读完需:约 21 分钟

云数据库 TDSQL 是一种兼容 MySQL 的关系数据库,是腾讯云提供的金融数据库解决方案。在腾讯 TEG 计费平台技术总监潘安群看来,金融的数据库要满足一下要求:新环境下的金融数据库应满足以下要求:要保证数据安全性、高可靠性,对数据丢失零容忍;需要高可用的容灾架构,以解决分布式环境中各种异常灾难;完善的水平扩展能力,以适应当前互联网爆发式增长带来的业务请求量和数据量。那具体而言,TDSQL 为了实现其适用于金融行业目标都做了哪些技术功课?InfoQ 采访了腾讯云 TDSQL 的潘安群先生。

嘉宾简介

潘安群,腾讯 TEG 计费平台部技术总监,目前主要负责金融级分布式数据库 TDSQL 的研发工作。2007 年加入腾讯,一直专注于分布式存储系统研发,尤其是分布式 NoSQL 及 MySQL 体系在支付金融领域的研发与实践。

InfoQ:TDSQL 目前线上使用情况如何?有哪些想和大家分享的亮点?

潘安群: TDSQL 诞生于腾讯计费平台部,2014 年开始为微众银行提供核心交易层数据库解决方案,2015 年正式上云,作为腾讯云金融政企行业的数据库解决方案,为客户提供公有云及专有云数据库服务。目前 TDSQL 的客户已覆盖第三方支付、互联网金融、银行、保险、证券、互联网 + 等多个金融政企行业。

数据库技术圈子不大,大家技术交流很开放,开源社区也很活跃,彼此会互相借鉴,所以技术层面,最终可能会殊途同归,只不过是各自产品针对不同场景,做不同的取舍而已。我们认为 TDSQL 有两点比较能打动人的:

  • 良好的用户体验:无论是开发体验,还是运营体验。腾讯很重视用户体验,集团内部有场景并大量使用 TDSQL,腾讯产品上线都会要求腾讯自己首先是重度用户,而刚好我们计费平台部有这么一个场景,全公司所有计费系统全部承载在 TDSQL 上,包括近 100 亿的账户或订购数据,其中就有大家熟知的 Q 币,各类包月服务、游戏点券等等。数据分布在深圳、上海、香港、加拿大等多地。可以说我们积累了很多经验,支付体系对数据库层的要求是什么;也会从运营和开发两个层面去不断思考什么样的数据库才好用。
  • 细节的把控:腾讯 10 多年来在 MySQL/NoSQL 等方面趟过的坑可谓一部血泪史,这促使我们不断的优化细节。就以容灾切换为例,在各种异常、各种灾难下,系统是否表现如预期一样是需要一个长期积累的过程。从 08 年以来,我们几乎每个月都会挑选系统,进行容灾演练确保容灾机制符合预期。即便如此,我们系统在线上依然发现很多场景没有覆盖到,因为故障的表现总是五花八门。所以一个系统的细节完善程度,一定是通过趟坑,在实践中去逐渐完善的。

InfoQ:为什么基于 MySQL?为什么当时没有选用其他类型的开源关系型数据库?

潘安群: 为什么会选择 MySQL 作为 TDSQL 的底层存储引擎,核心还是下面几点:

  • 团队技术能力:从技术上来说对 MySQL 更有把握。从 03 年开始,我们的团队基本都是基于 MySQL 定制开发,积累了不少相关经验。
  • MySQL 的技术成熟:本身的成熟度。金融场景要求的是稳定可靠,这正是我们技术选型的一个重要考查点。
  • 广泛使用和传播:MySQL 使用广泛;我们看好其 MySQL 社区的发展。尤其是 MySQL 近些年的几个大版本表现都非常出色。

InfoQ:TDSQL 的技术研发积累已经十二年,可否分阶段介绍下技术的发展?

潘安群: TDSQL 作为腾讯计费平台数据存储层的第四代产品,虽从严格意义上来说,其研发始于 2012 年,但实际上是我们十二年数据存储层容灾、扩容等方面的经验沉淀:

1)2003-2008,MySQL 热备 + 分库分表 最原始的数据库容灾扩容方案,备份直接使用 MySQL Replication 机制,一主一备或一主两备;容量或性能问题,通过在应用层的分库分表来实现。

整体来说,这套机制是简单有效,但也存在明显的问题,就是在极端情况下,可能会丢数据:因当时 MySQL 只有异步复制模式,并没有现在的 Semisynchronous
Replication,在主机异常或网络异常情况下,应用层直接切换到备机,是有可能丢失数据的。

2)2008-2010,MySQL 7*24 容灾 针对在异常情况下,会丢失数据的问题,我们设计了一套名为“7*24”的容灾体系,其核心思路就是增加了一个一致性控制中心(CC)。CC 会不断的比对主备数据之间的数据同步情况,当故障发生时,CC 会知道所有未同步数据(黑名单),应用层在切换到备机之前,需要先到 CC 拉取这份黑名单,将这些数据置为不可用状态,而其他数据则可以直接访问备机。通过牺牲极少部分用户的可用性,换取了 DB 主备切换的一致,一致性问题得到了系统的解决。整个故障检测、切换、恢复过程均由系统自动完成,基本无需手工操作。

通过大量的容灾演练和实战积累,这个阶段有了相对完善的孤岛检测、黑名单、多级切换等机制。同时,故障检测、主备一致性保障、数据恢复等机制也被提炼出来。当然,这套机制也有着她自身的问题:与应用层是高度耦合的,这要求每个业务开发人员必须对整套容灾逻辑非常熟悉,开发难度和运营维护难度都很高,而且容易出错。

3)2010- 至今,HOLD,一套基于全内存的,高一致性的 KV 存储系统 为了解决应用层与数据层高度耦合的问题,我们又开发了第三代产品,但是她的底层存储不再基于 MySQL,而是自研的一个全内存 KV 存储引擎。

后来的 TDSQL 架构和其中重要技术,几乎都在这个项目里进行了系统性的验证,包括在数据底层实现跨 IDC 的强同步、跨城容灾、切换一致性保障、数据自动的 Sharding、集群管理等。目前 HOLD 存储系统在公司内还大量使用,尤其是一些超高并发的业务系统。而她的缺点也是 KV 系统固有的问题,仅仅支持简单的 Get/Set 等接口,开发不够灵活。

4)2012 年 - 至今,TDSQL 经过近 10 年在数据存储层的摸爬滚打,我们希望能更优雅地解决数据层的问题,于是 2012 年立项 TDSQL:把 HOLD 中验证过的集群架构直接移植过来,将金融场景下最关注的一致性保障和水平伸缩等关键特性,都直接被融入底层架构中,这次直接使用了 MySQL 作为数据存储引擎,以获得成熟的关系型数据存储和访问能力。当然这里也有软硬件行业发展的契机:

  • SSD 在公司内开始大规模使用,SSD 的 IOPS 相对于机械硬盘有质的变化,能满足大部分系统的性能需求。利用好 SSD 优势,能极大简化存储系统的架构体系。
  • 以 KV 为代表的 NoSQL 无法形成业界标准及规范,反观以 Oracle、MySQL 为代表的传统关系型数据库生态完善,使用范围也更广,更容易被开发人员接受。
  • MySQL 在 5.5 版本引入半同步复制,5.6 版本引入 GTID 等机制,而且经过 5.5,5.6,5.7 等几个版本,开源的 MySQL 在性能、数据强一致性方面有了质的提升。

InfoQ:可否给介绍下你们的分布式数据库架构和设计思路?

潘安群: 在架构上,TDSQL 的核心思想只有两个:数据的复制(replica)和分片(sharding),其他都是由此衍生出来的。其中:

  • replica 配合故障的检测和切换,解决可用性问题;
  • sharding 配合集群资源调度、访问路由管理等,解决容量伸缩问题。 对应地,replica 引入了数据多副本间的一致性问题和整体吞吐量下降的问题,而 sharding 的引入也会带来一定的功能约束。

在最终实现上,TDSQL 由 Scheduler、Proxy、Agent 三个核心组件加上 MySQL 组成,其中:

  • Scheduler 是管理调度器,内部又分为 zookeeper 和 scheduler server;
  • Proxy 为接入网关,多个网关组成一个接入层;
  • Agent 是执行代理,与 MySQL 实例一起,构成数据节点。多个数据节点构成服务单元 SET。

InfoQ:是怎么保证服务器的高可用的?

潘安群: 分布式系统中,完整的容灾体系一般都是基于这样一个理论而设计的:多个独立的小概率事件同时发生的几率极低。

举个例子:假如一台服务器在一年内会出现故障的可能性为 0.5%,且服务器之间都是独立的。那么,在某一天内,任意指定的两台服务器均出现故障的几率为:(0.5%
\* 1/365)^2=0.00000002%,也就是常说的 7 个 9 的可用性,远远高于金融要求的 5 个 9。注意,这里的时间跨度是“同一天”,如果缩小到“同时”,如小时甚至分钟级别(一般一个节点故障恢复所需时间是几秒至几小时),这个几率还要小很多。

在这个理论中,实际有四个变量:多个、独立的、小概率、同时。传统的 IOE 架构,专用的软硬件使得其在
“小概率”这个方向上优势明显。而在互联网分布式架构中,正是因其分布式,在“多个”和“同时”这两个方向天生就有优势,所以容灾设计的大部分精力都是投在“独立的”这个方向上。

TDSQL 中,直接在 SET 这个级别上针对上述四个方向进行了优化:

  • “多个”,实际就是冗余度,这里是数据副本的个数。理论上是越高越好,但是太多副本一方面资源投入太大,另一方面保持副本间的一致性成本也很高;所以,在 TDSQL 中,一般要求一个 SET 三个节点;
  • “小概率”,就是节点的故障率,具备一定冗余度的节点会有更低的故障率,比如双电源、双网卡、磁盘 RAID 等。TDSQL 中,通过采用更加可靠的物理服务器来降低单机故障概率;
  • “同时”,实际上可以认为就是单节点的故障恢复时长,如果在一个节点的故障恢复时间内,同一个 SET 的另外一个节点又发生故障,则这两个节点就是“同时”故障。这个时长越短越好。在 TDSQL 中,节点故障是优先本地恢复,若本地恢复不了,会在异地通过物理快照 + 增量 binlog 实现快速重建;
  • “独立的”,就是说一个 SET 内的节点间,越独立越好。但是,这个世界所有东西都是相关的,绝对的独立是没有的。以两台服务器为例,如果它们在同一个机架、或者接入同一个交换机、或者在同一个 IDC,当机架电源故障、或者接入交换机故障、或者 IDC 故障,则两台服务器对外将表现为同时故障。更不用说更大范围的故障了,比如一个城市故障,整个城市的服务器都将“同时故障”。更好理解的例子是:如果地球没了,整个人类世界都没了。所以,“独立”只能是某个级别上的独立。在传统金融方案中,两地三中心的容灾方案,就是城市级别的。在 TDSQL 中,采用的“同城三中心,异地三中心”的方案,相比具有更高的容灾级别。

在同城部署时,一个 SET 至少三个节点,且三个节点跨三个 IDC。当一个 SET 中主机故障时,系统自动切换至备机,对上层应用没有任何影响;由于节点间的数据副本是强同步的,数据也不会有任何的丢失或错乱。当出现 IDC 级别的故障(如整个 IDC 网络孤岛或掉电宕机)时,仍然能保障每个 SET 至少有两个节点,服务也不会受到影响。

在跨城(两城地理距离 >1000km)时,SET 内在异地增加 watcher 节点。Watcher 节点不参与主备切换选举,仅通过异步方式从 master 复制数据。当整个主城故障且无法短时间内恢复服务时,可以直接将服务切换到异地的 TDSQL 上。这时候可能会存在几秒的数据的丢失,但在城市级灾难情况下,这属于可容忍范围。
所以,TDSQL 是将容灾直接做到 SET 内部:每个 SET 可部署为跨机架、跨 IDC、跨城容灾。在不考虑双重灾难的前提下,一个 SET 就是一个永不停服、永不丢数据的服务单元。

InfoQ:什么情况下建议采用数据库的分库分表?什么情况下不建议?

潘安群: 目前 TDSQL 有两个分支版本,一个是 No-Sharding(NS)版本,一个是 Group-Sharding(GS)版本。NS 版本不支持自动扩容;GS 版本支持自动扩容,但是该版本对 SQL 有一些限制,例如只支持 Group 内的 Join,不支持跨 Sharding 的 Join 等。

什么情况下选择 NS 版本,什么情况下选择 GS 版本,对于客户来说主要基于业务的数据量与并发量。目前 NS 版本,在我们现有机型下,最大支持 6T 存储空间,12 万 QPS,如果业务的数据量和并发量小于这个值,推荐使用 NoSharding 版本,因为其 SQL 是 MySQL 全兼容的。如果超过这个值,或者未来增长会比较快,那么就必须选择 GS,虽然在 SQL 语法支持上达不到 NS 版本,但是胜在业务可以近乎无感知的平行扩容。目前我们 TDSQL 在腾讯云上最大的 GS 库表是汇通天下,目前服务器数 12 台(一主一备模式),数据量已达 20T,请求量峰值达到 180 万笔每分钟。

InfoQ:数据库进行分库分表之后怎样保证数据一致性?数据的备份和复制工作应该遵循怎样的基本原则?你们有哪些优化?

潘安群: 我们谈数据的一致性的时候,通常有两种:一种就是 CAP 理论里的一致性,重点描述的是一份数据多个副本的数据一致性;另外一种是 ACID 理论里的一致性,重点描述的是事务的一致性。

首先解决的是多副本的数据一致性,在实现时,主要依赖如下两个机制:

  • 强同步机制:基于 MySQL 半同步复制优化,对于进入集群的每笔更新操作,都将发到对应 Set(每一个 Set 包含 3 个 MySQL 实例:一主两备)的主机上,主机会将 binlog 发往两个备机,且收到其中任一一个备机应答后(仅仅是备机收到了 binlog 并刷盘,但可能还没有执行这个 binlog),然后才本地提交,并返回给客户端应答,这就能确保数据零丢失。此外,强同步机制势必会影响系统吞吐量,所以我们也引入线程池实现,并做了异步化,以提升并发性能。
  • Leader 选举:MySQL 节点本身无法直接参与选举,于是我们由 Scheduler 模块来负责这个事,如果主机发生故障,Scheduler 会从两个备机中,选择一个数据较新的备机(因为 MySQL
    binlog 是严格有序的,所以谁同步主机 binlog 的偏移量更大,谁的数据就更新。当然也可以基于 GTID 来判断)提升为主机。

其次是事务一致性问题:TDSQL 水平 Sharding 后,数据被分布在不同的物理节点,如果一个事务涉及到多个物理节点上的数据,那就存在事务的一致性问题。目前 TDSQL 提供 2PC 的分布式事务功能,当然这里会有性能损耗,业务开发需要做一个选择和平衡:是由数据库的分布式事务来保障数据强一致,还是在应用层来实现。在大并发量的场景下,把这个提前到应用层,并做一些取舍,成本会更好控制。

InfoQ:各个分片数据怎么保证高可靠?如果某个分片出现故障了,该分片数据会怎样,系统会有什么响应措施?

潘安群: 在 GS 版本中,一个 Group 包含多个 Set,每个 Set 负责一个或者几个分片的数据,前端 Proxy 根据路由信息分发 SQL 到对应的 Set。

在 Set 内部,一般使用一主两备的架构,同时主备间使用强同步。如果一个备机挂了,不影响业务;如果主机挂了,由于至少一个备机是和主机同步的,因此该备机升为主机,同时修改路由信息,使得 SQL 能够正确地分发到主机。如果之前的主机能够修复,降为备机加入 Set;否则新增备机加入 Set。整个过程都不需要人为参与,单点故障不影响业务,不丢数据。

InfoQ:在您看来,分布式数据库的运维难点和重点在哪里?

潘安群: 分布式数据库运维体系里面,我们认为最重要的两点就是:自动化和监控。

关于自动化,现在 TDSQL 几乎所有的运营操作,例如购买、扩容、切换、备份、定点恢复、升级等等,均可以通过 HTTP 接口来完成。

关于监控,其实这里挑战很大,误告和漏告对运维来说都是极不友好的事。目前 TDSQL 的做法,基本围绕两个基本原则:

  • 透明。这是最基础的,系统应充分的将自身内部状态呈现出来,并上报到监控系统,目前我们已经采集了 100+ 指标,包括 InnoDB 锁信息、MySQL 活跃线程数,请求时耗等。此外我们也对每一个操作的进度及结果都有严格的采集要求。
  • 告警分级。例如我们对于主备切换,这是非常高级别,需要 NOC 电话告警,而对于慢查询这类,跟业务相关性较强的告警,会配合 IO、CPU 等使用率做告警聚合, 减少告警量。

InfoQ:TDSQL 适用什么样的场景,不适用什么样的场景,为什么?

潘安群: 当前 TDSQL 版本定位主要还是金融、政企的 OLTP 数据库场景,对于 OLAP 这类数据分析场景支持略显不足,对比 Oracle、PostgreSQL 系列产品,在统计函数和统计语法支持方面,例如分析函数等支持不够。此外我们的分布式版本,在分布式 JOIN 等,还有不少优化空间。所以我们并不推荐客户在 TDSQL 上做非常大量的数据分析工作。如果客户有大量的报表需求、关联查询,且数据量较大,我们的解决方案就是通过消息队列,将 TDSQL 数据实时同步到大数据平台(例如 Hadoop)进行计算。

2016-11-03 23:004867
用户头像

发布了 58 篇内容, 共 43.8 次阅读, 收获喜欢 35 次。

关注

评论

发布
暂无评论
发现更多内容

MySQL没有RowNum,那我该怎么按“行”查询或删除数据?

Java 程序员 后端

MyCat:第四章:Mycat中的概念(1)

Java 程序员 后端

MySql数据引擎简介与选择方法

Java 程序员 后端

mysql常用函数,mysql进阶

Java 程序员 后端

MySQL 数据库开发入门(四):MySQL 的数据引擎

Java 程序员 后端

MySQL基础总结

Java 程序员 后端

Mybatis开发要点-resultType和resultMap的区别?

Java 程序员 后端

MySQL 5

Java 程序员 后端

mysql-排它锁之行锁、间隙锁、后码锁

Java 程序员 后端

mysql分表spring拦截器进行日志采集

Java 程序员 后端

MyBatis官方文档-XML 配置

Java 程序员 后端

mybatis常用注解(绝对经典)

Java 程序员 后端

MyBatis逆向工程Generator和IDE Plugin

Java 程序员 后端

MySQL原理 - InnoDB引擎 - 行记录存储 - Off-page 列

Java 程序员 后端

MyBatis常用标签和注解(绝对经典)

Java 程序员 后端

MyBatis详解(二):mybatis开发dao

Java 程序员 后端

MYSQL-连接查询算法:JOIN语句在-MYSQL-内部到底是怎么执行的

Java 程序员 后端

MySQL基础学习手册

Java 程序员 后端

mysql用户&权限总结

Java 程序员 后端

MyCat教程【安装及配置介绍】

Java 程序员 后端

MySQL 千万数据量深分页优化

Java 程序员 后端

MyCat:第四章:Mycat中的概念

Java 程序员 后端

MySQL 千万数据量深分页优化(1)

Java 程序员 后端

MySQL入门篇

Java 程序员 后端

MySQL最全整理,1200页文档笔记,从高级到实战讲的太清楚了

Java 程序员 后端

mybatis映射器组件

Java 程序员 后端

MyCat1

Java 程序员 后端

MySQL 事务隔离级别

Java 程序员 后端

MySQL没有RowNum,那我该怎么按“行”查询或删除数据?(1)

Java 程序员 后端

MyBatis的Mapper接口以及Example的实例函数及详解

Java 程序员 后端

MYSQL 分组排名

Java 程序员 后端

探寻腾讯金融数据库TDSQL的十年之路_数据库_木环_InfoQ精选文章