技术问题排查
常见症状 / 错误及其解决方案。快速分类 → 详细解决流程。
status.sh— 容器 + 端口 + API + app.properties 核心键的一行摘要health.sh— 基于退出码的综合健康检查(适合 cron)doctor.sh— 诊断打包 tarball(api / docker / systemd / 7 个组件日志 / 脱敏配置 / 主机指标) → 支持升级/api/v1/system/health— 8 个组件的状态映射 + 503 分支(立即识别哪个组件处于 DOWN 状态)- 容器模式运维 — 故障应对 + 命令速查表
按症状索引
| 症状 | 可能原因 |
|---|---|
| 应用启动时卡住 | Cassandra 连接失败,DDL 应用失败 |
/api/v1/edge 响应为 started=false | Collector 初始化失败(驱动 / 缓存问题) |
特定 OPC 出现 connection_status=DISCONNECTED | PLC 网络 / 认证 / 地址格式 |
| 所有 OPC 偶尔同时断开 | 因 OPC 添加/修改导致 OPCUAServerManager 整体重启 |
| MQTT 无法发布 | 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 |
| keyspace 存在 | 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,端口 44818 |
优先参考各驱动页面中的"常见错误 + 解决方案"表。
LS-PLC Ping failed
LS 驱动在连接前通过 ICMP ping 来检查可达性。如果公司网络阻断了 ICMP,即使 PLC 正常也会显示为失败。
解决方案:
- 在防火墙中允许 ICMP
- 或后续更改
LSDriver.connect()中的 ping 检查为可选项(当前需要代码变更)
32位 / 64位值不一致
大部分原因是 format 未指定。
| 协议 | 错误模式 → 正确模式 |
|---|---|
| LS | D00600 + Integer(按 16 位读取) → D00600 + Integer + format=DW |
| Modbus | holding-register:1(16 位) → holding-register:1:DINT |
| S7 | %DB1.DBW0 + Float → %DB1.DBD0 + format=REAL |
32 位浮点值为 NaN / 异常大数
字节序(endianness)问题。检查从站 / 主站的字节/字交换策略:
- Modbus → 使用
:UDINT_LSWORD_FIRST等 PLC4j 选项 - 其他协议 → 使用计算公式进行后处理
传输(MQTT / Sparkplug)
MQTT 无法发布
# 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
- catalina.out 中是否出现
MQTT connected或重连日志
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 也可能被额外发布。在这种情况下,主机侧应实现为对相同 bdSeq 的 NDEATH 只处理一次。
性能 / 响应性
OPC 启动/停止响应耗时 5 秒
这是由于 ConnectService 的有意 Thread.sleep(保证 collector 预热)。
- 临时规避:通过刷新页面确认轮询响应
- 永久解决:应用
REFACTORING_PLAN.mdPhase A1(去除Thread.sleep/CountDownLatch)后的后续 PR
页面首次加载缓慢
opcList() N+1 查询 + LastValueMap 查找分散可能导致额外 1~2 秒延迟。
- 应用 Phase B1(IN 批量 select)和 B2(单一 facade)后预计改善
修改一个 OPC 时其他 OPC 也暂时中断
这是因为 OPCUAServerManager.restart() 是整体重启(Phase A2 — 部分重载目标)。
紧急规避:在非运维时间进行 OPC 变更。
数据 / Cassandra
tombstone 累积警告
运维中批量删除 OPC 时,nodetool cfstats pe.app_tag 的 tombstone 指标可能暂时飙升。
- 由于本网关的 OPC/标签数量通常 ≤ 1000,情况并不严重
- 时序数据(
TM_TAG_POINT)不属于本网关,而是plantpulse-timeseries-engine的职责
tag not found: <id>
在 PUT /api/v1/tag/{tagId} 或读取时频繁发生。
原因:
tag_id拼写错误APP_TAG.xml的R03属于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 外的协议目前不支持写入。
- 仅实现
HTTPDriver.bind() - 其他协议的写入需要 Sparkplug Phase 3(NCMD/DCMD)以及 SPI 扩展
安全 / 运维
/api/* 未认证即可访问
设计上以公司网络为前提(SecurityFilter 的 check-pattern 中不包含 /api/*)。外部暴露时,请在反向代理前端配置 mTLS / API Key / Basic 认证。
CSRF
仅对 *_.do 模式应用 CSRF。v1 变更端点不在应用范围内。外部暴露时请一并考虑。
日志收集指南
报告问题时,附带以下内容可以加快分析。
# 환경
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 的密码进行脱敏后再附上。