故障排查
常见症状 / 错误及解决方案。快速分类 → 详细解决流程。
status.sh— 容器 + 端口 + API + app.properties 核心键的单行摘要health.sh— 基于 exit code 的综合健康检查(适合 cron)doctor.sh— 诊断信息打包 tarball(api / docker / systemd / 7 个组件 logs / config redacted / host metrics)→ support escalation/api/v1/system/health— 8 个组件的 status map + 503 分支(可立即识别哪个组件为 DOWN)- 框内
/opt/kopens/install/RUNBOOK.md— 5 种场景矩阵(A~E)+ 命令 cheat sheet
症状索引
| 症状 | 可能原因 |
|---|---|
| 应用启动过程中卡住 | Cassandra 连接失败、DDL 应用失败 |
/api/v1/edge 响应为 started=false | Collector 初始化失败(驱动 / 缓存问题) |
仅特定 OPC 为 connection_status=DISCONNECTED | PLC 网络 / 认证 / 地址格式 |
| 所有 OPC 偶尔同时断开 | 因 OPC 新增/修改导致 OPCUAServerManager 整体 restart |
| MQTT publish 不成功 | mqtt.enable=false 或 broker 认证失败 |
| Sparkplug 主题未发布 | sparkplug.enable=false 或 jar 缺失 |
| 界面显示缓慢 | opcList() N+1 查询 + sleep 累积 |
| OPC 启动每次耗时 5 秒 | Thread.sleep 影响(Phase A1 对象) |
启动 / 初始化
Cassandra 连接失败
Caused by: com.datastax.oss.driver.core.exceptions.NoHostAvailableException
| 检查项 | 确认方法 |
|---|---|
| Cassandra 运行状态 | nodetool status |
| 端口可达性 | telnet <app.db.host> 9042 |
| 键空间是否存在 | cqlsh -u cassandra -p cassandra 后 DESCRIBE KEYSPACE pe; |
app.db.* 与 oltp.cassandra.* 是否一致 | 检查 app.properties 两侧配置项 |
app.sql.path 拼写为 resouces 的笔误
app.properties 中 app.sql.path = classpath:resouces/sql 的 resouces 属于拼写错误,但目录也保持了
相同名称,因此可正常工作。若出现找不到 SQL 资源的错误,请确认 WEB-INF/resouces/sql/ 路径
是否实际存在。
OPC / 驱动
特定 OPC 无法连接
| 协议 | 首要确认项 |
|---|---|
| OPCUA | opc_agent_port 可达性、discovery=true 尝试、用户名/密码 |
| Modbus TCP | 502 端口可达性、holding-register:... 格式 |
| MELSEC | MC 协议已启用、controller-type=Q_L 一致 |
| S7 | rack/slot 一致、"PUT/GET" 已启用 |
| LS | NetUtils.isReachable 失败时怀疑 ICMP 被阻断,端口 2004 |
| EIP | rack/slot、port 44818 |
优先参考各驱动页面的"常见错误 + 解决方法"表。
LS-PLC Ping failed
LS 驱动在 connect 前会通过 ICMP ping 确认可达性。若公司内网阻断 ICMP,正常的 PLC 也会 被标记为失败。
解决方法:
- 在防火墙中放行 ICMP
- 或后续变更为可选择关闭
LSDriver.connect()的 ping 检查(目前需要修改代码)
32-bit / 64-bit 值不一致
大多数情况由 未指定 format 引起。
| 协议 | 错误写法 → 正确写法 |
|---|---|
| LS | D00600 + Integer(按 16-bit 读取)→ D00600 + Integer + format=DW |
| Modbus | holding-register:1(16-bit)→ holding-register:1:DINT |
| S7 | %DB1.DBW0 + Float → %DB1.DBD0 + format=REAL |
32-bit float 值为 NaN / 异常大数
byte order(字节序)问题。请确认从站 / 主站的 byte/word swap 策略:
- Modbus → 使用
:UDINT_LSWORD_FIRST等 PLC4j 选项 - 其他协议通过 fomula 进行后处理
传输 (MQTT / Sparkplug)
MQTT publish 不成功
# broker 도달 확인
MQTT_USER="${MQTT_USER:-edge}"
MQTT_PASSWORD="$(tr -d '\r\n' < /run/secrets/mqtt-password)"
mosquitto_pub -h <mqtt.server.host> -p 1883 -u "$MQTT_USER" -P "$MQTT_PASSWORD" -t /edge/point -m '{"test":1}'
检查清单:
mqtt.enable=truemqtt.server.host/port/user/password是否正确- broker 的 ACL 是否允许该 client 进行 publish
- catalina.out 中是否有
MQTT connected或 reconnection 日志
看不到 Sparkplug 主题
| 检查项 | 方法 |
|---|---|
是否为 sparkplug.enable=true | 确认 properties 并需要重启 |
| jar 是否位于 lib 中 | ls WebContent/WEB-INF/lib/tahu-core*.jar |
| 是否为同一 broker | mqtt.server.* 与 SPB 是否相同 |
| broker 的 SPB 主题 ACL | spBv1.0/# 发布权限 |
NDEATH 似乎被发布了两次
这是正常行为。正常关闭时会显式发布,同时(由于已注册 will)若 broker 未能识别为 will-bypass 的连接断开,will 也可能被额外发布。此时 host 侧应实现为对相同 bdSeq 的 NDEATH 仅处理一次。
性能 / 响应性
OPC start/stop 响应耗时 5 秒
这是由于 ConnectService 中有意加入的 Thread.sleep(用于保证 collector 预热)。
- 临时规避:通过刷新页面确认 polling 响应
- 根本解决:应用
REFACTORING_PLAN.mdPhase A1(移除Thread.sleep/CountDownLatch)的后续 PR
界面首次加载缓慢
由于 opcList() N+1 查询 + LastValueMap lookup 分散,可能会额外产生 1~2 秒的延迟。
- 应用 Phase B1(IN 批量 select)与 B2(单一 facade)后将得到改善
修改一个 OPC 时其他 OPC 也临时中断
因为 OPCUAServerManager.restart() 是整体重启(Phase A2 — partial reload 对象)。
紧急规避:在运维时间外进行 OPC 变更。
数据 / Cassandra
tombstone 累积告警
运行中批量删除 OPC 时,nodetool cfstats pe.app_tag 的 tombstone 指标可能会临时出现 spike。
- 本网关的 OPC/Tag 数量通常 ≤ 1000,影响不严重
- 时序(
TM_TAG_POINT)不由本网关负责,而是plantpulse-timeseries-engine的职责
tag not found: <id>
在 PUT /api/v1/tag/{tagId} 或 read 时经常发生。
原因:
tag_id拼写错误APP_TAG.xmlR03的ALLOW FILTERING查询未指定 partition key。tag_id 必须准确。
确认方法:
cqlsh -u cassandra -p cassandra -k pe -e "SELECT tag_id FROM app_tag;"
写入值时 tag write not supported for opc_type=...
除 HTTP 外的协议目前不支持 write。
- 仅实现了
HTTPDriver.bind() - 其他协议的 write 需要随 Sparkplug Phase 3(NCMD/DCMD)一并进行 SPI 扩展
安全 / 运维
/api/* 无认证暴露
设计上以公司内网为前提(SecurityFilter check-pattern 中不包含 /api/*)。对外暴露时,请在反向代理
前端配置 mTLS / API Key / Basic auth。
CSRF
仅对 *_.do 模式应用 CSRF。v1 mutation 端点不在适用范围内。对外暴露时请一并评估。
日志采集指南
报告问题时,一并附上以下内容可加快分析速度。
# 환경
curl -s http://localhost:8080/api/v1/edge
# OPC 상태
curl -s http://localhost:8080/api/v1/opc
# 시스템 메트릭
curl -s http://localhost:8080/api/v1/monitoring
# 최근 로그
tail -n 500 $CATALINA_HOME/logs/catalina.out
请将 app.properties 中的密码进行脱敏后再附上。