首批通过分布式安全可靠测评,为关键业务系统打造
OBKV 使用带 CURRENT_STRAMP 属性的列作为 TTL 过期列导致节点宕机
更新时间:2026-06-04 09:56
问题现象
表定义要求:表定义中 TTL 过期列带有
current_timestamp属性。例如下面的表定义中 c3 列带有
current_timestamp列定义属性,并且作为了 TTL 过期列(TTL(c3 + INTERVAL 2 second))。create table if not exists test_ttl( c1 int(12) primary key, c2 int(12), c3 timestamp default current_timestamp, TTL(c3 + INTERVAL 2 second);
操作:使用 OBKV 客户端的
client.InsertOrUpdate接口进行数据更新。例子中,第一次 InsertOrUpdate 执行的是写入操作,不会触发 core dump。
例子中,第二次 InsertOrUpdate 执行的是更新操作,在更新操作中会检查旧行是否过期,检查过期过程中触发 core dump。
// 1. 第一次数据库中没有数据,InsertOrUpdate 执行的是插入操作 rowKey := []*table.Column{table.NewColumn("c1", int32(0))} mutateColumns := []*table.Column{table.NewColumn("c2", int32(0))} affectRows, err := cli.InsertOrUpdate( context.TODO(), tableName, rowKey, mutateColumns, ) assert.Equal(t, nil, err) assert.EqualValues(t, 1, affectRows) // 2. 第二次数据库中已经有相同 rowkey,InsertOrUpdate 执行的是更新操作操作 ctx, _ := context.WithTimeout(context.Background(), 1000*time.Second) // 10s rowKey = []*table.Column{table.NewColumn("c1", int32(0))} mutateColumns = []*table.Column{table.NewColumn("c2", int32(1))} affectRows, err = cli.InsertOrUpdate( ctx, tableName, rowKey, mutateColumns, ) assert.Equal(t, nil, err) assert.EqualValues(t, 1, affectRows)
表现:节点宕机,业务中断,业务端访问数据库超时。
关键诊断信息
触发条件
表定义中 TTL 过期列带有 current_timestamp 属性,使用 OBKV 客户端的 client.InsertOrUpdate 接口进行数据更新。
问题原因
直接原因:server 访问非法内存,导致节点宕机。
根本原因:在 TTL 算子中,检查过期时,由于时间列旧值没有正确刷到对应的表达式上,导致访问表达式的 datum 时 core dump。 以下面的表模型为例,执行 InsertOrUpdate。
create table if not exists test_ttl( c1 int(12) primary key, c2 int(12), c3 timestamp default current_timestamp, TTL(c3 + INTERVAL 2 second);
服务端生成的表达式
c1 c2 都是普通的列引用表达式
col_ref_expr。c3 是计算表达式 now() 表达式,计算结果需要做列转换,所以最上层是列转换表达式。
还有一个过期表达式,过期表达式是
(c3 + INTERVAL 2 second) < now(),是一个小于表达式。左表达式的定义是
c3 + INTERVAL 2 second,是一个加法表达式,加法结果需要转换为datatime,所以还有一个列转换表达式。c3 对应的是上面图中标黄的列转换表达式。
在 TTL 算子执行写入后,发现冲突后会进行过期检查,检查旧行是否过期,过期则删掉旧行,写入新行。
a. 扫描存储旧行,填充到 old row 中,也就是填充到
c1:col_ref_expr c2:col_ref_expr c3:col_conv_expr中。b. 过期表达式进行计算 eval,即执行小于表达式,获取小于表达式结果
get_bool(),true则过期,否则不过期。问题的原因是在刷旧值的时候,并没有刷到
c3:col_conv_expr中,而是刷到了c3:col_conv_expr下面的col_ref_expr,导致col_conv_expr是空的。
问题的风险及影响
节点会频繁宕机,业务中断。
影响租户
影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。
影响版本
OceanBase 数据库 V4.2.1 GA(oceanbase-4.2.1.0-100000182023092722)及之后版本。
解决方法
升级到问题已修复版本,目前已修复的版本包含 OceanBase 数据库 V4.2.1 BP1(oceanbase-4.2.1.1-101000062023103122) 及之后版本。
如果问题已经发生,可以执行如下命令把 TTL 定义删除进行恢复。
-- 删除 DDL 定义 SQL 语法 obclient> ALTER TABLE $table_name REMOVE TTL;
规避方式
不要将带有 current_timestamp 列定义属性的列作为 TTL 过期列。