暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一次 PolarDB-X `SHOW SLAVE STATUS` 报错的排障复盘

110

最近在自建 PolarDB-X 集群上遇到一个比较有意思的问题。

集群本身已经恢复正常,CDC global binlog 也在正常推进,但是执行下面这个命令时报错:

SHOW SLAVE STATUS;

报错信息如下:

ERROR 9204 (HY000):
[PXC-9204][ERR_REPLICATION_RESULT] {0}

一开始看到 SHOW SLAVE STATUS
 报错,很容易联想到 DN 节点的三副本复制是不是异常了。但排查之后发现,问题并不在 DN 三副本,而是 CDC 元数据里残留了旧节点,导致 CN 访问了一个已经失效的 CDC daemon 地址。

这篇文章记录一下完整排查过程。

背景

这套 PolarDB-X 是自建在 Kubernetes 上的,集群组件包括:

CN  2 个
DN  2 组
CDC 2 个
GMS 1 组

之前集群所在物理机发生过故障,恢复过程大致是:

物理机恢复
-> Kubernetes Node 恢复
-> PolarDB-X 各组件恢复
-> CDC 曾经手动删除并重新拉起

后面业务访问和 CDC global binlog 都恢复正常。

执行:

SHOW MASTER STATUS;

可以正常返回当前 global binlog 位点,例如:

binlog.000009  468571716

执行:

SHOW FULL BINARY LOGS;

也能正常看到 binlog 文件列表。

但执行:

SHOW SLAVE STATUS;

却报:

[PXC-9204][ERR_REPLICATION_RESULT]

第一反应:是不是 DN 三副本异常?

因为 MySQL 里 SHOW SLAVE STATUS
 通常用于查看复制状态,所以第一反应是:PolarDB-X 的 DN 是三副本,是不是这个命令在查看 DN 的 slave 状态?

后来确认并不是。

PolarDB-X 里的 DN 三副本不是 MySQL 原生主从复制模型,而是底层 consensus paxos 类机制。SHOW SLAVE STATUS
 在 PolarDB-X 里主要对应的是 CDC Replica/RPL 模块,也就是 PolarDB-X 作为同步目标时,通过类似下面这些命令建立的复制链路:

CHANGE MASTER TO ...
START SLAVE;
STOP SLAVE;
RESET SLAVE;
SHOW SLAVE STATUS;

所以这个命令查的不是 DN 三副本状态,而是 PolarDB-X CDC Replica/GDN/导入类链路状态。

源码确认

查看 CN 源码可以看到,SHOW SLAVE STATUS
 的处理入口在:

LogicalShowSlaveStatusHandler

核心逻辑类似这样:

String daemonEndpoint = CdcTargetUtil.getReplicaDaemonMasterTarget();

res = PooledHttpHelper.doPost(
    "http://" + daemonEndpoint + "/replica/showSlaveStatus",
    ContentType.APPLICATION_JSON,
    JSON.toJSONString(sqlNode.getParams()),
    10000
);

也就是说,当客户端执行:

SHOW SLAVE STATUS;

CN 实际上会去找 CDC daemon,然后访问:

/replica/showSlaveStatus

再看 CDC 侧源码,/replica/showSlaveStatus
 最终会查询 RPL 元数据,例如:

rpl_state_machine
rpl_task

然后组装类似下面这些字段:

Slave_IO_Running
Slave_SQL_Running
Seconds_Behind_Master
Master_Host
Master_Port
Running_Stage
Channel_Name

这就说明:

SHOW SLAVE STATUS 查的是 CDC Replica/RPL 状态,不是 DN 三副本状态。

直接访问 CDC 接口

既然 CN 是访问 CDC daemon 的 REST 接口,那就直接从 CDC pod 内访问一下:

curl -X POST -d '{}' http://127.0.0.1:3007/replica/showSlaveStatus

返回:

{"code":200,"data":"[]","msg":"success"}

两个 CDC pod 都是这个结果。

这说明:

  1. CDC daemon REST 接口本身正常。
  2. 当前没有配置 Replica/RPL 同步任务。
  3. 正常情况下 SHOW SLAVE STATUS
     应该返回空结果,而不是报错。

继续从 CN pod 里访问当前两个 CDC pod:

curl -X POST -d '{}' http://10.10.157.30:3007/replica/showSlaveStatus
curl -X POST -d '{}' http://10.10.157.124:3007/replica/showSlaveStatus

也都能正常返回:

{"code":200,"data":"[]","msg":"success"}

所以网络本身没有问题,CDC 接口也没有问题。

那为什么 CN 执行 SQL 会报错?

查看 CN 日志

在 CN 日志里找到了对应异常:

SQL: SHOW SLAVE STATUS
ERR-CODE: [PXC-9204][ERR_REPLICATION_RESULT]

同时慢日志里这条 SQL 的耗时是:

rt=10006222

约等于 10 秒。

而源码里 CN 调 CDC 接口的超时时间正好是:

10000

