问题现象
SQL 执行报错 internal error code, arguments: -4002, Invalid argument。

通过 trace-id 与 4002 报错过滤相应节点的 observer.log,可以看到 dir_id= 为负值,如dir_id=-2102698303。
WARN [SQL.DTL] get_interm_result_info (ob_dtl_interm_result_manager.cpp:158) [52090][2114][xxxxx-xxxxx] [lt=9] [dc=0] fail to get row store in result manager(ret=-4201, key.channel_id_=1772803030034689)
WARN [STORAGE] init (ob_tmp_file.cpp:433) [52248][2400][xxxxx-xxxxx] [lt=10] [dc=0] invalid argument(ret=-4002, fd=414577, dir_id=-2102698303)
关键诊断信息
触发条件
OBServer 持续运行,间断性持续产生临时文件,直至单调递增的临时文件 id > int32 类型上限。
事后诊断
通过 trace-id 与 4002 报错过滤相应节点的 observer.log,可以看到 dir_id= 为负值,如dir_id=-2102698303。
WARN [SQL.DTL] get_interm_result_info (ob_dtl_interm_result_manager.cpp:158) [52090][2114][xxxxx-xxxxx] [lt=9] [dc=0] fail to get row store in result manager(ret=-4201, key.channel_id_=1772803030034689)
WARN [STORAGE] init (ob_tmp_file.cpp:433) [52248][2400][xxxxx-xxxxx] [lt=10] [dc=0] invalid argument(ret=-4002, fd=414577, dir_id=-2102698303)
问题原因
在查询操作执行过程中,数据库会产生大量临时的数据,由于受到系统内存大小的限制,这些数据需要以文件形式临时存储到外部设备中。dir_id 由临时文件分配并设置到 chunk store 上面且不会修改的,分配逻辑从 0 开始依次递增,预期不会出现负值。由于一个代码的 BUG,导致临时文件 id int32 溢出。对于持续运行较长时间的集群,业务数据量大,触发落盘累积到了一定阶段,最终导致SQL执行报错 4002。dir_id 本身是 OBServer 节点级别的,意味着一旦这个节点出现了该问题 (tmp file dir_id 为负),那么后续有落盘场景的 SQL 都会持续报错 4002。
问题的风险及影响
SQL 报错 -4002。
影响租户
影响 OceanBase 数据库中的 Oracle 租户和 MySQL 租户,对于 SYS 租户无影响。
影响的版本
OceanBase 数据库企业版 V3.1.2 GA(oceanbase-3.1.2-20210618150922)及之后版本、V3.2.3 GA(oceanbase-3.2.3.0-20220418212020)及之后版本、V3.2.2 GA(oceanbase-3.2.2-20211130225726)及之后版本。
解决方法
升级至问题已修复最新版本,目前已修复版本为 OceanBase 数据库企业版 V3.1.2 BP8 Hotfix7 (oceanbase-3.1.2-20220712165759)、V3.1.2 BP8 Hotfix8(oceanbase-3.1.2-108080032024122610)、V3.1.2 BP8 Hotfix9(oceanbase-3.1.2-108090022025021811)、V3.1.2 BP9(oceanbase-3.1.2-20220727191622)、V3.2.2 Hotfix11(oceanbase-3.2.2-20220610224123)、V3.2.2 Hotfix12(oceanbase-3.2.2-20220713204333)、V3.2.2 Hotfix13(oceanbase-3.2.2-20220804203507)、V3.2.2 BP1(oceanbase-3.2.2-20211215001504)、V3.2.3 BP2 (oceanbase-3.2.3.0-20220530152606)。
该节点一旦已经遇到了 dir_id 为负导致 4002 的问题,就需要重启该节点来解决问题。否则后续落盘的 SQL 也会报错 4002。最终需要升级到修复版本来最终解决问题。
规避方式
短期规避方法。
运行中的系统可以通过调整 SQL 降低落盘的情况来降低触发该问题的概率或者延缓问题出现的时点,如果是跑批类似的的场景时,可以通过调低并发度,降低一部分算子中间结果的落盘数据量来解决问题。在调整 SQL 后可以通过对
gv$sql_workarea_active的观察和诊断协助观察调整 SQL 后对落盘大小的需求,需要关注的字段是tempseg_size。响应的 SQL 如下。select POLICY,operation_type, operation_id, active_time, work_area_size, expect_size, actual_mem_used, tempseg_size from gv$sql_workarea_active;监控方式。
对于受影响的版本,运行一段时间后需要对于正在运行的 OBServer,可以观测日志中来自
ob_chunk_datum_store.cpp打印的open file success INFO级别日志, 如果 dir_id 接近int32 max (2147483647),那么下一次有落盘场景的 SQL 遇到 4002 的时间点就更加接近了。-- 相关的日志打印代码逻辑 LOG_INFO("open file success", K_(io_.fd), K_(io_.dir_id));