深度揭秘腾讯云数据库技术的 7 年变迁史

早在上个世纪 50、60 年代,“数据”二字就已不再是简单的数字信息而已。随着信息技术的不断发展,在计算机应用领域,计算机存储和处理的对象逐渐广泛,表示这些对象的数据也随之变得越来越复杂,数据库这一门新兴学科的应用也越来越广泛。纵观国内几大云服务商过去几年在云数据库领域的发展,腾讯云基于自身的业务场景以及技术研发能力,在云数据库市场上也经历了蛰伏、发展与突破。

2012 年,伴随着腾讯宣布历史上第二次组织架构调整,腾讯云数据库 MySQL 高性能版、CKV 兼容 Memcached 版本的推出,也正式开启腾讯数据库新时代。
2016 年,马化腾首次公布过去 18 年腾讯存储总数据量超过 1000 个 PB,面对如此庞大的数据量,腾讯金融分布式数据库 TDSQL 商业化进程就此展开。
2018-2019 年,当“上云”已成常态,在特定场景下重磅升级后的腾讯云数据库(TencentDB)也应运而生。

在 2019 年 5 月 21 日举办的腾讯全球数字生态大会上,InfoQ 记者也有幸与腾讯云数据库产品总监王义成做了一次深度对话,详细回顾了腾讯云数据库七年变迁之路。

腾讯云数据库演进史

跟很多互联网公司不同的是,腾讯初始的业务发展并未对数据库有过强依赖。

与最初需使用 Oracle,SQL Server 等商业数据库的 IOE 厂商相比,腾讯云数据库的起步是从 KV 与存储分析的类型开始。直到当财付通和微信红包这类的业务产生后,这才逐步促使着关系型数据库的使用,因此腾讯内部是没有一个去 IOE 的过程。那么腾讯是以何种路线逐步进阶数据库的?

这还得先从腾讯云数据库的发展历程说起,其发展历程总体来说可以分为两条线:

  1. 迎接开源——开源定制参与回馈开源——为云而生定制——适配客户需求;

一开始,腾讯云数据库建设主要引入了当时业界较为主流的开源数据库,如 MySQL,Redis,PostgreSQL 等。随后针对云上客户定制需求,腾讯云在数据库中衍生研发了如数据库并行复制、审计日志、在线加字段等核心功能,并将以上功能回馈给了 MariaDB 和 MySQL 社区。

  1. 内部自研——业务倒逼技术发展——云化支撑——走进互联网及传统行业。

之后,腾讯云开启了数据库自研的道路,其自研数据库典型代表是 TDSQL、CKV 以及 CynosDB 等产品。随着财付通、微信红包等业务的爆发性增长,对数据库稳定性、安全性和数据一致性的需求也倒逼着自研数据库技术的不断发展和成熟。接下来,腾讯云在服务越来越多的云上用户,并向企业级用户进发后,也逐步开始对外输出到金融、政府等传统行业,因此对数据库的要求也越来越高。

王义成在受访时回忆说,在这段发展历程中,腾讯·财付通刚成立的时候是对内部数据库依赖最强的时候。2003 年,腾讯的数据库从开源数据库 MySQL,到适配业务而自研 MySQL,当财付通业务真正发展起来后,业务需求就开始持续倒逼腾讯云数据库产品的演进。

因此,腾讯数据库的发展更多是在初始就已选择用开源数据库来承接。而此后,由于腾讯海量用户的存储需求与业务爆发性的增长,倒逼腾讯更加理解开源,进而在开源的基础上,适配业务进行数据库的自研迭代。

从开源到适配

作为一个产品驱动型的企业,当产品的大方向确定之后,腾讯会驱动技术做相应选型,比如财付通的研发,就需要一款交易类型的关系型数据库来支撑。但在任何一款数据库产品研发之前,腾讯都需要预测数据未来可能到达的量级。值得注意的是,无论是成本的压力也好,或者说业务的压力也罢,都并不足以驱使当时的腾讯选配 Oracle 等商业数据库。

因此,腾讯必须选择一条成本与基础能力均可控的方式——在开源的基础上,慢慢地演变自身业务,把单节点变成双节点,再把双节点进行横向扩展。然而。在提前预测相对合理的业务发展路径并做出选择之后,产品的开发过程仍会出现很多的问题,比如交易场景下的查证能力拓展等。

2007 年的财付通,其查证能力在一组多读的情况下还是存在数据延迟,这对于用户来说是完全无法接受的。但也是由于这些业务需求,促使了 TDSQL 这款数据库产品的诞生,其适配了异步多线程的强同步复制方案,这在当时也是领先其他云计算友商的解决方案。

从适配到自研

