MySQL DuckDB 引擎的产品形态演进
RDS MySQL 将 DuckDB 嵌入到 MySQL 内核,利用 DuckDB 在分析查询场景下的性能优势,弥补了 MySQL 在 AP(分析处理)能力上的不足。
在产品定位上,我们从立项之初就明确了“MySQL 为主、DuckDB 为辅”的策略:以 DuckDB 增强 MySQL 的分析能力,并围绕 MySQL 的用户生态,尽可能兼容客户现有的使用习惯,包括语法、协议以及第三方工具等。
在技术实现上,我们将 DuckDB 以内置存储引擎的形式集成到 MySQL 中。这不仅使其天然具备 MySQL Server 层提供的各项能力(如数据字典管理、binlog 复制等),还能像 InnoDB 等原生存储引擎一样,独立承担来自 MySQL Server层的所有操作请求。 在查询SQL执行路径中引入 DuckDB 计算引擎,保证了DuckDB节点的查询效率和对MySQL语法的高度兼容。
基于 DuckDB 引擎的基础能力,我们推出了 DuckDB 只读实例。DuckDB 节点作为一个数据副本,接受来自主库的 binlog 日志回放,可以独立对外提供读请求的服务。同时,结合代理层的行列自动分流能力,MySQL 主节点和DuckDB节点共同提供了一个完整的HTAP 解决方案。
除了 DuckDB 只读实例这个形态,很多客户反馈,希望DuckDB节点能够作为独立的数据库实例单独部署,允许用户使用SQL直接进行数据写入,或者作为多个源实例的汇聚实例。 因此我们新推出了 DuckDB 分析主实例,也称DuckDB 分析主实例。
MySQL DuckDB 两种产品形态
MySQL DuckDB 分析主实例
主实例形态极大地扩展了 DuckDB 的使用场景,理论上所有可以使用 MySQL 的地方都可以替换为 DuckDB 主实例。 当然,主实例形态对 MySQL DuckDB 引擎也提出了更高的要求,包括数据的安全性保障,数据入库写入的性能, 以及更大的存储空间管理等。
下文将重点围绕 Binlog 适配、高可用与数据安全、数据入库能力、兼容性 四个方面,介绍 DuckDB 引擎在主实例形态下所增强的核心能力。
需要说明的是,DuckDB 的分析性能已在 TPC-H、ClickBench 等多项基准测试中得到充分验证。DuckDB 主实例在查询能力上与只读实例完全一致,同时具备相同的压缩效率,这些基础能力本文不再赘述。
Binlog 能力适配
在 DuckDB 只读实例上线时,我们默认关闭了只读实例的 Binlog 开关。其一,用户场景中只读实例通常无需额外生成Binlog日志;其二,当时 DuckDB 引擎对 Binlog 打开场景没有完全适配。 然而在 DuckDB 主实例形态,Binlog 是不可或缺的重要一环。 在主实例建设过程中,我们已完整适配 Binlog,并提供了以下技术能力:
1. 提供一主多从的集群部署结构,主从之间通过 Binlog 数据同步,支持对 Binlog 实时备份,支持下游的 Binlog 订阅需求。这里需要指出 DuckDB 主实例 Binlog 格式目前固定为 Mixed 格式(binlog_format=MIXED)。
2. 保障 Binlog 与引擎数据的一致性:DuckDB 引擎在事务提交阶段,将 Binlog 写入与 DuckDB 事务提交进行原子性协调。即使实例在事务提交过程中发生异常重启,也能确保 Binlog 日志与引擎数据的一致性(详见下一小节)。
3. 目前 DuckDB 已经适配 Binlog Cache Free Flush 以消除大事务提交时Binlog Flush的代价。后续会继续适配 Binlog 实时传输、Binlog 实时应用等优化以解决大事务及 大DDL 场景下的复制延迟问题。
4. 支持 Binlog 级联复制及多源复制:DuckDB 主实例可作为上游节点,参与多级复制链路。支持 Binlog 多源复制:DuckDB 主实例可同时作为多个源实例的复制下游,配置多条独立的复制通道。(多源复制的典型应用场景详见本文“客户实践”章节)。
高可用及数据安全
高可用,指数据库具备持续对外提供服务的能力。DuckDB 主实例采用一主多从的集群架构,主库通过 Binlog 向从库进行单向数据同步。当主库发生异常时,系统可自动触发高可用(HA)切换,确保服务持续可用。
DuckDB 主实例部署示意图
数据安全,具体指数据库 ACID 特性中的 Durability(持久性),即一旦事务提交,其结果必须永久保存,即使系统崩溃也不丢失。
对于 DuckDB 只读实例而言,由于其作为主实例的数据副本,对持久性的要求可适当降低:即使实例崩溃时部分数据尚未持久化,也只需在重启后从主实例拉取 Binlog 并回放即可恢复。为此,只读实例采用了 Binlog 幂等回放机制,确保主库和 DuckDB 只读节点的数据一致。
然而,对于 DuckDB 主实例,持久化能力成为刚性需求。在此形态下,数据仅以列式格式存储,无法依赖主节点重建数据,因此 DuckDB 引擎必须保证在任何故障场景下的数据持久性。DuckDB 主实例的数据安全主要通过以下几方面保障:
1. 备份恢复能力:DuckDB 主实例的备份恢复能力与标准 MySQL 实例完全一致,支持定期全量备份和基于 Binlog 的实时增量备份。在此基础上,提供精确到秒级的时间点恢复(PITR)功能,可将实例恢复至任意历史时间点。
2. 内核持久性保障:DuckDB 引擎自身通过 WAL 机制确保事务数据的持久性。在此基础上,我们在 MySQL 层面对 DuckDB 引擎的事务提交路径进行了改造,确保 Binlog 写入 与 DuckDB 本地事务提交 的原子性。在实例崩溃恢复阶段,系统能正确回放已提交事务,保证 DuckDB 引擎数据、Binlog 内容与 Binlog GTID 位点三者的一致性,从而实现了与 MySQL 标准对齐的数据安全保障。
综上,DuckDB 主实例在高可用与数据安全方面,已全面对标 MySQL 高可用实例,能够有效保障客户核心系统的持续可用性与关键数据资产的安全性。
数据入库性能
与只读实例仅支持主库 Binlog 日志回放不同,DuckDB 主实例支持多种数据写入方式,包括 Binlog 日志回放、SQL 直接写入,以及 DTS 全量与增量数据同步。其中,通过 Binlog 回放写入的方式与只读实例保持一致,日志回放性能可达约 30 万行/秒。此外,DuckDB 主实例还支持更灵活的复制拓扑,如多源复制与级联复制。
在业务直接写入或通过 DTS 同步数据的场景下,DuckDB 主实例仍能保持较高的入库性能,这主要依赖以下内核优化能力:
1. 批量导入模式:DuckDB 引擎提供 duckdb_data_import_mode 配置开关。开启后,符合条件的 INSERT 和 DELETE 请求会自动进入攒批提交路径,将多个 DML 操作在临时表中进行缓存,最终合并为单次事务提交写入 DuckDB 中,显著降低 DML 语句在 DuckDB 内的执行开销。
2. DuckDB 乐观汇入路径优化:在全量数据迁移阶段,导入事务会进入 DuckDB 的乐观汇入路径。在此模式下,事务提交时无需拷贝数据,而是直接将生成的 RowGroup 链接到表结构中完成持久化;同时,WAL 日志的真实数据写入也被跳过。乐观汇入降低了写入阶段的 IO 放大,提升写入吞吐。
3. 大事务 Binlog 优化:依赖 RDS MySQL Binlog Free Flush 能力,大事务提交时不需要将 Binlog Cache 中的内容拷贝到 Binlog 文件中,消除了大事务提交时写 Binlog 的性能瓶颈。
我们基于 Sysbench 数据集对 DuckDB 主实例作为同步目标端的写入性能进行了基准测试。
- 全量数据通过 LOAD DATA 方式导入时,峰值吞吐可达 200 万行/秒;
- DTS 增量同步的峰值吞吐可达 30 万行/秒。
需注意,实际同步速度受多种因素影响,包括源端实例的查询效率、表结构复杂度以及 DTS 实例规格等。上述数值为理想测试环境下的端到端同步性能上限。
RDS DuckDB 实例已与阿里云 DTS 深度集成。用户在创建 DTS 任务时,只需将目标数据库类型选择为 DuckDB,即可自动获得高效的入库性能,无需进行繁琐的参数配置与性能调优。
兼容性增强
兼容性是我们持续进行优化的方向,在近期我们对在以下方面做了增强。 SQL 语法兼容方面,通过对MySQL Prepare 阶段得到的抽象语法树进行反解析,完成了对SQL的正则化,有效解决了超 90%的不兼容 SQL 语法,兼容性大幅提升。在函数方面,我们通过快速迭代,支持了近二十个使用频率较高的JSON函数,正则函数等,基本涵盖线上用户的所有常见函数,对于一些使用频率较低的不常见函数,我们也在陆续支持,最终将会在函数方面完全兼容MySQL。
我们近期对 DuckDB 引擎支持了 ascii, latin1 等字符集,支持生成列。对 COPY DDL 执行效率进行了增强。 这些内核能力演进可以参考我们的 Release Note:
客户实践
某出行平台使用 DucDB 主实例进行数据汇聚
客户需对近期业务订单进行全局查询,要求将来自 32 个源端 MySQL 实例的 1024 张分表数据实时同步至一个汇聚实例,实现统一查询。该汇聚实例需保留 1 个月数据(总量约 10 TB),同步峰值 TPS 达 30 万,且流量均为与订单相关的事务性 DML 操作,包含高频的 INSERT、UPDATE 和 DELETE。
数据汇聚场景通常需要对多张分表进行联合分析,因此需通过数据同步将多个实例的数据汇聚到单一目标实例。此类任务通常由分析型数据库或分布式数据库承担,而我们采用单个 DuckDB 主实例 成功满足了客户需求,主要依赖以下能力:
多源多表汇聚能力:我们扩展了 MySQL Binlog 多源复制功能,支持配置表级路由映射规则,可将多个源端分表的 Binlog 流统一写入 DuckDB 的单张目标表。为此需对表结构进行适配调整。例如,源端 MySQL 表以自增 ID 为主键,而在 DuckDB 中改用业务订单号作为主键,以避免不同源实例自增 ID 冲突。
跨事务 DML 批量优化:DuckDB 通过将 Binlog 中多个事务的 DML 操作进行合并,实现“攒批写入”,即将多次小操作转化为对引擎的一次批量提交。系统支持通过参数灵活配置攒批时间窗口、事务批次大小及低流量下的合并策略,在保障低延迟的同时显著提升同步吞吐。
DuckDB 主实例的汇聚方案成功满足了客户的多源同步需求,不仅节省了原本需部署的 32 条独立同步链路的成本,还平稳支撑了客户元旦跨年期间的业务流量洪峰。 所有分析查询均在 DuckDB 主实例上高效完成,绝大多数 SQL 查询耗时低于 1 秒;涉及多表 JOIN、JSON 函数等复杂操作的查询,相比在原 MySQL 分表上执行的等效查询,性能提升尤为明显。 此外,得益于列式存储的优势,DuckDB 的存储空间占用大幅降低。经实测,在相同数据量下,DuckDB 的磁盘占用约为 InnoDB 的 1/4。
Not Just a MySQL Storage Engine
DuckDB 主实例形态极大地扩展了使用场景,理论上所有可以使用 MySQL 的地方都可以使用 DuckDB 主实例支持。 更进一步地,DuckDB 不仅仅是 MySQL 内的一个存储引擎,同时也为 MySQL 提供了一个开放的窗口,成为连接 MySQL 与开放数据生态的桥梁。
其中,数据湖集成是我们后续的重要演进方向。通过集成 DuckDB 原生支持的 Iceberg 等插件,MySQL 可与数据湖无缝打通:应用仍通过标准 MySQL 接口写入数据,而底层数据可自动落盘至 S3 上的 Iceberg 表中。对业务方而言,写入方式完全不变;对数据平台而言,数据已天然以标准 Iceberg 格式存在于数据湖中。 同时,业务还可通过 MySQL 的 SQL 语法直接查询 Iceberg 等数据湖中的表,实现“一套接口,双模访问”的统一体验。
来源 | 阿里云开发者公众号
作者 | 思勉 缘琪