摘要: 本文整理自 OSC 重庆源创会上简怀兵老师的演讲,他从TxSQL 的发展历程、特性功能、深度优化及演进计划四个方面,对腾讯 CDB 内核进行了全面的解读。欢迎大家积极参加源创会,一起交流、学习、进步。
简怀兵,腾讯云数据库高级工程师,负责腾讯云 CDB 内核及基础设施建设,从事 MySQL 内核开发工作 8 年,具有丰富的优化经验;在分布式存储等领域有丰富经验。
TxSQL,是腾讯 CDB(Cloud Database 云数据库)的内核,由开源的数据库 MySQL 分支发展而来。
本文会从四个方面来对 TxSQL(腾讯CDB内核)进行解读,分别是:
- TxSQL 的发展历程
- TxSQL 的特性功能
- TxSQL 的深度优化
- TxSQL 的演进计划
一、TxSQL 的发展历程
TxSQL 最早是用于腾讯的内部业务,像腾讯游戏当中使用的数据库。
然后受业务驱动,被用于互联网金融支付业务。支付业务对数据库提出了更高的要求,尤其是在性能和稳定性方面。
再后来,运营推动其发展,针对外部需求加上更多功能。大家比较熟悉的可能就是 RDS(腾讯云)。
所以基本上 TxSQL 的发展历程就是首先从内部业务到互联网金融,再到现在 RDS 上蓬勃发展的趋势。这三个业务的维护慢慢驱动形成了一个腾讯内部自己维护的数据库分支 —— TxSQL。
二、TxSQL 的特性功能
TxSQL 的特性功能有很多,在此仅列出一些大家可能比较感兴趣或者是对开发者及其他公司来说会有一些借鉴性的功能。
① 分布式锁服务
TxSQL 这个内核分支当中有提供一个分布式的锁服务。这个锁服务是用来做什么的呢?
首先它提供了一个和连接无关的锁服务,可以通过完整的和 MySQL 兼容的协议来使用这个锁服务。它和现在的一些分布式锁服务不一样,比如说 zp(ZooKeeper)。不一样的地方在于:
第一是它可以实现让你的锁和你的数据在一起;第二是可以用原生的完全兼容 MySQL 的协议来使用这个锁服务。所以它提供的其实是两个不一样的东西。
比如说有时要部署一个 MySQL,需要一个比较高可用的集群,同时还要去做一些后期的维护,有了分布式的锁服务以后,不需要做额外的应用,只需要在 RDS 里面操作,后面所用的高可用、运维等一些东西都已经包含在 MySQL 这个运维的体系当中了。
② 超级 root 账号
这个功能比较有意思。拿 MySQL 来说,在公有云上申请了 MySQL 实例时,后端会负责做主从复制、备份,但是做这些工作都需要有一个 MySQL 账号。假如现在已经申请了一个数据库实例,但有时候由于误操作或其它原因,会把一个不属于自己的业务帐号删掉,由此会影响网站后端做备份这些功能。
TxSQL 提供的这个 root 账号,其实是 MySQL 的虚拟账号。即便把 MySQL 的系统表 delete 以后,也不会有任何影响,后端的业务还是可以连接上来,继续运营、运维。
③ OSC(Online Schema Change)
所谓 OSC,就是 Online Schema Change。用过数据库的人都知道,尤其是互联网业务,变化很泛,业务需求在变,产品形态也在变。此时就有对数据库的表结构、规范结构进行增加、删除和字段类型修改的操作的需求。如果在原生 MySQL 中实行这样的操作,会比较麻烦而且有风险。这个功能可以通过改变内部的表结构来与原生的进行支持,并且可以在线修改。
④ 带租约的工作模式
在一些对移植性要求比较高的数据库的应用场景下,为了防止在同一个拓扑结构下会有多个 master 或者是有多个读写的情况,可以通过带租约的工作模式,把每一个 MySQL 的实例定位到一个具体的 multi mode 当中,就是说现在是只读、可读写还是说查询类似这样的一些区分。
带租约的工作模式,即是可以通过外围的一些空 paper 让租约在整个拓扑范围内,让每一个节点达到一个唯一确定的状态。
⑤ Binlog 限速插件
在 MySQL 的主从之间,一般原生的是通过获取 node 来访问主从复制,但这样就会有一个问题,就是在主从之间(也就是 master 和 slave 之间)新建了一个实例,如果中断时间比较长,而你的网络刚开始恢复的时候,它会瞬间把你主从之间的带宽给打满,这可能会影响到其他一些正常的业务逻辑。
为了避免类似这样的问题,TxSQL提供了一个限速插件。这个插件在主从同步的时候,可以设置阈值。因此即便在这种情况下,也可以保证为业务应用预留一定的带宽。
⑥ Super Read Only
第六个就是 Super Read Only。在 MySQL 发布 5.5 之前,也有 Read Only 这样的一个功能,但为了保证访问数据严格的一致性,又开发了 Super Read Only 的功能,不管是 root 账号还是其他的普通用户账号,通过开启这个功能都可以保证数据在预期的时候去写,不会出现不预期的写。
⑦ 预留 super 连接
这里指的是预留 super 连接的权限。比方说,当你开发了一个 app,可这个 app 有 bug,它会一直去连接 MySQL,但是每一个 MySQL 实例都是有连接次数限制的,所以有可能会因为这个程序的 bug,导致设置的 GET 连接数被占满了。这种情况下,无论是 DBA 还是运维,都没办法连接上来做一些其他的应急措施。
因此,TxSQL 提供了这样的一个功能,会为预留的 super 账号提供一些额外的连接,这些连接不可以配置,因此即便是你的 app 有 bug 或是其他紧急情况下,也可以保证这个运维的连接是始终都可以连上的。
⑧ 安全 Reset Master
在通常情况下,比如主从复制正在进行时,外面 master 也正在进行一个 Reset Master 的操作,这可能会导致有些 Binlog 会被删除,下次再来建主从的时候就会导致有一些 node 还没同步过去就已经被删除,因此会出现建不上主从复制的情况。
TxSQL 会在 Reset Master 前,确保现在是没有主从连接。如果一定要做这个动作,而现在又有主从连接,会先把主从复制上的拓扑停掉。
⑨ 数据强同步
数据强同步的封装最早是在 MySQL 5.5 上,5.5 之前都是通过异步的方式。所谓的异步就是指 master 和 slave 之间不主从复制,比方说现在有一个 app 已经在 master 上,你提交了一个事务或一条数据,这时候把 master 的大小切到 slave 上,你会发现刚才提交的事务有可能已经查询不到。
为了防止这种情况,在 5.6 和 5.7 已经提供了半同步的功能,半同步和强同步的差别就是半同步第一次在某些比较特殊的场景还是保护不了数据同步的一致性,第二就是它会设置一个 time out 的值,第三个就是性能方面的问题,原生的话可能性能不足。
针对一些应用对数据的一致性要求非常高,TxSQL 在 MySQL 原生半同步的基础上进行了深度优化,确保一个事务在主库上提交之前一定已经复制到至少一个备库上,确保主库宕机时数据的一致性。
⑩ 在线 GTID 升级
MySQL 5.6 已经提供了 GTID 这样的一些特性,但是这个版本中从 非 GTID 的版本到 GTID 版本是没有办法比较简单在线升级的。所以为了确保可以在线平滑升级,有做一些工作。
最后还有两个特性功能,第一个是需要在某些场景下过滤其中一些功能,这就需要把一些 MyISAM 的表转换成 InnoDB 的表,第二个是把系统库里面的一些需求隐藏掉。
功能这部分就讲完了,这里列的 12 个特性功能,都是在最常见的使用场景当中对大家比较有意义的一些功能。
三、TxSQL 的深度优化
① 主从复制全链路优化
这个会在后面作为一个点单独来讲,比如说在主从复制中、优化过程中,还有很多其他环节中做了哪些优化,有什么效果。
② ReadView 优化
第二个是 ReadView 的优化,在最新的 MySQL 5.7.14 版本中,MySQL 官方已经有这个优化。
③ Redo Log Buffer 锁拆分
简单讲就是以前会有一把大锁去共享这个 Redo Log Buffer、去读写字段,然后都会频繁竞争这把锁,这就会导致在大并发的量下产生较大的性能开销。
④ Logical Clock(MTS)
Logical Clock,就是 MTS(multi-threaded slave)。传统的官方 MySQL 版本是 slave 去回放,master 同步 Binlog 过来的时候,都是单线程的模式,到 5.6 以后就变成了并行。
TxSQL上做了一些正式的优化,按临界事务提交的这个区间,只有不同的事务没有的情况下去竞争或者在同一个资源上的时候竞争,相当于把它的粒度拆分到最细。
⑤ Thread Pool
有关 Thread Pool 的功能,在 MySQL 中,一般情况下是产生一个连接就会去建一个线程,该线程用 node 连接,这个可能跟早期的 Apache 一样。
⑥ Redo Group Commit
Redo Group Commit,简单的理解就是因为 TxSQL 是 IO 密集型的服务器,对于服务器,最致命的东西就是 IO、磁盘,使用传统的机械硬盘又需要转磁头以定位到扇区,而这些东西的开销都很大,因此这个功能就是为了减少磁盘寻道和寻址的开销。
接下来从三个维度去介绍 TxSQL 所做的改进,分别是高性能、强一致和工程化。
1. 主要改进 - 高性能
在 MySQL 内核复制的 4 个主要环节优化:
- Binlog 读写锁拆分
- 网络传输 Binlog 串行变并行
- 写 RelayLog IO 合并和解锁
- 事务回放串行变并行(MTS)
1) 高性能 - Binlog 读写锁拆分
MySQL 5.6 存在的问题:
- 对 Binlog 的读写都要互斥,高并发(尤其是有多个 Slave)时,是影响性能的关键之一;
TxSQL 的优化:
- 将读写分离开来,多个写入的线程还是在锁保护下串行执行,每一个写入线程写入完成后更新当前 Binlog 的长度信息,多个 Dump 线程以 Binlog 文件的长度信息为读取边界,多个 Dump 线程之间并行执行。以这种方式来让复制拓扑中的 Dump 线程发送得更快!
2) 高性能 - 传输 Binlog 串行变并行
MySQL 5.6 存在的问题:
- 未收到上一个 Binlog Event 的 ACK 之前,不能发送下一个 Binlog Event;
- 每个事务需要一个 RTT,不能有效利用主从 DB 之间的带宽,尤其是跨园区条件下;
TxSQL 的优化:
- 将发送和 ACK 回应的接收独立到不同的线程中,由于发送和接收都是基于 TCP 流的传输,所以时序性是有保障的;这样发送线程可以在未收 ACK 之前继续发送,接受线程收到 ACK 后唤醒等待的线程执行相应的任务。
3) 高性能 - 写 RelayLog 时 IO 合并和解锁
MySQL 5.6/5.7 存在的问题:
- IO 线程和 SQL 线程竞争 RelayLog 的锁
- 以 Binlog Event 为单位写文件,产生大量小 IO
- 写 Masterinfo 文件产生额外文件 IO
- 频繁动态内存分配和释放
TxSQL 的优化:
- 使用读写边界解除 IO 线程和 SQL 线程之间的锁竞争
- 合并小 IO 到事务级别
- 使用 GTID 规避 Masterinfo 文件写 IO
- 内存复用
4) 高性能 - 事务回放串行变并行(MTS)
MySQL 5.6 存在的问题:
- 事务按 Database 级别并行,并发粒度大,效率低
TxSQL 的优化:
- 在 Master 上提交无冲突的事务,都可以并行回放
2. 主要改进 - 强一致
优化 MySQL 内核半同步复制为强同步:
- Master 提交事务前保证至少有一个 Slave 已经收到日志
- HA 单独处理临界事务
存在问题:
- Master 在本地完成事务提交后再同步 Binlog,导致幻读
1 )强一致 - 事务不丢失和消除幻读
MySQL 5.6 存在的问题:
- 主 DB 先提交事务再发送给 Slave, 在发送过程中 Crash 时,主 DB 可见的事务在从 DB 不可见
TxSQL 的优化:
2) 强一致 - 临界事务处理
HA 存在的问题:
- Master 写 Binlog 成功,但 Binlog 同步时进程 Crash;
- Master 进程恢复时,会产生多余的事务
TxSQL 的优化:
- Truncate 临界事务的 Binlog 信息
3. 主要改进 - 工程化
1) 工程化 - 低侵入
- 业务痛点:老应用迁移成本高、风险大、无法享受新技术红利
- TxSQL 的方案:完全兼容 MySQL 5.1-5.7 的复制中间件
2 )工程化 - 健康诊断和审计
业务痛点:
- 访问安全:IP、帐号、对象、越权操作记录、不活跃帐号
- SQL安全:注入、宽松条件的修改\删除、低效SQL
TxSQL的方案:
- 对访问和SQL相关安全事件进行记录
- 对异常事件进行拦截或者预警
- 提供SQL级别耗时统计
3 )工程化 - 兼容
业务痛点:
- 不同业务使用不同分支的 MySQL,迁移难
- 不同业务使用不同版本的 MySQL,升级难
TxSQL 的方案:
- 支持主流 MySQL 分支
- 支持在线升级
- 支持业务的持续集成
四、TxSQL 的演进计划
首先是实现用户使用的基本功能,然后在此基础上进行深度优化,也就是上面提到的那些。将来,会针对架构进行优化。