在数据分析场景中,数据结构的动态调整是常态。Apache Doris作为高性能MPP数据库,其灵活的Schema设计支持业务快速迭代,但Schema变更若处理不当,可能导致数据不一致、查询性能下降甚至服务中断。本文深入解析Doris Schema变更机制,并结合实战经验总结关键最佳实践。
无锁化 Schema 变更机制
Doris采用独特的无锁化Schema变更机制,通过版本控制实现多版本元数据管理。当执行Schema变更时,系统会生成新的元数据版本,同时保留旧版本Schema的访问能力。这种设计实现了以下的优势:
- 零阻塞读写:在线业务不受 DDL 操作影响;
- 原子性切换:版本切换瞬间完成,避免中间状态;
- 多版本共存:新旧版本数据并行存在直至完全切换。
Schema 变更原理实现
Doris 支持轻量级和重量级两种类型的 Schema 变更操作,区别主要体现在执行过程的复杂性、执行速度和资源消耗上。
特性 | 轻量级 Schema Change | 重量级 Schema Change |
---|---|---|
执行速度 | 秒级(几乎实时) | 分钟级、小时级、天级(依赖表的数据量,数据量越大,执行越慢) |
是否需要数据重写 | 不需要 | 需要,涉及数据文件的重写 |
系统性能影响 | 影响较小 | 可能影响系统性能,尤其是在数据转换过程中 |
资源消耗 | 较低 | 较高,会占用计算资源重新组织数据,过程中涉及到的表的数据占用的存储空间翻倍。 |
操作类型 | 增加、删除 Value 列,修改列名,修改 VARCHAR 长度 | 修改列的数据类型、更改主键、修改列的顺序等 |
轻量级 Schema 变更
轻量级 Schema 变更不涉及数据重写的,这些操作通常在元数据级别进行,仅需要修改表的元数据,而不涉及数据文件的物理修改。轻量级 Schema 变更 操作通常能够在秒级别完成,不会对系统性能造成显著影响。轻量级 Schema 变更包括:增加或删除普通列、更改列名及修改 Varchar 列的长度等操作。
重量级 Schema 变更
重量级 Schema 变更涉及到数据文件的重写或转换,这些操作通常会涉及到对表数据结构的深度变更,可能会影响到存储的物理布局,通常需要借助 Doris 的 Backend 进行数据的实际修改或重新组织。典型的重量级 Schema 变更包括:更改列的数据类型和修改列的排序顺序等。
重量级操作会在后台启动一个任务进行数据转换。后台任务会对表的每个 tablet 进行转换,按 tablet 为单位,将原始数据重写到新的数据文件中。数据转换过程中,可能会出现数据"双写"现象,即在转换期间,新数据同时写入新 tablet 旧 tablet 中。完成数据转换后,旧 tablet 会被删除,新 tablet 将取而代之。
Schema 变更风险与应对
虽然 Doris 提供了灵活的 Schema 变更策略,但实际操作中如处理不当,也可能会引发风险。
隐式数据类型转换导致变更失败
将 varchar 字段改成 int 类型时,如果存在非数值数据(如空字符串或字母),转换会失败,导致数据丢失或表被长时间锁定。建议变更前先检查确认是否存在类似的数据,提前进行相应的数据转换和清洗。
下游应用兼容性故障
BI 工具、ETL 脚本等依赖原 Schema 字段,变更后导致查询报错或数据解析失败;修改聚合键或排序键后,关联的物化视图也需要重建,否则会导致统计结果失真。
性能下降资源消耗增加
修改排序键后,全量数据重写会占用大量临时存储,导致 BE 节点磁盘 I/O 或内存超限,甚至引发节点 OOM,此外还可能会由于索引失效导致查询延时上升。建议在变更前备份元数据,避免回退过程需要重建表结构重新导数据。
写在最后
虽然 Oracle 也有不少场景支持轻量级的 Schema 变更,但是似乎并没有整理出类似的概念。Doris 等新型数据库将这些场景独立出来,并大大扩展了其支持场景。一方面是 Oracle 数据库在设计上比较严谨,严格遵守 ACID 原则,不允许中间状态出现;另一方面也和 Doris 所管理的数据体量和应用场景有关,毕竟要修改动辄上 TB 规模的表结构,还是一件毕竟危险的动作,需要数据库提供相应的能力来尽可能的规避风险。