트러블슈팅
자주 발생하는 증상 / 에러와 해결책. 빠른 분류 → 상세 해결 흐름.
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 연결 안 됨
| 프로토콜 | 1차 확인 |
|---|---|
| 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 (endianness) 문제. 슬레이브 / 마스터 의 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 가 client 로부터의 publish 허용 ACL 인지
- 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 워밍업 보장).
- 임시 회피: 화면 reload 로 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 의 비밀번호는 마스킹 후 첨부하세요.