# 电梯应用「服务实例缺失」排查结论(2026-04-30) 本文档落实排查计划:锁定运行形态、Ribbon ServerList 行为、Consul 健康实例、最小风险修复分支。 ## 1. 运行版本与配置目录 ### 1.1 仓库内 Maven 验证日志(`maven-cw-elevator-application/logs/elevator-app.log`) - **Tomcat 端口**:`18081`(与 `deploy/README.md` 中 **v2-maven** 并行对拍端口一致)。 - **Profile**:`access-control`。 - **Kafka**:`192.168.3.12:9092`(本地验证栈)。 - **结论**:该日志对应 **本机/验证环境** 启动的 **Maven 构建版 V2 JAR**(非生产星中心 V1 目录),用于 API 对拍或本地联调。 ### 1.2 生产侧采集证据(`artifacts/elevator-evidence-20260430-000038/`) - **JAR**:`星中心/cw-elevator-application-V1.0.0.20211103/cw-elevator-application-V1.0.0.20211103.jar`(V1 fat-jar)。 - **`start.sh`**:`java -jar cw-elevator-application-V1.0.0.20211103.jar`,**未**附加 `--spring.config.location`。 - **`bootstrap.properties`(现场快照)**:`spring.cloud.consul.discovery.enabled=false`,Consul host 为 **主机名**(与发布包内 IP 形式不同)。 - **`application.properties`(现场快照)**:含 `feign.*.name`、业务参数、`ninca-crk-std.ip`,**未见** `ninca-crk-std.ribbon.listOfServers`(与 [`deploy/v1-legacy/application.properties`](../../maven-cw-elevator-application/deploy/v1-legacy/application.properties) 中显式 Ribbon 静态段不一致时,行为依赖 JAR 版本与配置合并)。 **结论**:排查时需区分 **(A) 本仓库 Maven V2 + deploy/v2-maven** 与 **(B) 星中心 V1 fat-jar + 同目录配置**,二者 Consul/Ribbon 生效路径不同;勿混用日志归因。 --- ## 2. `ninca-crk-std` 的 Ribbon ServerList 是否稳定 ### 2.1 日志统计(同一 `elevator-app.log`) | 模式 | 日志特征 | 次数(近似) | |------|-----------|----------------| | Consul 发现 | `ServerList:ConsulServerList{serviceId='ninca-crk-std'` | **19** | | 配置型列表 | 后续行出现 `ServerList:com.netflix.loadbalancer.ConfigurationBasedServerList@…`,且实例列表含静态地址(如 `10.128.161.95:16106`) | **多条**(`ConfigurationBasedServerList@` 在全日志约 **66** 处,含换行续行;并非全部为同一客户端,但 `ninca-crk-std` 存在两种初始化交替) | ### 2.2 代码与配置依据 - [`NincaCrkStdRibbonConfiguration`](../../maven-cw-elevator-application/cw-elevator-application-starter/src/main/java/cn/cloudwalk/ribbon/NincaCrkStdRibbonConfiguration.java) 强制使用 `ConfigurationBasedServerList`,注释说明用于避免 Consul 返回空列表时覆盖静态 `listOfServers`。 - **事实**:日志仍出现 **`ConsulServerList`**,说明在部分生命周期/上下文刷新路径下,负载均衡仍会按 **Consul** 解析;**不稳定**,与「仅静态 Ribbon」预期不完全一致。 ### 2.3 次要现象(同一日志) - 即使走 `ConfigurationBasedServerList` 且实例为 `10.128.161.95:16106`,仍可能出现 **`Connection refused`**(对端未监听或网络不通),与「无实例」不同,需区分。 --- ## 3. Consul 侧是否存在依赖服务实例(验证环境实测) 对 **`http://192.168.3.12:8500`**(仓库 `deploy` 文档中的本地 Consul)执行: `GET /v1/health/service/?passing=true` | 服务名 | 结果 | |--------|------| | `cwos-portal` | `[]` | | `ninca-common` | `[]` | | `ninca-common-component-organization` | `[]` | | `ninca-crk-std` | `[]` | | `elevator-app` | **有** passing 实例(摘录响应中含 `elevator-app` 注册信息) | **结论**:当前验证用 Consul 上 **四个上游均无健康实例**。若应用侧 **`spring.cloud.consul.discovery.enabled=true`**(早期发布包曾在 `bootstrap` 中如此配置;当前基线见 [`deploy/v2-maven/bootstrap.properties`](../../maven-cw-elevator-application/deploy/v2-maven/bootstrap.properties)),Ribbon 走 **`ConsulServerList`** 时会出现 **`Load balancer does not have available server`**,这与实测一致。 生产环境请在 **目标 Consul 地址**上重复上述 HTTP 检查([`scripts/collect_elevator_runtime_evidence.sh`](../../scripts/collect_elevator_runtime_evidence.sh) 已内置相同请求)。 --- ## 4. 最小风险修复分支(二选一) ### 分支 A:禁用 Consul 客户端发现 + 静态 Ribbon(与 `deploy/v1-legacy`、较新发布包中对齐) 1. 设置 **`spring.cloud.consul.discovery.enabled=false`**(仍可保留 `consul.enabled=true` 用于配置中心等其他用途,以现场为准)。 2. 在 **`application.properties`**(与 JAR 同目录或 Consul KV,以实际生效源为准)为各 Feign 客户端补充 **`*.ribbon.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList`** 与 **`*.ribbon.listOfServers=host:port`**(至少覆盖:`cwos-portal`、`ninca-common`、`ninca-common-component-organization`、`ninca-crk-std`)。 3. **`ninca-crk-std`**:与 [`deploy/v1-legacy/application.properties`](../../maven-cw-elevator-application/deploy/v1-legacy/application.properties) 一致,配置 `ninca-crk-std.ribbon.*` 与 `ninca-crk-std.ip`;Maven V2 已含 `NincaCrkStdRibbonConfiguration`,仍需保证 **静态列表属性**在运行期可见。 4. 配置来源探针 **默认已运行**([`ConfigSourceProbeRunner`](../../maven-cw-elevator-application/cw-elevator-application-starter/src/main/java/cn/cloudwalk/elevator/debug/ConfigSourceProbeRunner.java));在 `*-probe.log` 核对 `*.ribbon.listOfServers` 的最终来源(无需再设 `elevator.config.probe.enabled`)。 ### 分支 B:启用 Consul 服务发现 1. 保持 **`spring.cloud.consul.discovery.enabled=true`**。 2. 在 **同一 Consul** 上确保四个服务 **注册成功且健康检查 passing**;服务名须与 `feign.*.name` 一致(如 `cwos-portal`、`ninca-common` 等)。 3. **不要求**静态 `listOfServers`;若仍报错,用 Consul UI/API 核对实例与健康检查脚本。 ### 版本选择提示 - **较早的发布包(如 v2.0.1~v2.0.3)**:`bootstrap` 中曾 **`discovery.enabled=true`**,在无上游注册的环境下更易触发本问题。 - **v2.0.4 及以后发布包**:**`discovery.enabled=false`**,与「静态 Ribbon」分支一致。 ### `deploy/v2-maven/run.sh` 注意 当前 [`run.sh`](../../maven-cw-elevator-application/deploy/v2-maven/run.sh) 仅 **`java -jar`**,不注入 `file:./application.properties`。若未通过 Consul KV 提供 Ribbon 键,则依赖 JAR 内默认配置 —— 本地「仅 Consul、无上游」时仍会失败。验证/对拍时请确保 **外置 `application.properties` 与 JAR 同目录** 或 **显式 `--spring.config.location=...`**(以团队约定为准)。 --- ## 5. 建议的只读复核命令(现场) 1. **进程与 JAR**:`ps -ef | grep cw-elevator-application`;确认 **工作目录**与 **JAR 文件名**(V1 vs V2)。 2. **Consul**:`curl -s "http://:8500/v1/health/service/?passing=true"`。 3. **日志关键字**:`ConsulServerList`、`ConfigurationBasedServerList`、`Load balancer does not have available server`。 --- ## 6. 一次性评估:应用内探针与对照方式 以下均在 **`cn.cloudwalk.elevator.debug`** 包内输出(WARN 用于异常路径),并 **双写** 主日志与 **`*-probe.log`**(见 `logs/logback.xml`);**默认始终启用**,调度见源码 **`ElevatorProbeConstants`**(不再使用 `elevator.*.probe.enabled`)。**Spring Cloud Consul**、**Netflix loadbalancer**、**Discovery** 相关 logger 在 `logback.xml` 中按 **DEBUG** 双写到 `*-probe.log`(与 `cn.cloudwalk.elevator.debug` 一致)。 | 探针 | 作用 | 与其他探针对照 | |------|------|----------------| | `ConfigSourceProbeRunner` | 启动期打印 Consul/Feign/Ribbon 关键键的 **value** 及 **PropertySource** 命中链 | 确认 `discovery.enabled`、`*.ribbon.listOfServers` 是否被 KV/本地覆盖 | | `RibbonLoadBalancerProbeRunner` | 延迟后打印各 Ribbon 客户端 **实例级 host/port** 与 **`serverCount`** | **Consul passing=0 且此处也为 0**:多为静态配置未生效或未调用;**Consul>0 此处仍 0**:重点查 `NIWSServerListClassName` / 懒加载 | | `ConsulUpstreamHealthProbeRunner` | 延迟 HTTP:**本服务**与上游 **`/v1/health/service/...`** **逐实例**(endpoint、checks 摘要)、**`/v1/agent/self`** | 与上一行 **交叉验证**:区分「注册侧无实例」与「应用侧 Ribbon 未吃到地址」 | 启动时会打一行 **`ELEVATOR DIAGNOSTIC PROBES always on`** 汇总。进程外仍建议配合 [`scripts/collect_elevator_runtime_evidence.sh`](../../scripts/collect_elevator_runtime_evidence.sh) 做完整证据包。 **一次性阅读顺序**:`*-probe.log` 中先 **CONFIG SOURCE** →(延迟后)**CONSUL** → **RIBBON**,再对照主日志中的业务异常时间线。 --- **文档维护**:若发行包 `bootstrap` 或 `run.sh` 再变更,请同步更新第 4 节与「版本选择提示」。