客户的一套两节点 RAC,节点 2 每隔两三天就被驱逐一次,重启后一切正常,过两天又驱逐。CSS 日志里反复出现 'clssnmPollingThread: node 2 (consecutive) missed checkins'。这种间歇性故障最烦人,因为你抓不到现场。
2.1 CSS 的两条心跳,断一条还能活,断两条必死
Oracle RAC 的 CSS(Cluster Synchronization Services)有两条心跳:一条是 Network Heartbeat,走私网(private interconnect),每秒一次 UDP 包;另一条是 Disk Heartbeat,走 voting disk,每 200ms 写一次。misscount 默认是 30 秒,也就是说如果连续 30 秒没收到某个节点的心跳,CSS 就认为它挂了,发起驱逐。但这里有个细节:两条心跳是"或"关系,只要有一条活着,节点就不会被驱逐。所以间歇性驱逐说明两条心跳同时抖动了,或者 CSS 进程自己卡了。
2.2 模拟实验:分别阻断两条心跳
为了验证这个结论,我在测试环境做了两组实验:第一组,用 iptables 阻断私网,但 voting disk 正常。结果节点 30 秒后被驱逐,符合预期。第二组,私网正常,用 tc(traffic control)给 voting disk 的 I/O 加 500ms 延迟。结果节点没有被驱逐,因为 network heartbeat 还在。第三组,同时阻断私网并延迟 voting disk。结果 15 秒就被驱逐,比单断一条快一倍。
回到客户现场,我们查了 OSWatcher 的历史数据,发现节点 2 被驱逐前,私网的 rx_crc_errors 有突增,同时存储多路径(multipath)有一条链路闪断。也就是说,网络 CRC 错误导致 UDP 包丢包,存储链路闪断导致 voting disk I/O 排队,两条心跳同时承压,CSS 判定死亡。
2.3 根因与修复
-- 查看 CSS 心跳历史(从 diag 目录)
grep -i "missed checkins" $DIAG_HOME/crs/node2/cssd/ocssd.log
-- 查看网络错误
ethtool -S eth2 | grep crc
-- 发现 rx_crc_errors: 1523(正常应该是 0)
-- 查看多路径状态
multipath -ll
-- 发现 3600...dm-2 有一条 path 状态是 failed
-- 修复:更换网线(解决 CRC),调整 multipath 的 polling_interval 从 5 秒降到 1 秒
-- 同时把 RAC 的 misscount 从 30 秒调到 60 秒(应急措施,给心跳更多容错)
crsctl set css misscount 60
这次故障让我对 RAC 的心跳机制有了新认识:很多人只关注私网带宽,觉得千兆够用了,但忽略了 UDP 包的完整性和存储 I/O 的稳定性。RAC 的"高可用"不是免费的,它需要网络、存储、OS 三层都稳,任何一层抖一下,CSS 的 misscount 就像一个不确定的因素。