尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

OceanBase集群状态running但组件not running?OBD状态不一致排查指南

OceanBase集群状态running但组件not running?OBD状态不一致排查指南 很多人第一次看到obd cluster display输出里的running和oceanbase-ce is not running同时出现时基本都会愣一下集群状态明明还挂着 running怎么核心组件反而变成 not running 了这到底是算好还是算坏该从哪儿下手排查我一开始也在这个组合拳上栽过跟头而且不止一次。后来把 OceanBase 4.x 的部署、启动和状态判断逻辑摸了一遍才发现这个“矛盾状态”背后其实是一套很清晰的因果关系。这篇文章就把我自己的排查链路、踩过的坑和最终的修复套路完整写出来给遇到同样问题的朋友一个可以直接照着操作的参考。1. 状态running和“oceanbase-ce is not running”为什么能同时出现1.1 OBD到底是怎么判断组件状态的在 OceanBase 4.x 的部署体系里OBDOceanBase Deployer是我们最常用的部署和管理工具。obd cluster display输出的状态其实来自多级判断不是一个单一的“集群好着没”的信号。OBD 对集群状态的汇总逻辑简单说就是只要集群里还有组件处于运行中集群层面的状态就可能继续显示为running。但单独看某个组件时它会基于进程和端口探测来判断这个组件当前是否真正存活。也就是说集群状态 running 和组件状态 not running描述的是两个不同粒度的东西。当一个集群里既有 obproxy 又有 observer也就是 oceanbase-ce 组件时如果 obproxy 还在正常跑而 observer 已经挂掉那么集群整体往往还是显示 running但组件列表里 oceanbase-ce 那一行就会明晃晃地写着is not running。还有一个容易被忽略的点OBD 判断 observer 是否存活并不是单纯看进程在不在还会看端口是否监听成功。Observer 启动是一个相对慢的过程它要先做初始化、加载配置、申请内存、启动内部线程组最后才会监听 2881 和 2882 端口。在这个过程中进程可能已经 fork 出来了但端口还没起来如果这时候刷新状态OBD 会认为组件 not running。这也就是为什么很多人刚执行完obd cluster start后立刻obd cluster display会看到短暂的不一致状态。1.2 最容易复现的两个部署场景从我自己的实践来看这个现象主要集中在两种部署方式下。第一种是 OBD 本地部署也就是非容器方式。最常见的过程是集群跑着跑着服务器内存被占满内核 OOM 直接把 observer 进程杀了或者 observer 因为某个初始化步骤失败自行退出。这时候 obproxy 可能还活着所以obd cluster display的整体状态依然显示 running但 oceanbase-ce 组件已经凉透。第二种是 Docker 部署。很多朋友图省事直接用oceanbase-ce镜像起容器然后用docker ps一看容器状态显示 Up就以为数据库没问题。但容器是 Up 不代表容器里的 observer 进程就是健康的。部分镜像启动时靠一个 supervisord 或启动脚本托底即使 observer 崩溃容器主进程也不会退出于是容器状态依然是 running而真正干活的数据库进程早就没了。这时候进去看ps -ef | grep observer什么都搜不到。还有一个相对隐蔽的场景机器重启后OBD 记录的元数据和实际进程状态不一致。比如服务器异常断电之前启动的 observer 进程全部消失但 OBD 的一些状态记录还停留在 running等你再次执行obd cluster display时它重新探测进程发现 observer 的 PID 已经不存在了就会报出oceanbase-ce is not running。明白了状态不一致是怎么来的下一步就不是盯着 display 输出干瞪眼而是直接去核实真实运行状态。2. 排查第一步先别急着折腾配置把observer进程和端口看明白2.1 用ps和ss还原真实运行状态遇到这种状态报错我的习惯是先用三分钟把“现场”固定下来不要一上来就改配置或者重启。所谓现场就是进程、端口、日志三个维度的快照。先看进程还在不在ps -ef | grep observer | grep -v grep如果输出里能看到类似observer -o ...的进程行说明 observer 至少被拉起过。如果什么都搜不到那基本可以断定数据库主进程已经退出问题不是“没起来”而是“起来后死掉了”。再看端口有没有监听ss -lntp | grep -E 2881|28822881 是 SQL 服务端口客户端连接数据库走的是这个2882 是 observer 内部 RPC 通信端口。如果 2881 没有监听哪怕进程还在数据库对外也是不可用的OBD 判断 not running 也不冤。还有一种很特殊的情况进程在端口也在但数据库就是连不上。这时候要检查进程状态是不是僵尸态cat /proc/pid/status | grep State如果状态是Z (zombie)说明 observer 进程已经终止只是父进程还没回收它的 PID 信息。出现这种情况OBD 靠进程 PID 判断存活时可能误判但业务侧连接一定失败。看到僵尸态基本可以放弃对这个进程的指望直接进入清理和重启流程。2.2 区分“集群跑着但组件起不来”和“组件起过但已经崩了”同样是 not running背后对应的处理思路完全不同。如果 observer 进程压根没出现过那大概率是启动阶段就失败了比如配置不对、端口被占、磁盘空间不够、目录权限不对或者内存参数配置到天上去了进程一启动就被系统拒绝。这种情况的重心在于看启动日志找到第一个报错点。如果 observer 进程出现过但现在已经消失那重心就要放在“为什么中途死掉”上。最典型的就是被 OOM Killer 干掉尤其是单机部署 OceanBase 4.x 时memory_limit配得比物理内存还大或者 system_memory 留得太小都很容易触发。这两种情况虽然表现都是 not running但排查方向完全相反。前者看的是“为什么起不来”后者看的是“为什么被杀”。确定方向后下一步自然就是翻日志。3. 顺着observer日志往回追根因通常写在日志里3.1 observer.log在哪里怎么看OceanBase 的 observer 进程日志路径一般在部署目录下的log子目录里。OBD 默认部署环境下常见路径是~/oceanbase/log/observer.log如果你不确定部署目录在哪里可以通过 OBD 查看obd cluster list obd cluster display deploy_namedisplay 输出里能看到部署的 home_path日志就在home_path/log/observer.log下。查看日志时习惯先看结尾部分tail -n 200 ~/oceanbase/log/observer.log重点关注几类关键字关键字含义ERROR明确的错误信息基本可以定位到失败模块FATAL致命错误进程通常活不下来failed to bind端口绑定失败No space left磁盘空间不足Permission denied目录或文件权限问题ret-4016等错误码对应具体 OB 内部错误码需要进一步查手册out of memory内存不足observer.log 是滚动写入的文件往往很大直接grep ERROR可能刷出几百行。我一般会先看最后 200 行因为一个进程崩溃前写的日志往往就在尾部。3.2 OBD常规部署里最容易触发的几个启动失败点以 OBD 部署 OceanBase 4.x 为例启动失败有几个高频原因基本每次都能在日志里找到对应痕迹。第一个是devname配置不对。Observer 启动时需要指定一个网卡设备名用来绑定内部通信地址。如果配置里写的devname: eth0但机器上实际叫ens33observer 会直接初始化失败。看日志会发现网络相关的 ERROR。检查网卡名可以用ip addr第二个是内存参数不合理。OceanBase 4.x 启动流程中会做内存预检和预分配memory_limit如果超过物理内存或者system_memory设置得过小都会导致启动失败。日志里常见到 memory 相关的报错。特别是有些朋友用虚拟机测试物理内存只有 4G却照着默认配置把memory_limit拉到 8Gobserver 必挂无疑。第三个是数据目录残留。如果之前已经在这个目录初始化过一套集群数据再次启动时 observer 不会重新 bootstrap而是尝试去加载已有数据。如果数据目录里的集群元数据和当前配置对不上也会卡住或者报错。日志里会出现类似 store 初始化失败的记录。第四个是 ulimits 限制。Observer 启动后会开大量线程和文件句柄如果系统的nofile、nproc限制太低进程虽然能起来但运行一段时间后因为资源耗尽而退出。日志里有时能看到Resource temporarily unavailable。3.3 docker部署怎么看容器日志如果你是容器方式部署排查路径稍微有点不同。先定位容器docker ps -a | grep oceanbase docker logs --tail 200 container_iddocker logs能看到容器内启动脚本的输出。如果脚本里把 observer 的 stdout 重定向到了日志文件容器日志里可能看不到太多有效信息那就得进容器里看docker exec -it container_id bash ps -ef | grep observer ls /root/oceanbase/log/ tail -n 200 /root/oceanbase/log/observer.log这里我要多说一句Docker 部署时很多人只盯着docker ps的 STATUS 列看到 Up 就认为服务正常。但容器生命周期和数据库进程生命周期是两回事数据库探活永远要以端口和实际连接结果为准。4. 内存、磁盘、端口三类高频因素逐一验证并修复4.1 内存不足OOM Kill是最隐蔽的杀手在排查过的案例里内存不足导致的被动态地 kill 掉占比最高而且最隐蔽。obproxy 和 observer 同时跑在一台小内存机器上时observer 作为内存大户很容易成为 OOM Killer 的目标。检查系统日志dmesg -T | grep -i -E killed process|out of memory | tail -n 20或者journalctl -k | grep -i oom | tail -n 20如果看到类似Out of memory: Killed process 1234 (observer)的输出基本锤实是内存不足。这种情况要做的不是简单重启而是先调整内存配置。查看机器物理内存free -h然后修改 OBD 集群配置里的memory_limitobd cluster edit-config deploy_name把memory_limit改到一个物理内存能够承受的值。比如机器只有 8G 内存observer 的memory_limit建议压到 4G-6G 左右system_memory也要留出合理空间防止 observer 运行后把内存吃光。4.2 磁盘空间和目录权限启动失败里被小看的坑磁盘满导致 observer 启动失败的案例也不少。observer 启动时要写日志、写数据文件如果所在分区没空间了进程会在初始化阶段直接失败。检查方式很直接df -h重点关注数据目录所在分区的使用率尤其要留意/home、/data这类常见部署目录。日志目录和 store 目录如果分离部署还要分别确认两个分区都有空间。目录权限问题通常出现在手动修改过部署目录归属的场景。OBD 默认以当前用户身份部署observer 也以该用户运行。如果 store 或 log 目录被chown成了别的用户observer 启动时无法写入也会失败。修复方式就是确认部署用户和目录属主一致chown -R user:group home_path另外要提醒一句如果你是因为数据目录残留导致启动失败不要第一时间就删 store 目录。store 里是真实数据删了就没了。正确做法是先确认这是测试环境或者已经做过备份再决定是否清理。4.3 端口占用和绑定失败端口被占用是本地部署里最常见的“低级坑”。有时候是上一次没完全停干净有时候是同一个机器上跑了好几个实例。检查ss -lntp | grep -E 2881|2882如果端口被占用看到 PID 后先确认是不是残留的 observer 进程是的话就 kill 掉。如果是不相关服务占用可以修改 OceanBase 的 SQL 端口和 RPC 端口但改端口会涉及客户端连接串、obproxy 配置等多个方面成本较高所以更推荐把占用端口的无关服务挪走。同样值得检查的还有devname对应的网卡 IP 是否和配置匹配。OceanBase 4.x 对网络环境比较敏感一个错误的主机名解析或网卡名足以让 observer 在启动阶段就放弃治疗。5. 从“not running”恢复到running的完整操作顺序5.1 清理状态和残留确认根因后进入恢复阶段。恢复前先做一次干净的停止避免残留进程干扰后续启动obd cluster stop deploy_name如果 OBD 因为状态混乱执行 stop 失败可以手动把残留 observer 进程清掉ps -ef | grep observer | grep -v grep | awk {print $2} | xargs -r kill -9这里要注意如果服务器上同时跑着多套 OceanBase 实例按进程名批量 kill 会误伤需要先根据命令行参数确认实例归属再按 PID 精确清理。如果确认是数据目录残留导致启动失败而且数据不需要保留再考虑清理 store 目录。稳妥起见先把目录改名而不是直接删除mv ~/oceanbase/store ~/oceanbase/store.bak.$(date %Y%m%d)这样即使判断失误还能把数据找回来。5.2 修正配置后重新启动并验证配置改动通过 edit-config 完成obd cluster edit-config deploy_name修改完保存后OBD 会提示需要重启集群使配置生效。执行启动obd cluster start deploy_name启动过程中 OBD 会等待 observer 端口起来。如果启动卡住把 OBD 日志打开对照看tail -f ~/.obd/log/obd.log启动完成后不要只盯 display 的状态直接验证真实连通性obd cluster display deploy_name mysql -h127.0.0.1 -P2881 -uroot -p能连上而且能正常执行select 1;才算是真正恢复了。建议等待一两分钟再看一次 display因为 observer 启动后还需要完成内部初始化有些时候端口已经能连但组件状态要过一会儿才切到 running。6. 说点实际的平时怎么避免再被这个状态坑6.1 部署前就把这几项钉死经验积累到后面我越来越觉得与其每次出问题再排错不如部署阶段就把隐患抹掉。内存评估要提前做。OceanBase 4.x 单机部署建议物理内存不低于 8Gobserver 的memory_limit不要超过物理内存的 70%同时system_memory要留足一般建议 1G-2G 空余具体按集群规模来。如果机器配置比较低宁可让 observer 小跑也别把参数拉满然后被 OOM 教做人。网卡devname必须核对。部署前执行ip addr确认网卡名写到配置里不要照搬别人的模板。很多部署文档写 eth0但云服务器上通常叫 eth0 也有叫 ens3、ens5 的写错直接起不来。系统资源限制要提前调。ulimit -n、ulimit -u这些参数建议直接写进 limits.conf并确认 OBD 启动时能继承。最稳妥的做法是把 ulimit 消息写进部署脚本避免每次手动设置。6.2 维护期不要只信obd status要盯真实探活OBD 的 status 是一个管理平面的判断可以作为参考但不能作为唯一依据。日常巡检我更推荐直接做真实探活。最简单的健康检查脚本逻辑检查 observer 进程是否存在pgrep -f observer。检查 2881 端口是否监听ss -lnt | grep 2881。用 mysql/obclient 执行select 1 from dual;验证 SQL 层是否可用。这三个条件同时满足我才认为这个组件是真正 running。否则就算 OBD 还挂着 running我也会按故障处理。此外建议把系统 OOM 日志作为告警项接入监控。很多时候 observer 被 OOM Kill 是有前兆的比如内存持续走高、free 指标持续下降。等 observer 真被杀了再去看业务已经中断好一会儿了。与其事后修不如在内存水位达到阈值时就收到告警。最后分享一个小习惯每次排查这类问题时我都会把obd cluster display的完整输出、observer.log 尾部日志、dmesg 的 OOM 记录、以及当时的 free 和 df 结果存成一个时间戳命名的文档。下次再遇到类似问题先翻历史记录判断是不是老毛病复发。这个习惯帮我省了不少时间也让我对这套环境的状态变化有了更清晰的判断依据。
返回列表