而对于腾讯云自研的数据库,主要分为两类,一类是 为腾讯内部业务适配而生的自研数据库 ,比如腾讯金融级数据库架构 TDSQL;另一类 是基于服务海量客户后的 经验 ,腾讯云在新的场景下,由开源数据库适配业务自主研发的数据库 ,比如企业级云原生数据库 CynosDB。

第一类是腾讯业务上的突破自研。从某一个历史结点上来看,那时的开源或商业数据库的场景是无法满足业务发展的,因此腾讯云自研了许多相应的数据库适配业务的迭代,典型的代表就是 KV 类型的数据库——CKV,它是由海量存储衍生的 KV 类型数据库,以及在线分析数据库 TBase。

另一类自研数据库,是在真正服务了很多云上的客户后,腾讯云发现开源数据库并不能完全满足用户的需求,或者说用户需求即便被满足,也并未激发出使用云数据库的最大价值。用户数据规模较小的时候,使用腾讯云的数据库服务比自建 IDC 节省很多成本,但随着用户使用数据库的规模逐渐扩大,腾讯云数据库团队思考要提供超出用户想象的产品和服务,节省运维以及人力成本是云数据库 1.0 时代的特征,到了 2.0 时代,云数据库要在根本上具备自建数据库无法比拟的优势,才能成为支持用户业务运转不可撼动的基石。

这时,分布式数据库成为了用户自建与云厂商服务有所区分的关键。分布式数据库也同样分两类,一类是像 MPP 并行计算的数据库,以及把数据拆分为多个节点的分布式数据库;另一类是当下比较流行的存储分离数据库。从工程实践以及成熟性的角度来看,存储与计算分离的架构确实是更适合在分布式数据库上取得成功的工程实践,这也成为腾讯云布局自研数据库的初衷。说到腾讯云自研数据库,就不得不提到两款十分具有代表意义的数据库——腾讯分布式数据库 TDSQL & 企业级云原生数据库 CynosDB。

腾讯业务倒逼自研——TDSQL 技术全解析

2002 年,由于当时腾讯的计费产品还处于起步阶段,技术团队选择完全基于开源 MySQL 构建数据库体系。为了解决计费等公司级敏感业务高可用、核心数据的零流失、核心交易的零错账等问题,腾讯从 07 年开始自研了一款数据库产品,这也是 TDSQL 的前身,这款数据库在当时很好的支撑了 09 年的开放平台浪潮。

随着腾讯开放合作的发展扩大,行业场景越来越多,这款数据库无法很好的为合作伙伴提供服务,因此从 2012 年开始,由腾讯内部业务适配而衍生的自研数据库 TDSQL 诞生。那么,TDSQL 是如何实现自主可控和技术迭代的呢?

TDSQL 架构解析

从架构上讲,TDSQL 是 Shared-Nothing 架构的分布式数据库;从部署方式来讲,TDSQL 是一款支持多租户的云数据库。整体来说,TDSQL 是由决策调度集群 /GTM,SQLEngine、数据存储层等核心组件组成的,其每个模块都基于分布式架构设计,可以实现快速扩展,无缝切换,实时故障恢复等,通过这一架构,TDSQL 的 Noshard、Shard、TDSpark 实例可以混合部署在同一集群中。并且使用简单的 x86 服务器,可以搭建出类似于小型机、共享存储等一样稳定可靠的数据库。

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

  • replica 配合故障的检测和切换,解决可用性问题;

  • sharding 配合集群资源调度、访问路由管理等,解决容量伸缩问题。

同时,因 replica 引入了数据多副本间的一致性问题和整体吞吐量下降的问题,而 sharding 的引入也会带来一定的功能约束。在最终实现上,TDSQL 由 Scheduler、Gateway、Agent 三个核心组件加上 MySQL 组成,其中:

  • Scheduler 是管理调度器,内部又分为 zookeeper 和 scheduler server;

  • Gateway 为接入网关,多个网关组成一个接入层;

  • Agent 是执行代理,与 MySQL 实例一起,构成数据节点。多个数据节点构成服务单元 SET。

TDSQL 面向数据一致性考验

在金融行业,银行、风控、渠道等第三方通常通过读写分离方式来查询数据,而在互联网行业,由于 x86 相对较高的故障率,导致数据可能经常性的出现错乱、丢失场景。为了解决这个问题,就必须要求主从数据保持强一致和良好的读写分离策略。而其中的关键在于如何实现强同步复制技术。

由于 MySQL 的半同步和 Galera 模式不仅对性能的损耗是非常大的,而且数据同步有大量毛刺,这给金融业务同城双中心或两地三中心架构容灾架构带来了极大的挑战。为什么会这样呢?

从 1996 年的 MySQL3.1.1.1 版本开始,业务数据库通常跑在内网,网络环境基本较好,因此 MySQL 采用的是每个连接一个线程的模型,这套模型最大的好处就是开发特别简单,线程内部都是同步调用,只要不访问外部接口,支撑每秒几百上千的请求量也基本够用,因为大部分情况下 IO 是瓶颈。

