首批通过分布式安全可靠测评,为关键业务系统打造
列间编码数据溢出导致访问编码数据时 OBServer crash
更新时间:2026-06-04 09:56
问题现象
当一张表中有两列数据类型属于同一个大类型(如 varchar / tinytext 类型),且大部分数据基本相同、仅少量数据不同的列时,如果某一列上这两列之间不相同的数据长度的和超过 64KB,那么在集群合并时就可能导致 OBServer core。如果该环境关闭了微块校验配置项(micro_block_merge_verify_level = 0),甚至会导致数据正确性问题。
说明
有关 micro_block_merge_verify_level 的详细介绍,请参见:micro_block_merge_verify_level。
底层触发的条件为当一张表中两列 varchar / tinytext 类型数据基本相同,少量数据不同,但不同的数据长度的和大于 64KB,且合并时编码选择算法选择了列间等值编码对这两列进行压缩时,会导致上述现象。
关键诊断信息
触发条件
一张表中有两列数据类型属于同一个大类型(如varchar / tinytext类型),且大部分数据基本相同、仅少量数据不同的列,某一列上这两列之间不相同的数据长度的和超过 64kB, 集群合并。
问题原因
表上有两列数据类型属于同一个大类型,且数据基本相同,集群合并时相关数据编码可能会采用列间等值编码算法。列间等值编码处理两列不相同的值存储时,需要一个数组存储每一行不相同数据的 offset。offset 会根据最大 offset 长度 pack 到对应的字节,代码上只 pack 到了 1,2 字节,也就是最长只能支持长度为 65535(64KB)的 offset。
OceanBase 数据库 4.0 版本后 encoding meta 的长度放开到了和微块大小限制相同,因此在列间等值编码不相同数据的长度超过 64KB 时,offset 数组会发生溢出,导致读数据异常。
问题的风险及影响
影响:这个问题出现的概率相对较低,但一旦被触发就会导致进程 crash。
如果开启了微块校验配置项 (
micro_block_merge_verify_level > 0默认为 2)。- 会导致合并时 OBServer crash。需要已修复版本的 OBServer 替换 binary 恢复集群服务,错误数据不会落盘。
如果关闭微块校验配置项 (
micro_block_merge_verify_level = 0)。- 正确性问题。会导致合并结束后,下次查询/合并时 OBServer crash,错误数据被落盘。通过特殊的方法可以人工找回数据。
影响租户
影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。
影响版本
OceanBase 数据库企业版 V4.1.0 GA(oceanbase-4.1.0.0-100001122023040322)及之后版本。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V4.1.0 BP2(oceanbase-4.1.0.1-102000042023061309)及之后版本。
如果开启了微块校验配置项,可以使用带有这个问题的修复代码,且与当前 OBServer 版本数据兼容的 observer binary 直接拉起集群,然后对集群做升级到没有该问题的版本。
如果关闭了微块校验配置项,需要联系 OceanBase 技术支持使用临时 binary,拉起集群后做全量合并,检查这个问题在哪些表上出现,再根据是否需要保留数据做删表/人工数据恢复处理。
规避方式
开启微块校验配置项 (降低问题影响)。
关闭列间编码,使用
flat微块格式或condensed微块格式(防止问题发生)。注意
由于目前不能只关闭列间编码,只能关闭
encoding功能,因此关闭后会有存储空间放大的问题(放大程度与数据有关,平均估计 30% 以上)。可以通过调整表级压缩选项 row_format 实现,具体操作请参见:表压缩。调小微块大小表级配置项
BLOCK_SIZE,schema 上避免两个相同的 varchar 列(降低问题发生概率),具体操作如下。obclient> ALTER TABLE tbl1 SET BLOCK_SIZE = 1025; Query OK, 0 rows affected (0.107 sec)说明
BLOCK_SIZE块大小应介于 1024 字节和 1048576 字节之间。