本文作者:任仲禹,爱可生数据库高级工程师,擅长故障分析和性能优化。
本文将分享一例案例,介绍OMS 关联 OCP时, 报 服务器内部错误 时的诊断过程与思路。
背景信息
涉及的软件版本如下:
- OMS 402bp2
- OCP 410
该案例属于实际客户场景触发报错,故障时 OMS 能够正常访问到 OCP ,但是 OMS 白屏界面操作 添加关联 OCP 该步骤时将报错 服务器内部错误 ,如下图所示。
问题诊断
1. 日志分析
由于 OMS 白屏界面除 服务器内部错误 外无其它报错信息帮助诊断问题,所以第一时间准备登到 OMS 容器上查看 OMS-Console 组件日志。
题外话,OMS 界面相关的例如显示问题、点击按钮报错等首选查看 Console 组件日志
- OMS 容器内日志路径:/home/admin/logs/ghana/Ghana/comon-error.log
- 过滤 ERROR 关键字
收集到的有效信息是 SQL 执行报错 “插入的数据没有指定 ocp_proxy_host
列或者该字段没有默认值”。
### The error occurred while setting parameters
### SQL: INSERT INTO ocp_info ( id, ocp_domain, ocp_api_user, ocp_api_password, ocp_charset, ocp_version, region, ocp_name) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
### Cause: java.sql.SQLTransientConnectionException: (conn=783124) Field 'ocp_proxy_host' doesn't hava d default value;
2.元数据库排查
继续沿着上文线索进入 OMS 的 metadb 元数据库中,查询 oms_rm 库下的 ocp_info
表结构,如下图所示。
目前可知 OMS 关联 OCP 时需要向表 ocp_info
中插入一条数据,如果 SQL 执行报错或其它原因就导致了页面触发 服务器内部错误:
- 插入的语句:
INSERT INTO ocp_info ( id, ocp_domain, ocp_api_user, ocp_api_password, ocp_charset, ocp_version, region, ocp_name) VALUES ...
- SQL 执行报错
"Field 'ocp_proxy_host' doesn't have a default value."
的原因是表结构ocp_info
中字段ocp_proxy_host
属性是 NOT NULL,并且没有 default 值。 - 这里的疑问:OMS 为啥下发一条“注定”会执行报错的 SQL ? 难道是 BUG?
排查到这里,咨询 OB 产研得到的反馈是这个 ocp_info
表的 ocp_proxy_host、ocp_proxy_port、ocp_meta_user、ocp_meta_password、ocp_meta_db 字段已经在 OMS 402 版本中被去除了,所以还得继续分析为啥 ocp_info
的表结构不符合预期。
是否是部署的 OMS 402 版本读取了老版本的 metadb 库?
3.OAT 部署排查
沿着安装部署溯源,通过 OAT 排查到该 OMS 是 7月1日 15:39 部署的,如下图。
比对 OMS metadb 中 ocp_info
表的创建日期和该 OMS 集群的部署日期。
查询 oceanbase.__all_virtual_table 表,关注 gmt_create 和 gmt_modified 字段。
发现 ocp_info
表创建更晚于 OMS 创建,所以先排除读取到了老版本的 metadb 库。
继续分析 OAT 的部署流程,在 start_first_batch_oms_container 步骤中发现了 ERROR 信息,如下图。
OAT 部署任务中,start_first_batch_oms_container 步骤记录了 OMS metadb 相关的 DDL init 脚本导入记录。
上图中的报错结合 OMS 容器中( /root/omsflow/meta_init/drc_rm_schema.sql )文件发现 ocp_info
表对应字段的 DROP 操作在 OAT 中显示全部执行失败。
这里的 2 个问题点:
- 问题 1:为啥
ALTER TABLE ocp_info DROP COLUMN ...
执行失败? - 问题 2:SQL 执行失败为啥 OMS 初始化元数据成功,OAT 没有报错?
问题 1
通过排查,DROP Column 失败是因为 DDL 执行的时间点,OMS 所在 metadb Cluster 处于运维状态 (其中一个 OBServer 宕机),导致 DROP Column 的DDL 无法执行,这个不太重要,关键在于 问题 2 OAT 未抛出报错。
问题 2
OAT 中初始化 DDL 调用的 SQL 执行失败了按理应该抛出报错,需要人工介入才是,为啥 OAT 还显示 start_first_batch_oms_container 步骤正常完成呢,这点比较重要得继续排查。
逐个翻阅 start_first_batch_oms_container 任务的调用步骤,发现问题大概出在这一步:
[2023-07-01T15:49:20.785+0800] INFO - mysql -h 'xxxxx' -P2883 -u 'root@oms_meta#xxxxxx' --password='xxxxxx' -f -D 'oms_rm' < /root/omsflow/meta_init/drc_rm_schema.sql "
- 上文将 DDL init 脚本(drc_rm_schema.sql )导入 OMS 元数据库时,加了 " -f " ,该参数是 mysql 客户端忽略报错的行为。
- 问题 3: 为啥加了 " -f " 参数会有问题?
问题 3
首先,OAT 只能判断 DDL init 脚本的执行结果,OAT start_first_batch_oms_container 任务中展示的实际是容器里的DDL init 脚本执行的输出 (例如 SQL 的执行是否报错)。
然而,当指定了 " -f " 参数时,将忽略 init 脚本中的 SQL 执行报错。
所以,OAT 获取到 init 脚本执行的报错码是 0,OAT 判断任务正常完成。
# 示例
[root@10-186-58-75 ~]# cat 1.sql
select 11 from bbbb;
select 13,a from renzy.t;
[root@10-186-58-75 ~]# mysql -h10.186.58.75 -P8001 -uroot -proot -f < 1.sql
ERROR 1046 (3D000) at line 1: No database selected
ERROR 1049 (42000) at line 4: Unknown database 'renzy'
[root@10-186-58-75 ~]# echo $?
0
临时修复
进入 OMS 容器,按 OMS 容器初始化脚本提示(下图所示),单独重新执行【步骤二】OMS 元信息库初始化步骤即可(该步骤幂等性,可反复执行)。
python -m omsflow.scripts.units,oms_init_manager --init-db
结论
- 本次案例 OMS 无法关联 OCP (报“服务器内部错误”)是由于要往 OMS 的 metadb 中注册一条信息(insert SQL),而这条 SQL 因为 metadb 中表结构不正确导致执行失败。
- 表结构不正确是由于 OAT 安装 OMS 时调用了 oms_init metadb 脚本, oms_init 脚本中导入 SQL 时忽略了报错,导致元数据库表结构和预期不符。
- 第 2 条结论笔者已提 OB 官方,产研已确认为缺陷,并反馈将修复在 OMS 421 版本。