剑客
关注科技互联网

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

云数据库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)进行计算。

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址