但随着当前硬件的发展,尤其是 ssd 等硬件出现,IO 基本上不再是瓶颈,如再采用这套模型,并采用阻塞的方式调用延迟较大的外部接口,则 CPU 都会阻塞在网络应答上了,性能自然上不去。

为了解决这些问题,TDSQL 引入了线程池,将数据库线程池模型 (执行 SQL 的逻辑) 针对不同网络环境进行优化,并支持组提交方案。例如,在 binlog 复制方案上将复制线程分解:

  1. 任务执行到写 binlog 为止,然后将会话保存到 session 中,接着执行下一轮循环去处理其它请求了,这样就避免让线程阻塞等待应答

  2. MySQL 自身负责主备同步的 dump 线程会将 binlog 立即发送出去,备机的 io 线程收到 binlog 并写入到 relaylog 之后,再通过 udp 给主机一个应答

  3. 在主机上,开一组线程来处理应答,收到应答之后找到对应的会话,执行下半部分的 commit,send 应答,绑定到 epoll 等操作。绑定到 epoll 之后这个连接又可以被其它线程检测到并执行。

改造后, TDSQL 基本可以应对复杂的网络模型。

但上述方案还有小缺陷:当主机故障,binlog 没有来得及发送到远端,虽然此时不会返回给业务成功,备机上不存在这笔数据,然而在主机故障自愈后,主机会多出来这笔事务的数据。解决方法是对新增的事务根据 row 格式的 binlog 做闪回,这样就有效解决了数据强一致的问题。

基于规则和基于代价的查询引擎

当前大多数分布式数据库都设计的是基于规则的查询引擎 (RBO),这意味着,它有着一套严格的使用规则,只要你按照它去写 SQL 语句,无论数据表中的内容怎样,也不会影响到你的“执行计划”,但这意味着该规则复杂的数据计算需求不“敏感”。虽然金融业务都有自己的数据仓库,然而也会经常需要在 OLTP 类业务中执行事务、Join 甚至批处理。

TDSQL 在 SQLENGINE 实现了基于代价的查询引擎 (CBO),SQL 经过 SQLENGINE 的词法、语法解析、语义分析和 SQL 优化之后,会生成分布式的查询计划,并根据数据路由策略(基于代价的查询引擎)进行下推计算,最后对汇总的数据返回给前端。

而作为分布式的计算引擎,在存储与计算引擎相分离的情况下,非常重要的一环就是如何将计算尽量下推的下面的数据存储层。因此 TDSQL 的 SQLENGINE 在经过大量业务打磨后,实现了基于 shard key 下推、索引条件下推、驱动表结果下推、null 下推、子查询下推、left join 转化成 inner join 等多达 18 种下推优化手段,尽量降低数据在多个节点传输带来的压力,以提供更好的分布式查询的能力,支撑金融交易的关联操作。

开源数据库适配自研——CynosDB 技术全解析

伴随着云计算时代的到来,云数据库服务常被大家理解为,云厂商直接把传统数据库搬到云上,让客户以租用的方式获得服务。但由于传统数据库在云上的资源利用率低、扩展能力不足、资源规划难,以及备份难等缺点,使得传统数据库无法完全释放云上得天独厚的扩展性、可靠性和规模化等优势。

2017 年,在腾讯云服务了百万客户之后,由开源数据库适配业务和具体场景,腾讯云自主研发了数据库 CynosDB,它将传统数据库与云计算的优势相结合,解决了传统数据库云上的难题,其设计思路可以概括为以下几点:

  1. 首先是计算存储分离,比如把运算 CPU 或者内存放在一起统一分配,可以获得弹性调度能力。

  2. 第二个是日志下沉及异步回放,同时我们移除了数据页面的刷脏逻辑,这样降低了计算存储分离的架构下的网络开销。

  3. 第三个就是分布式存储,这也是我们腾讯云自研的分布存储系统,共享的分布式存储可以横向扩展。

  4. 第四个是后台的持续日志备份,传统数据库我们的备份是在数据库主机上去拷日志完成备份,而 CynosDB 的持续备份是在存储上进行,不干扰数据库实例,减轻由于备份的工作任务对数据库的冲击,并且用户可以不必关心备份策略和备份存储资源规划。

计算存储分离架构的实现和优化

传统数据库的优化演进历史,基本上是和 IO 做斗争的历史,因为数据库是有状态、重 IO 的服务,传统 MySQL 架构有多个 IO 类型,存储相同的文件,所以主机和备机的磁盘会有很多相同的 IO 和冗余的文件。即便数据库被搬上云,为了在云上做弹性的扩容,开发者依然面临传统数据库所面临的问题。

基于以上痛点,CynosDB 引入计算存储分离的架构,存储层使用共享的分布式块存储云服务,计算层则将不必要的 IO 全部卸载,实现计算与存储基于日志传输的新架构。