这基本说明:CN 执行 SHOW SLAVE STATUS
 时,访问 CDC daemon 超时了。

但我们手动从 CN 访问当前 CDC pod 是正常的。

所以问题很可能是:

CN 查询出来的 CDC daemon endpoint 不是当前真实的 CDC pod。

关键表:binlog_node_info

CN 获取 CDC daemon endpoint 时,会查询 MetaDB 里的 binlog_node_info
 表。

重点逻辑类似:

select ip, daemon_port
from binlog_node_info
where cluster_type = 'BINLOG'
  and role = 'M';

于是查看这张表:

select cluster_type, role, ip, daemon_port, status, gmt_heartbeat
from binlog_node_info
order by cluster_type, role, ip;

结果发现了问题:

cluster_type  role  ip             daemon_port  status  gmt_heartbeat
BINLOG        M     10.xx.xx.120  3007         0       2026-06-16 07:05:33
BINLOG        M     10.xx.xx.124  3007         0       2026-07-01 14:40:58
BINLOG        S     10.xx.xx.30   3007         0       2026-07-01 14:40:58
BINLOG        S     10.xx.xx.41   3007         0       2026-06-16 07:05:32

当前真实 CDC pod 只有:

10.xx.xx.30
10.xx.xx.124

但是表里还残留了两个旧 IP:

10.xx.xx.120
10.xx.xx.41

其中更严重的是:

10.xx.xx.120  role=M  status=0

也就是说,一个已经不存在的旧 CDC 节点,仍然被标记成 master,并且还是可用状态。

从 CN pod 里访问这几个 endpoint:

10.xx.xx:3007 -> timeout
10.xx.xx.124:3007 -> success
10.xx.xx.30:3007  -> success
10.xx.xx.141:3007  -> timeout

问题终于明确了。

根因

这次问题的根因是:

CDC 元数据表 binlog_node_info 中残留了旧 CDC 节点记录。
旧节点已经不可达,但仍然保持 role='M'、status=0。
CN 查询 CDC daemon master 时可能拿到旧 IP,导致访问超时。
最终 SHOW SLAVE STATUS 报 PXC-9204。

这个问题和之前物理机故障恢复过程有关。

推测过程是:

物理机故障
-> 旧 CDC pod 非正常退出
-> 旧 CDC daemon 没有机会优雅下线/更新元数据
-> CDC pod 后续重建,获得新 IP
-> 新 CDC 正常注册
-> 旧 CDC 元数据残留
-> 表里出现两个 BINLOG master
-> CN 访问旧 master 超时

修复方式

修复前先备份 binlog_node_info

kubectl exec -n polardbx-operator-system <cn-pod> -c engine -- \
  bash usr/bin/ctmeta -N -B -e "select * from binlog_node_info;" \
  > root/binlog_node_info.before_fix.tsv

注意这里要用:

bash usr/bin/ctmeta

因为当前容器里的 /usr/bin/ctmeta
 是脚本,但缺少 shebang,直接执行会报:

exec format error

然后把旧节点标记为不可用:

update binlog_node_info
set status = 1, role = 'S'
where cluster_type = 'BINLOG'
  and ip in ('10.xx.xx.120''10.xx.xx.41')
  and gmt_heartbeat < '2026-06-17 00:00:00';

再次查询确认只剩当前真实 CDC master 可用。

修复后执行:

SHOW SLAVE STATUS;

不再报 PXC-9204

因为当前没有 Replica/RPL 任务,所以正常结果应该是空结果。

总结

这次问题最容易误判的地方是 SHOW SLAVE STATUS
 这个名字。

在 MySQL 里,它通常意味着主从复制状态;但在 PolarDB-X 中,它更偏向 CDC Replica/RPL 链路状态,并不是 DN 三副本状态。

这次真正的问题不是:

DN 三副本异常
CDC global binlog 异常
Replica 任务异常

而是:

CDC 元数据残留旧节点,导致 CN 选错 CDC daemon endpoint。

排查这类问题时,可以按这个顺序:

1. SHOW MASTER STATUS 看 global binlog 是否正常推进
2. 直接访问 CDC replica/showSlaveStatus 接口
3. 从 CN pod 访问 CDC REST 端口,确认网络
4. 查询 binlog_node_info,确认是否有旧 IP、多个 master、过期 heartbeat
5. 修复旧节点 status/role

这类问题也提醒我们:自建 PolarDB-X 集群在经历物理机故障、K8s 节点异常、Pod 非优雅退出后,除了看 pod 是否 Running,还要检查 CDC/GMS 元数据是否存在脏记录。尤其是 CDC 这种依赖元数据选主和路由的组件,旧节点残留会导致一些看似随机、但本质很明确的异常。


#PolarDB-X

✪ 本文是小编的第209篇文章,第一阶段目标是累计输出 1000 篇优质内容,核心是为了提醒自己:保持学习、保持记录、保持分享,如果觉得本文对你有帮助,欢迎点赞、转发、在看三连!


 or  


文章转载自PostgreSQL运维技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论