본문으로 건너뛰기

트러블슈팅

자주 발생하는 증상 / 에러와 해결책. 빠른 분류 → 상세 해결 흐름.

컨테이너 모드 (2026.05+) 진단 자원
  • 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=falseCollector 초기화 실패 (드라이버 / 캐시 문제)
특정 OPC 만 connection_status=DISCONNECTEDPLC 네트워크 / 인증 / 주소 형식
모든 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 cassandraDESCRIBE KEYSPACE pe;
app.db.*oltp.cassandra.* 일치app.properties 양쪽 항목 검토

app.sql.pathresouces 오타

app.propertiesapp.sql.path = classpath:resouces/sqlresouces 는 오타이지만 디렉토리도 같은 이름으로 유지되어 동작합니다. SQL 리소스를 못 찾는다는 에러가 나면 WEB-INF/resouces/sql/ 경로 실제 존재 여부 확인.


OPC / 드라이버

특정 OPC 연결 안 됨

프로토콜1차 확인
OPCUAopc_agent_port 도달, discovery=true 시도, 사용자/비번
Modbus TCP502 포트 도달, holding-register:... 형식
MELSECMC 프로토콜 활성, controller-type=Q_L 일치
S7rack/slot 일치, "PUT/GET" 활성
LSNetUtils.isReachable 실패면 ICMP 차단 의심, 포트 2004
EIPrack/slot, port 44818

각 드라이버 페이지의 "흔한 에러 + 해결" 표를 우선 참조.

LS-PLC Ping failed

LS 드라이버는 connect 전 ICMP ping 으로 도달성을 확인합니다. 사내망에서 ICMP 가 차단되면 정상 PLC 도 실패로 표시됩니다.

해결:

  • 방화벽에서 ICMP 허용
  • 또는 LSDriver.connect() 의 ping 검사를 옵션으로 끄도록 후속 변경 (현재는 코드 변경 필요)

32-bit / 64-bit 값이 부정합

대부분 format 미지정 이 원인입니다.

프로토콜잘못된 패턴 → 올바른 패턴
LSD00600 + Integer (16-bit 로 읽힘) → D00600 + Integer + format=DW
Modbusholding-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=true
  • mqtt.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 토픽 ACLspBv1.0/# 발행 권한

NDEATH 가 두 번 발행되는 것 같음

정상 동작입니다. 정상 종료 시 명시 발행 + (will 도 등록되어 있으니) 접속 종료를 broker 가 will-bypass 인지 못 하면 will 도 추가 발행될 수 있습니다. 이 경우 host 측에서 같은 bdSeq 의 NDEATH 는 한 번만 처리하도록 구현되어 있어야 합니다.


성능 / 응답성

OPC start/stop 응답이 5 초

ConnectService 의 의도적 Thread.sleep 때문입니다 (collector 워밍업 보장).

  • 임시 회피: 화면 reload 로 polling 응답 확인
  • 항구 해결: REFACTORING_PLAN.md Phase 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.xml R03ALLOW 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 의 비밀번호는 마스킹 후 첨부하세요.