CynosDB 架构有如下几个特点:

  1. 日志即数据库。架构中只有日志流,因而只有日志能表达数据库;

  2. IO 卸载。除了日志,其他所有类型 IO 全部卸载,如数据文件、源数据文件、biglog 文件等;

  3. 无状态。本地文件将不复存在,包括日志文件,所以计算层是无状态的。

在新架构中,日志处理无可厚非具有非常重要的作用。其中连续的日志在存储层被打散成了很多的小的分片,分别存储在不同的 cell 里。而日志处理的逻辑是将存储引擎将日志发给存储节点,存储节点将日志放到一个日志队列里面,并将其持久化,之后立即返回给存储引擎,当存储引擎获得日志的反馈后就可以将一部分事务提交。其中,存储节点会异步的进行一些操作,这些操作和事务的提交过程无关,不影响事务的提交响应速度。

而在数据库里面,如果 buffer 足够的话,数据库的写性能是和日志的落盘时间相关的,传统数据库组提交机制可能存在几个问题,一是如果有大量的连接进来,MySQL 将会为每一个连接创建一个线程,如果用户的业务没有连接管理,那么将会存在频繁的线程创建与销毁,浪费很多资源,同时,大量并发线程的锁冲突以及切换代价也会非常大。

针对以上问题,CynosDB 引入了线程池,直接解决了资源管理和线程切换的问题,但线程池只适合处理短任务。为此,CynosDB 同时引入了异步组提交的机制,基于线程池实现,再增加独立的日志写线程 log writer,每一个工作线程提交事务的时候,并不是去做写和刷的操作,而是将自己的请求提交到一个提交队列里去,然后立即返回给 Server 层,以便释放自己的线程资源。如果某一段日志持久化成功之后,log writer 会唤醒提交队列里面等待的请求,将其重新调度到线程池的高优先级队列,重新获得工作线程执行事务提交后的工作。如此一来就能高效的利用线程池的资源,同时做到资源的控制,避免上下文频繁切换带来的性能问题。

日志下沉、异步回放的关键设计

日志下沉是什么意思?比如开发者在一个页面做插入操作,生成的日志会放到日志管理子系统的日志 buffer 里,日志 buffer 的重用、刷新、并发管理等都是由数据库来做。CynosDB 会把日志管理做成独立模块,并在 CynosStore Client 中实现。任何数据库如果想接入这个系统的话,都不用去关心日志管理,直接调相关接口完成日志记录即可。这里的日志和普通日志存在区别,比如 PG 的日志更偏向逻辑的概念,而 CynosDB 的日志,记录的是物理修改(对某页面的什么位置做了什么内容的修改)。另外,日志向日志 buffer 的插入过程是并行的,若有 5 个用户同时生成日志,往日志 buffer copy 都是并行进行的而非串行。

总结来说,日志下沉是指 DB 层产生的日志都会放到 CynosStore Client 的 buffer 中,然后异步发送到分布式存储中,而不是存到本地。而在分布式存储中有一块固定的存储空间来专门存储日志,由于空间大小固定,因此在 CynosStore 中会有特定的线程,定时地把日志异步地合并到数据页面上,通过这种日志回收机制可以有效的利用日志空间,保证写的连续性。

CynosDB 应用场景及未来规划

近日,腾讯云数据库 CynosDB 正式亮相 MariaDB 用户者大会,并受到了 MariaDB 基金会以及众多参会者的认可。

据了解,今年 Q3,CynosDB 将会彻底完成商业化。与此同时,腾讯云数据库产品总监王义成还向记者透露,CynosDB 的技术能力以及存储层早已具备按使用量计费的能力,计算层也正在进行相应的适配,待 CynosDB 商业化后将逐步推上日程。

由于 CynosDB 对主流开源数据库的兼容,以及快速弹性升级、海量数据存储等优势,王义成称,CynosDB 未来将持续落地应用于包括互联网及游戏等广阔的行业,帮助用户更好地应对业务高峰,加速业务创新。

后记

从 2012 年到 2019 年,这七年,腾讯云数据库无不见证、参与数据库技术发展史上的一次次突破与迭代。回望这段从开源到适配,从适配到自研的历程,腾讯云可以说将每一次经由业务适配考验后的思考、经验都化作数据库服务的“活水”,灌溉自身业务的同时也灌溉了开发者社区。

但值得注意的是,在长达几十年的时间里,由于国内数据库市场启动较晚,国外巨头始终占据数据库绝对领先优势,使得国产数据库的发展十分艰难。未来,由云原生技术带来的一系列新技术与市场机遇,不仅仅是对数据库管理员的挑战,也是对数据库产品内核与工具的考验,接下来腾讯云数据库“风”往何处吹?且看“行云”。