TDSQL-C 的内核关键技术深入解读
日前,Distributed Cloud|2021 全球分布式云大会·上海站隆重召开。腾讯云凭借其信息技术系统的安全可控性和前沿技术的创新性,在一众企业中脱颖而出,荣获**“分布式数据库创新技术奖”**。这是继腾讯云数据库 TDSQL 获第四届中国保险大数据分析与人工智能创新国际峰会年度“保险创新者大奖”之后再次获评。
在云原生专题论坛上,腾讯云数据库产品专家梁文灿先生就腾讯云企业级分布式数据库 TDSQL 生态发展战略、落地应用案例做出了详细介绍。同时腾讯云数据库专家工程师张远先生对云原生数据库 TDSQL-C 的内核关键技术进行了深入解读。
TDSQL-C 基于全新计算存储分离的分布式数据库架构,融合传统数据库和云计算技术优势,100%兼容 MySQL 和 PostgreSQL,极致计算能力突破千核,存储容量达 PB 级别,使得性能和安全性媲美商用数据库。并且 TDSQL-C 支持集群和 Serverless 灵活弹性部署,克服传统架构下的存储量受限、扩展难、主从延迟高等缺点,充分释放领先技术的成本效益,最高可为企业节省 90%的成本。
下面带来腾讯云数据库专家工程师张远老师主题为《腾讯云 TDSQL-C 云原生数据库技术》的文字版。
TDSQL-C 简介
张远介绍说,TDSQL-C 是腾讯云自研的新一代企业级云原生分布式数据库,经过五年的打磨,在总体架构上,TDSQL-C 是基于共享存储的存储和计算分离的架构。
与传统的 MySQL 主备架构对比,可以看到传统的 MySQL 主备通过 binlog 进行逻辑复制,而 TDSQL-C 是通过 redo 日志进行的物理复制;传统的 MySQL 需要向存储写多份数据包括 data,binlog,redo log 等, 而 TDSQL-C 只需向存储写一份 redo 日志即可;传统的 MySQL 主备各存储一份数据,而 TDSQL-C 基于共享存储只有一份数据。
TDSQL-C 具有以下几个关键的特性:
(1)可靠性。TDSQL-C 基于共享存储的云原生架构,存储是多副本的,能够保证数据可靠性。同时能够做到即时回滚,任意时间数据都可靠。
(2)极致性能。腾讯云对主备机读写性能做了全面优化,同时也根据不同规格做针对性优化。
(3)可用性。TDSQL-C 可以做到秒级的 RTO,故障几乎无感知,同时主备延迟可以做到毫秒级。此外,基于共享内存,数据能够快速恢复、快速预热。
(4)弹性扩展。数据能够快速透明拓展,而且容量最大可以达到 1PB,满足大的需求。
TDSQL-C 内核关键技术
张远演讲的第二部分围绕关键特性展开,详细介绍了 TDSQL-C 特性背后的技术原理和细节。
1、TDSQL-C 之高性能
(1)TDSQL-C 高性能-plan cache
TDSQL-C 高性能的一个重要优化是实现了查询计划缓存,称之为 plan cache。
图中展示了一条 SQL 在数据库中的执行过程,会经过以下几个阶段:
首先 MySQL server 接受到用户的 SQL 请求,在 parse 阶段解析为逻辑的执行计划树,接下来在查询优化阶段生成物理的查询计划,然后执行器从存储引擎获取数据进行计算。
经过 plan cache 优化后,一条 SQL 执行过程省略了前面的解析和查询优化阶段,SQL 的执行时间大大缩短了。
优化效果以 sysbench 场景为例,不同颜色代表不同阶段的耗时,可以看到经过 plan cache 优化后,parse 和查询优化时间减少了,性能提升了 70%左右。
(2)TDSQL-C 高性能-异步组提交
TDSQL-C 是计算和存储分离的架构,因此计算节点和存储节点之间的网络 IO 存在一定时延。而写事务提交时需要保证 redo 先刷盘才能完成提交,因此 Redo 日志刷盘存在网络 IO。TDSQL-C 在线程池的基础上进行了异步组提交优化,事务提交交给后台线程异步完成,将线程池资源提前释放从而能够去处理更多的请求。优化后整体的读写事务 QPS 有 70%的提升。
(3)TDSQL-C 高性能-Log Compaction
TDSQL-C 是基于日志的数据库,计算机节点和存储节点之间有日志的传输,同时 Master 节点和 TXStore 存储之间也有 redo 日志传输,TDSQL-C 将 redo 日志进行了压缩。
下图是 redo 日志的结构,一条普通的 redo 日志包括日志头和日志内容,日志头主要包括日志类型以及 Space ID 和 pageno 等信息。通常情况下日志头占了日志的较大一部分。TDSQL-C 对 redo 日志进行压缩存储,对于同一页面进行修改的多条 redo 日志可以共享一个日志头。优化后 redo 日志量减少了 30%。
2、TDSQL-C 之高可用
(1)TDSQL-C 高可用-物理复制
传统的 MySQL 的是通过 binlog 进行复制的。Binlog 复制是在 MySQL server 层进行的,binlog 记录的是逻辑的修改记录,binlog 在备库 apply 需要经过 server 层的 parser,optimizer 后再经过 engine 的 btree 查找才能修改到对应的记录。这个路径比较长,复制速度慢。
而腾讯云 TDSQL-C 采用的是 redo 物理复制。Redo 日志记录的是页面物理修改记录,redo 复制是在 engine 层进行的,备库 apply redo 日志不需要查找就可以直接定位到页面,在内存中完成页面的修改,因此复制速度快。
更重要的一点是,TDSQL-C 是基于共享存储的,主备数据物理上是一致的,而 binlog 复制只能保证逻辑一致。
(2)TDSQL-C 高可用-备库延迟优化
TDSQL-C 高可用另一个优化是备库延迟优化,TDSQL-C 最多支持 16 个备库提供读服务,备库延迟可以达到毫秒级别。其中一个优化就是备库读写 IO 冲突优化。TDSQL-C 备库是提供读服务的,同时备库也会 apply 主库传来的 redo 日志。
张远以场景举例说,首先用户读取 pageA,pageA 不在 buffer pool 中,那么会从 TXStore 中请求 pageA,TXStore 中请求 pageA 就存在网络和 IO 的开销。同时 redo 日志回放线程上有 log1/log2/log3 正在等待回放到 pageA 上。也就是说,用户发起的读操作可能阻塞 redo 日志回放线程,从而导致主备延迟。
优化方案是将 pageA 上的 redo 日志缓存到 page 上的链表中,pageA IO 完成以后再将链表中的 redo 日志回放到 pageA 上。这样 pageA 的 IO 过程就不阻塞 redo 的回放了。
(3)TDSQL-C 高可用-独立 buffer pool
TDSQL-C 高可用的另一个优化是独立 buffer pool。Buffer pool 是 InnoDB 数据页的缓存。计算节点 HA 重启后,buffer pool 需要重新加载进行预热,持续时间比较长,期间业务会受到较大影响。
TDSQL-C 将 buffer pool 从计算节点独立出来放到共享内存中,计算节点 crash 后 buffer pool 可以独立存在。这样一来,Buffer pool 不需要预热,重启时间也缩短了。
(4)TDSQL-C 高可用-秒级 RTO
TDSQL-C 在基于 redo 日志的架构下,计算节点 crash recovery 不需要 apply redo,redo 的 apply 由存储节点来完成。从而 crash recovery 时间相比传统 MySQL 要快很多。在此基础上,TDSQL-C 做了更多的优化,可以做到秒级 RTO。例如经过测试,大规格实例重启速度比较慢。
例如 buffer pool 为 500G 的大实例重启,初始化 buffer pool 耗时 23 秒,这对于用户来说是不可接受的。优化方案是并行初始化加 pag 上的 mutex 延迟初始化。并行初始化是指按 InnoDB buffer pool instance 来并行初始化。而 page mutex 延迟初始化,是指当 page 首次使用时才初始化,而不是在启动时全部都初始化。优化后 buffer pool 初始化速度提升近 20 倍,而且腾讯云将这个方案也贡献给了 MySQL 官方。另外回滚段并行初始化也贡献给了 MySQL 官方。
TDSQL-C 之弹性扩展
TDSQL-C 备库可以提供读服务。为了提供更好的读服务,腾讯云做了许多读优化。Btree 一致性读优化就是其中一个。
Btree 在数据的更新过程中会发生 SMO 操作,即 btree 的分裂或合并。
如图所示,Btree 发现分裂,page B 分裂为 pageB 和 pageC。Btree 分裂时,用户查询 pageB 可能导致数据不一致甚至 crash。但主库在 Btree 发生分裂时会通过 index 锁和 page lock 的方式保证正在发生分裂的 page 不被其他用户访问。但对于备库来说,备库通过 redo 日志不能感知 Btree 的 SMO 操作,SMO 操作所产生的日志只有页面修改的信息,redo 日志中没有 index lock 上锁信息。因此备库在 SMO 过程是没有被保护的,备库的查询可能异常。
这里有一个可选方案就是将 SMO 操作 index lock 记录到日志中,备库解析 index lock 日志对整个 btree 加 index lock。但 index lock 会锁整个 btree 导致并发查询性能比较差。
TDSQL-C 对此进行了优化,MySQL 的 SMO 操作是原子的,所有产生的 redo 日志都在一个 mini-transaction 中。引入新的日志类型来标记 redo 日志中 SMO 操作的边界。这样用户在查询 btree 过程遇到 page 在 SMO 操作重新扫描 btree 即可。例如用户访问 page A 时会判断一下 page 是否在 SMO,如果 A 在,则会在 mtr start 和 end 之间则重试。
这样优化后,备库读不会被主库更新产生的 SMO 操作所阻塞。
TDSQL-C 其它特性
TDSQL-C 秒改列(instant modify column)
在官方 MySQL8.0 支持 instant add column 后,修改列类型操作便顺势成为 MySQL 中最不友好的 DDL 类型,修改列类型既不是 inplace 的同时也需要 rebuild table。而在我们用户实践中,修改列类型也是用户执行比较频繁的 DDL 之一,而此操作会长时间阻塞用户的读写请求,对业务的影响非常大。
TDSQL-C 创新的支持了 instant modify column 功能,达到了秒级修改列的效果。
具体的实现方式是:
a.元数据多版本化, 表元数据保存列的多个版本信息,用户只能看到的总是最新的表元数据。
b.行记录增加版本信息对应到不同版本的表元数据上。
c.修改列只修改元数据,修改列的过程中不修改实际的行记录。
d.行记录读取时,老版本记录会自动转换为最新版本的记录。
e.行记录更新时,老版本记录会自动更新为最新版本的记录。
值得注意的是,这是业界首创的方案。
TDSQL-C purge 预读
Undo 空间膨胀问题是 MySQL 历史老大难问题,TDSQL-C 创新的通过 purge 预读解决了此问题。Purge 会读取 undo page 并清理 delete mark 的记录,清理完成后会释放 undo page,从而最终释放 undo 表空间。IO bound 场景, purge 时读取 undo page 更容易出现 remote IO。而 remote IO 时占用时间比较长,导致 purge 不及时 undo 日志空间膨胀。
解决方法是实现 purge 预读机制:
a.根据事务提交顺序在内存中保存 undo page 的 purge 顺序用于预读。
b.Purge coordinator 异步预读这些 page。
TDSQL-C 展望
展望 TDSQL-C 的未来发展,张远表示,未来 TDSQL-C 会进一步加强查询优化的能力,比如增加新的 join 类型如 SMJ, 以及在 parallel query 上做一些拓展。同时 TDSQL 在支持多写方面会进一步探索,未来 TDSQL-C 也会向 HTAP 方向演进,TDSQL-C 会同时具备 OLTP 和 OLAP 的能力。
评论