火山引擎云数据库 veDB 在字节内部的业务实践
veDB 整体架构呈现计算与存储分离的总体特征。以 veDB(for MySQL) 为例,其技术架构具有以下特点:
完全兼容 MySQL :计算层基于 Percona Sever 8.0 版本打造,完全兼容字节线上的 MySQL 生态,字节的应用迁移到 veDB 上不需要任何改造; 计算存储分离:云原生架构,计算引擎能力和存储能力均可以独立扩展; 超大实例容量:数据库容量不受单机磁盘容量限制,存储层容量可以按需扩展; 只读线性扩展:添加只读节点无需拷贝数据,并且只读节点支持页面级别 REDO 并行回放技术,提供低读延迟(~10ms); 闪速备份恢复:存储层支持快照备份,通过 PITR 技术快速恢复至历史任意时间点。
veDB(for MySQL) 具体的发展历程如下图所示:
目前,在字节跳动内部,veDB 已大规模接入线上业务,包括在国内预生产环境已完成了对 RDS MySQL 的全量替代,已接入国内生产环境 ~40% 的业务库,基本覆盖所有业务门类。预计到 2022 年底,veDB 将替代内部 RDS MySQL 约 80% 的国内业务,并使综合成本下降约 30%。同时,veDB 也已亮相字节跳动云服务平台火山引擎,对外提供 NewSQL 类 DBaaS 服务。
veDB(for MySQL)技术挑战
在构建 veDB(for MySQL)的过程中,团队遇到了以下三方面的技术挑战:
相比于本地的 NVME SSD 磁盘,计算存储分离架构会带来时延的增加; 在只读节点读延迟方面,如何做到比较低的读延迟; 由于业务会有各式各样的个性化诉求,需要对其个性化的数据进行优化。
如何克服时延挑战
解决方案
共享内存写缓存/NVME SSD 读缓存:首先,Redo 日志在写入远端 Log Store 之前,会写入一个共享内存,然后再批量写入远端,这样做虽然类似于原生 MySQL 异步提交,但效率上要比异步提交高很多;其次,团队提供了二级读缓存的特性,虽然本地盘比较小,但是也有一部分存储空间,团队利用这部分存储空间来实施 Buffer Pool 的扩展,大大减少对远端 Page Store 的读取操作; 页面预取/计算下推:团队面对部分业务场景可以针对性地进行页面预取优化,提前从 Page Store 读取页面到缓冲区,可以避免在有需求时临时读取; RDMA/AEP Store:这个其实类似于 PolarDB 读写 Polar FX ,但是 RDMA 部署会受到一些条件限制,团队目前是在有部署条件的场景下推行使用 RDMA 网络,并且结合 AEP Store 优化读写时延。
只读节点如何做到超低读延迟
页面(Page)级别并行回放机制:首先只读节点启动后,veDB会基于最新快照,持续从共享存储去拉取物理日志并行解析回放,值得注意的是,veDB可以根据不同的规格选择不同的并行机制;
Redo 日志拉取(Pull)模式:这种模式下的计算节点读写,RW 节点和 RO 节点之间并没有直接的网络交互(如上图所示),只读节点从存储池拉取 Redo 日志;
Redo 日志推送(Push)模式:Push 模式是指在 RW 节点完成日志持久化之后,直接把 Redo 日志推到只读节点。
数据导入能力优化
对于如何更快从 MySQL 迁移数据,传统方式是 MySQL 本身支持 Dump、Restore, 或者第三方工具支持 Myloader Mydumper ,但由于存储计算分离,这种逻辑转换方式的性能表现并不佳。
优化效果如何呢?总体而言,对于24G(1亿条)数据,用时从 1637s 降到 32s,性能提升了 51 倍;对于 69G(3 亿条)数据,用时从 21585s 降到 95s,性能提升了 227 倍。
大表DDL处理优化
解决方案
veDB引入了 FastDDL 来解决以上问题,具体而言:
主键索引(源表)页面预取:DDL 分为两个阶段,第一个阶段是对原表主键索引进行全表扫描,然后在这一阶段进行精准的页面预取;
并行构建(按索引,多机房):第二个阶段就是并行构建,比如按照索引并行构建,团队要重新构建表,其中包含 10 个索引,那么会有 10 个并发;同时,如果机房之间通过 Binlog 去同步,团队可以多机房一起执行;
存储层 Write-Through:veDB 架构的特点是 Log is Database。为了优化 DDL,团队直接写入 Page store,Bypass 了 Log store,起到一定的加速作用。
关于优化效果,主要有以下三点:
普适:基本上 MySQL 能够支持任何 Online DDL的操作; 快:它作为一个内部实现工具,是 gh-ost 速度的十分之一; 静:团队不引入 Binlog 主备延时,比如机房分别执行 DDL,等待它们执行差不多,最后 relay 就能完成。
复杂查询下推处理优化
解决方案
计算操作(部分)直接下推存储层:当执行任务时,团队会去查询 B+ 数的倒数第二层节点,得到需要分发的页面 ID 情况,并且把任务并行分发给存储层; 并行任务分发:团队引入了并行执行查询算子, SQL 层完成分发之后,可以通过算子收集结果,汇聚并返回给计算层; 回表查询页面精准预取:对于回表查询,比如查完二级索引之后,需要去主键索引上查询,团队会做预取。
秒杀场景优化
在类似于秒杀、限时抢购、抢红包等场景下,大量用户需要在极短时间内请求商品或者红包,此时数据库将面临单行记录大并发更新的老大难问题。通常,这会导致系统活跃线程增加、 TPS 降低、时延增加、系统吞吐降低。针对这种情况,目前有两种解决方案,其一是不依靠数据库,在应用层进行处理,但是这种方案较为复杂;其二就是依靠数据库来解决问题。
解决方案
SQL 语句更新列热点标识:对于带有热点更新标识的 SQL ,团队会在数据库内部维护一个哈希表,会将相同数据的 SQL 放在哈希表的一个队列里; 批量处理:经过一段时间之后,团队会针对队列里的 SQL 进行合并处理; 语法糖:为了更好地满足业务需求,veDB支持打开 Binlog ,以及语法糖,比如:Auto_Logic_Commit_Rollback hint,是指成功就自动提交,否则 Rollback;另外veDB扩展 Update..returning,支持语句返回。
基于以上操作,实施效果如何呢?以一个 20c 的虚拟机为例,单行更新性能能够达到 9.3w QPS,多行更新性能能够达到 14.7w QPS。同时,团队目前已经上线了电商直播、抖音的本地生活,在业务直播带货过程中,即使热点商品 QPS 突然猛增到 1.5 万,veDB数据库也能够提供足够的支持。
计算引擎写能力如何扩缩容?
对于一写多读的架构,是如何做到多写呢?团队结合了字节内部的分库分表的中间件与 veDB,提供 Multimaster 支持。但是分库分表的 Multimaster 在写流量较大的场景时(例如 618 或双 11 活动)会面临集群扩容的问题,活动结束后又会面临集群缩容的问题。传统基于中间件的分库分表方案扩容需要复制数据,会面临两个问题:其一是耗时与数据量成正比,其二是还需要一倍的冗余空间,因此需要扩容。另外,分库分表目前没有一个有效的在线缩容方案,会导致在大型网络活动结束后,没有办法及时缩容。
首先来了解一下 veDB(for MySQL) 在字节的部署情况,主要包含高可用和高可靠两种部署方案。
高可用部署方案
因此,该部署方案适用于对可用性和性能要求较高的业务场景,同时在极端情况下,比如机房整体故障,可能会损失失一点数据。
高可靠部署方案
小微库
历史库
单体大库
分片库
veDB目前往以下方向发展:
多写架构——Multi Master 2.0
Multi Master 2.0 的架构如下图所示,一共包含三层,分别是接入层、计算层、存储层。veDB主要提供了以下三方面的支持:
DDL :团队会提供一套完整的 DDL 语法(包括表、索引),之前采用分库分表的方式时,DDL 通常是通过DBA提交工单的方式去执行的,对外肯定是不行的;同时,也会提供 Online 操作,允许并发 DML; 增强分布式事务/查询:支持分布式一致性读/写,以及支持全局二级索引; 其它:还会进行一致性备份/恢复,融入 Quick Resharding。
复杂查询:列存储索引和向量化引擎
内存优化表
在这个方向上,veDB主要提供了以下三方面的支持:
MM 事务引擎:MemTable 本质上是一个单独的存储引擎,独立于 InnoDB 之外,与 InnoDB 实现方式完全不同,但是能够达到 10 倍的 InnoDB 性能;另外,veDB提供了完整的 ACID 能力; MM 存储引擎:深度融合了 RDMA/AEP,另外,日志和数据一体化; 编译执行:在 SQL 语句上执行了预编译优化,大幅减少了 CPU 执行指令数。
除了上述外,团队下一步还会在新硬件、无服务器方面对veDB进行迭代。新硬件方面,veDB会融合RDMA/AEP/DPU;无服务器方面,veDB会开展自主扩缩容、“自动驾驶”等。