结论
机器人下单消息已进入 SAAS,但普通订单在地址区域名称回填时调用 BaseData 的 RegionInterface,因服务发现没有可用节点而失败。根因不是 BaseData 数据未迁移,而是 SAAS 迁出 Kubernetes 后接入了看不到 BaseData 注册信息的错误 Consul 集群视图。
证据链
群消息
-> DGJ 解析商品与地址
-> 发布机器人下单 MQ
-> SAAS 消费
-> AddressService::getDefaultAddress()
-> RegionInterface::getCollectionByIds()
-> Consul 返回 0 个健康节点
-> 下单事务失败,消费者 ACK
- SAAS 日志显示 MQ 已收到消息,随后
getCollectionByIds报Cannot select any node from load balancer。 - 代码链路位于:
/Users/zhoujiangbin/code/docker-dev-env/www/saas/app/Service/Order/V3/WechatRobotOrderService.php/Users/zhoujiangbin/code/docker-dev-env/www/saas/app/Service/User/AddressService.php/Users/zhoujiangbin/code/docker-dev-env/www/saas/config/autoload/services.php/Users/zhoujiangbin/code/docker-dev-env/www/saas/app/Amqp/Consumer/Dgj/DgjConsumer.php
- BaseData 两个实例均运行并监听 JSON-RPC TCP/HTTP 端口,也有注册 Consul 的日志;在 BaseData 所属生产 Consul 集群可读到健康
RegionInterface节点。 - SAAS 所解析到的另一 Consul 集群返回 0 个健康节点,因此 SAAS 的负载均衡器无法选择节点。
DgjConsumer::WechatRobotOrder()在异常后最终 ACK,失败消息不会自动重试。
排查顺序
- 先确认 DGJ 是否完成解析和 MQ 发布,不要从“没有下单”直接归因到商品或库存。
- 在 SAAS 消费日志按消息/来源单号关联 RPC 客户端日志,确认具体 JSON-RPC method。
- 在 SAAS 主机和 BaseData 主机分别解析 Consul 地址,读取服务目录与健康节点数量;同名域名返回不同集群时,必须做直连对照。
- 核对
RegionInterface服务名、JSON-RPC 传输方式、端口和健康检查,而不是只看 BaseData 进程是否存在。 - 只有服务发现恢复后,才评估失败消息补偿;先做单条幂等回归,再决定是否扩大范围。
风险与处置边界
- “进程运行”和“调用方能发现健康节点”是两个独立条件,注册日志不能替代调用方视角的服务目录验证。
- 失败消息被 ACK 后不能假设会自动补偿;需要核对是否已有后续重试/人工补单,并防止重复下单。
- 本次排查未修改生产代码、配置、数据库、MQ 或服务进程。修复动作应由运维按配置、服务发现和回滚方案执行。