본문으로 건너뛰기

현장 사례집

「이렇게 하세요」가 아니라 「이렇게 됐고 이렇게 풀었다」의 기록입니다. 2026년 2월부터 9월까지 실제 현장에서 겪고 해결한 것만 담았습니다.

이 문서를 읽는 법

일반 절차와 기본 사용법은 여기 없습니다. 그건 문제 해결 과 기술 문제 해결 이 정본입니다.

여기 있는 것은 증상 → 원인 → 조치 세 줄입니다. 지금 겪는 증상과 비슷한 것을 찾아 원인 후보로 쓰세요. 남아 있는 숫자는 프로토콜 표준이나 라이브러리 기본값처럼 지식 자체인 것뿐이고, IP·호스트명·고객사명은 뺐습니다.


1. 현장 설치 · 네트워크​

PLC 에 ping 이 안 되고 데이터를 못 주고받음​

  • 증상 현장 설치 후 PLC 와 통신 불가. ping 무응답.
  • 원인 PLC IP 와 엣지 PC 에 할당할 IP 를 구분하지 않았습니다.
  • 조치 엣지 PC IP 를 PLC 와 같은 대역 · 다른 호스트 · 동일 마스크로 설정합니다. 출장 전 표에 두 IP 를 채워 서로 다른 값인지 확인하고 출발하세요.
  • 확인 양쪽 통신이 동시에 끊기면 IP 충돌을 먼저 의심합니다. ping → 포트 → read 순으로 좁힙니다.

미쓰비시 포트를 몰라 엔지니어 대기만 함​

  • 증상 MC 프로토콜 포트를 몰라 작업이 멈춤.
  • 원인 미쓰비시는 공식 고정 포트가 없습니다. GX Works 의 「오픈 설정」에서 지정하는 값입니다.
  • 조치 엔지니어에게 네 가지만 지정해 요청합니다 — ① 오픈 설정 화면 ② 프로토콜·오픈 방식·자국 포트 ③ MC 프로토콜용 설정 여부 ④ 접속 허용 IP 제한. 「통신 설정 어떻게 하나요」로 열어 묻지 않습니다.
  • 참고 관행값은 내장 이더넷 1025 · 모듈 2001 이고 5001·5002 는 예약입니다. 5007 은 라이브러리 기본값이지 미쓰비시 기본값이 아닙니다.

ping·포트는 되는데 값이 안 읽힘​

  • 증상 연결은 되는데 메모리 값이 안 들어옴.
  • 원인 PLC DB 블럭 메모리 주소값 문제.
  • 조치 PLC 엔지니어에게 DB 블럭 주소값 확인을 요청합니다. 주소가 맞고 연결 옵션에 이슈가 없으면 엣지 측 스캔 문제는 없다는 것이 현장 자료로 증명돼 있습니다. 그 선부터는 PLC 측 조치입니다.

판넬 문을 닫으면 통신이 불안정해짐​

  • 증상 판넬 문을 닫으면 네트워크가 매우 불안정하고, 열어두면 양호.
  • 원인 두꺼운 판넬 내부에 엣지 PC·LTE 라우터·안테나까지 전부 넣은 구성.
  • 조치 안테나를 판넬 외부로 설치합니다. 타공 위치는 전기실 담당이 지정합니다. 외부 설치 시 접합부 실리콘 처리가 필수입니다 — 고정 불량을 막습니다.

실사에서 확인 항목을 놓쳐 현장에서 막힘​

  • 증상 준비했다고 생각했는데 현장에서 변수가 계속 나옴.
  • 조치 실사 6항목을 고정합니다 — 판넬 구조·함체 종류 / PLC 모델·상태 / 네트워크 통신 방식 / AP 구역 ping 상태 / 엣지 PC 설치 위치 / 안테나 위치. 함체는 엣지 미니 PC + LTE 라우터 + 2구 멀티탭 구성이며 전원 어댑터 위치를 반드시 고려합니다.

엣지 PC 설치 대수를 확정할 수 없었음​

  • 증상 실사를 마쳤는데 장비 수량이 안 나옴.
  • 원인 수집 태그 수가 확보되지 않았습니다. 태그 수와 수집 주기가 있어야 장비당 부하를 잡고 대수를 정할 수 있는데 목록이 없었고, 설치 위치도 제한적이라 추가 설치가 어려웠습니다. 1:1 매핑을 전제했으나 고객사는 1:N 을 요구했습니다.
  • 조치 실사 전에 ① 사업장별 PLC 태그 목록·수 ② 설치 정보 양식(PLC/SCADA · IP/PORT · 프로토콜) ③ 신규 구간 네트워크 구성 방안을 먼저 받습니다.

PLC 에 이더넷 포트가 없거나 SCADA PC 경유를 요구받음​

  • 증상 이더넷 TCP 직결 전제가 성립하지 않음. 「PLC 에 연결된 PC 에서 가져가면 되지 않냐」는 요구, 또는 PLC 다수가 SCADA PC 의 DB 에만 기록되는 구조.
  • 조치 실사 시 PLC 이더넷 포트 유무 / SCADA 경유 여부 / SCADA DB 종류·기록 방식을 반드시 확인해 수집 방식을 사전에 결정합니다.

테스트 도구를 붙였다가 수집이 깨짐​

  • 증상 검증 도구 접속 후 기존 수집이 거부되거나 교란됨.
  • 원인 MELSEC 같은 단일 연결 슬롯 장비에 두 번째 TCP 연결을 열었습니다.
  • 조치 세 가지를 금합니다.
    1. 수집 중인 PLC 에 두 번째 연결 금지 — 해당 OPC 를 먼저 정지합니다.
    2. write 금지 — 도구 인자 하나로 write 가 됩니다.
    3. 프로브 타임아웃 1초 금지 — 장비 accept 지연 실측이 약 2.6초입니다. 3~5초로 잡습니다.

2. 부팅 · 기동​

부팅 후 모든 endpoint 무응답 + ping retry 로그 도배​

  • 증상 요청이 전부 timeout(code=000).
  • 원인 dev.mode=EDGE 인데 외부 플랫폼 웹 포트가 죽어 부팅이 차단됐습니다.
  • 조치 dev.mode=STANDALONE 으로 바꿔 재기동하고, 외부가 회복되면 원복합니다. server.host 도 함께 확인합니다.

웹 화면이 3~4분마다 먹통​

  • 증상 주기적으로 웹이 죽고 되살아남.
  • 원인 플랫폼 미연결. 붙지 못하면 웹 컨텍스트가 3~4분마다 리로드 루프에 빠집니다. 연결되면 멈춥니다. 웹 자체 문제가 아닙니다.
  • 조치 플랫폼 연결 복구가 근본입니다.

인증 키를 바꾼 뒤 NPE 무한 폭주​

  • 증상 로그에 dm is null NPE 가 끝없이 쌓이고 DB 관련 기능이 전부 죽음.
  • 원인 키가 틀리면 API client 초기화가 403 으로 hard-fail 하고, 그 결과 DatalakeManager 가 초기화되지 않아 DB 계층이 무너집니다. 정상 키일 때는 폴백으로 올라옵니다.
  • 조치 원래 키로 원복 후 재기동합니다. 부팅 로그의 DataSource initialized — ready 줄로 확인합니다.

3. 플랫폼 상행(전송) 끊김​

엣지 웹·수집은 정상인데 플랫폼에 데이터가 안 올라옴​

가장 자주 마주친 형태입니다.

  • 증상 현장 수집과 웹은 멀쩡한데 상행만 멈춥니다. 웹포트 TIME-WAIT 이 100개 이상 폭주합니다.

  • 원인 회선 순단 후 MQTT 재연결 CONNECT 에 인증정보가 빠져 플랫폼이 거부하고 무한 재연결에 빠집니다. 최초 기동 경로에는 인증정보가 들어가므로, 한 번 끊기면 앱이 스스로 복구하지 못합니다.

  • 조치 웹앱 재시작으로 세션이 복구됩니다. 재발 방지는 아래 watchdog 입니다.

  • 확인 지문은 「플랫폼 웹포트는 열리는데 MQTT 세션이 없다」입니다.

    nc -z -w2 <플랫폼IP> <웹포트> && echo ROUTE_OK
    ss -tan | grep -c "ESTAB.*<플랫폼IP>:<MQTT포트>" # 1 정상 / 0 끊김

순단은 몇 초인데 며칠간 상행 중단​

  • 증상 7초 순단 후 3시간 중단, 순단 한 번으로 11일 중단.
  • 원인 위와 같습니다. 웹·PLC 수집·회선이 전부 정상이라 아무도 인지하지 못했습니다.
  • 조치 자동복구(watchdog)를 배포합니다. 순단 길이와 중단 길이는 무관하므로 감시자 없는 장비를 먼저 처리합니다.

플랫폼에 적재가 안 되는데 엣지를 계속 파고들었음​

  • 증상 상행은 되는데 플랫폼에 데이터가 남지 않음.
  • 원인 엣지가 아니라 플랫폼 저장 경로였습니다. 브로커 전 토픽 캡처로 엣지 발행은 정상임을 확인했고, 진짜 차단점은 플랫폼 저장 초기화가 DB 쿼리 타임아웃으로 영구 미초기화된 것이었습니다.
  • 조치 플랫폼 서버를 재기동합니다. 최종 복구는 여러 원인을 동시에 해소한 것이었습니다 — 브로커 인증 파일 누락 + 태그 description null + 플랫폼 저장버퍼 정지.
  • 확인 적재 성공은 SSTable 생성이 아니라 대상 태그의 실재로 판정합니다. 생성만 보고 통과로 오판한 이력이 있습니다.

watchdog 자동복구 구성​

  • 증상 상행 끊김을 사람이 발견해야만 복구됐습니다.
  • 조치 watchdog 세 종을 각각 독립 서비스로 배포합니다 — 회선(로그만) · 설비망(로그만) · 플랫폼 세션(웹앱 재시작). 하나가 죽어도 나머지가 살아야 하므로 하나로 합치지 않습니다.
  • 판정 30초 간격 4회 연속(약 2분) 지문 확정 → 재시작 → 15분 재발동 금지.
  • 결과 6대 배포에 오탐 0건. 실전 복구는 순단 05:27 → 발동 05:39 → 복구 05:40 이었습니다.

watchdog 을 깔았는데 자동복구가 안 됨​

  • 증상 11일간 중단됐는데 watchdog 이 아무 동작도 안 함.
  • 원인 관찰 전용(DRY_RUN=1) 상태였습니다. would restart 가 1,013회 기록만 남았습니다. 판정은 정확했고 실패 지점은 이것 하나였습니다.
  • 조치 관찰 배포 → 1대 실재시작 검증 → 정상 상태에서 실행 모드로 전환합니다. 끊긴 상태에서 전환하면 즉시 재시작이 발동합니다.

수동 재시작 명령이 자기 셸을 죽임​

  • 증상 재시작 명령 실행 후 셸이 즉사하고 웹앱이 3분 34초간 다운.
  • 원인 pkill -9 -ef tomcat 의 커맨드라인에 「tomcat」 이 들어 있어 자기 자신을 매치했습니다. 뒤에 이어붙인 startup 이 실행되지 않았습니다.
  • 조치 kill 과 startup 을 별도 실행으로 분리합니다. 상태 확인은 pgrep -f 'catalina[.]startup' 처럼 대괄호로 자기 매치를 피합니다.
  • 주의 restart.sh 는 끝에 로그 tail 이 있어 자동화에서 호출하면 멈춥니다.

PLC 는 정상인데 watchdog 이 서비스 DOWN 이라고 함​

  • 증상 세션이 살아 있는데 오탐 1,422건.
  • 원인 ① 판정 패턴이 IPv6-mapped 표기([::ffff:<PLC_IP>]:<PLC포트>)를 놓쳤습니다. ② 폴백으로 쓴 nc 가 단일 세션 장비에서 거부됐습니다.
  • 조치 ① 패턴을 대괄호 유무 양쪽을 받도록 고칩니다. ② 판정 순서를 ss ESTAB 패시브 우선, 없을 때만 nc 로 바꿉니다.

watchdog 을 재시작했더니 수집이 2분 끊김​

  • 증상 watchdog 설정을 바꾸자 웹앱이 함께 종료됨.
  • 원인 watchdog 이 띄운 웹앱은 watchdog 서비스의 cgroup 에 편입되어 함께 죽습니다.
  • 조치 90초 뒤 재감지·재기동으로 자가치유되지만 2분 중단이 생깁니다. watchdog 설정 변경은 조업 영향 없는 시간에 합니다.

진단 채널 401 이 반복 기록됨​

  • 증상 진단 포트가 만성 SYN-SENT, 로그에 진단 인증 401 이 2~3초마다 찍힘.
  • 원인 플랫폼 측 사안이며, 401 은 진단 전송기가 키를 싣지 않는 세대 차 때문에 정상 동작 조합에서도 똑같이 발생합니다.
  • 조치 엣지 재시작으로 해결되지 않으므로 watchdog 트리거에서 제외합니다. 연동 정상 여부는 60초 안에 실제 태그 데이터가 들어오는지로 판정합니다.

4. PLC 수집 안정성​

통신이 잠깐 흔들릴 때마다 수집이 중지·재시작을 반복​

  • 증상 일시적 통신 변동에 수집이 멈추고 다시 붙기를 반복.

  • 원인 ping 1회 실패로 즉시 수집기를 멈췄습니다.

  • 조치 유예를 멈춤과 복구 쪽에 두었습니다. NOT_COLLECT 판정 자체에는 유예가 없습니다.

    무엇값
    ping 주기 · ICMP 타임아웃5초 · 800ms
    ping 연속 실패 몇 회에 수집기를 멈추나 (성공하면 리셋)3회
    최근 읽기가 성공해 신선하면 ping 을 건너뛰는 창15초 또는 수집 주기 ×3 중 긴 쪽
    NOT_COLLECT 로 떨어지는 조건유예 없음 — 한 주기에 오류가 1건이라도 있거나 값을 하나도 받지 못하면 그 주기에 바로
    NOT_COLLECT 가 얼마나 이어져야 복구(재연결)를 요청하나60초 넘게
    설정으로 바꿀 수 없습니다

    ping 3회 · 복구 60초를 비롯해 위 값은 모두 코드에 박힌 상수입니다. app.properties 에 해당 키가 없습니다 — 바꾸려면 제품 변경이 필요합니다. 예전 자료에 설정 키처럼 적힌 것이 있는데 사실이 아닙니다.

    함께 태그별 재시도를 없앴습니다. 연결이 끊기면 모든 태그가 동시에 실패하므로 재시도는 스캔만 지연시킵니다. 대신 태그별 읽기 타임아웃을 두어 한 태그의 지연이 전체 스캔을 묶지 않게 했습니다.

    연결 실패에는 연결별 재접속 백오프가 걸립니다(2026-10-01). 1초부터 두 배씩, 최대 60초까지 기다렸다가 다시 붙습니다. 접속에 성공하거나 IP·포트를 바꾸면 기다리지 않고 바로 다시 시도합니다.

  • 결과 잠깐의 흔들림은 화면에 NOT_COLLECT 로 잠깐 보일 수 있습니다. 그래도 수집기를 멈추거나 재연결을 일으키지는 않습니다 — ping 이 3회 연속 실패하기 전엔 멈추지 않고, 복구는 NOT_COLLECT 가 60초 넘게 이어질 때만 요청합니다.

감시층 ICMP 오탐으로 멀쩡한 수집이 정지됨​

  • 증상 수집은 되고 있는데 감시가 수집기를 멈춤.
  • 원인 감시층이 ping 결과만으로 판단했습니다.
  • 조치 감시 기준을 **「트래픽이 곧 생존 증거」**로 바꿉니다. 최근 read 가 성공했고 신선하면 프로브를 생략합니다.

소켓 누수로 PLC 가 50분간 전면 거부​

  • 증상 수집·프로브·복구 모든 연결이 거부됨.
  • 원인 드라이버를 폐기할 때 close 없이 버려 소켓이 누수됐고, 단일 슬롯 장비라 그 소켓이 슬롯을 영구 점유했습니다. connected=false 는 논리 플래그일 뿐 TCP 소켓과 별개입니다.
  • 조치 드라이버를 제거·교체하는 코드에 close 를 반드시 동반시킵니다.

프로브 타임아웃 때문에 복구가 영영 열리지 않음​

  • 증상 슬롯이 비어 있는데도 복구가 안 됨.
  • 원인 장비 accept 지연이 약 2.6초인데 프로브 타임아웃이 1초라 영구 실패로 판정했습니다.
  • 조치 타임아웃을 4초로 올립니다. 새 장비를 붙일 때는 연결 소요를 로그로 실측하고 여유를 검증합니다.
한 번의 검증 통과를 믿지 마세요

바로 위 세 사례는 같은 증상에 원인이 세 겹이었습니다. 하나를 고칠 때마다 「해결됐다」고 판단했지만 다음 원인이 남아 있었습니다.

사고는 대부분 부팅 후 1분 안에 나타납니다. 초기 3분을 집중해 관찰하고, 통과 판정은 부팅 결정 구간 + 15분 무정지 + 로그 0건을 모두 채웠을 때만 줍니다.

통신 불안정의 원인이 회선인지 확인이 안 됨​

  • 증상 간헐적 수집 실패의 원인 구간을 못 짚음.
  • 관측 실사례에서 연결 지연이 평균의 6배(6,125ms) 로 뛴 뒤 며칠에 걸쳐 링크가 끊겼고, 무조치로 자동 복구되어 수집이 재개됐습니다. 지연 급증이 전조입니다.
  • 조치 상시 품질 감시를 둡니다. 1초 ping 을 10분 단위로 요약(손실률 · RTT 최소·평균·최대)하고, 손실률 5% 이상이면 인터페이스 에러 카운터와 라우팅을 스냅샷으로 동시 기록합니다. 판정은 정상 / 주의 5% / 위험 10% 이고 로그는 15일 보관합니다.

패킷 손실 상황을 재현할 수 없었음​

  • 증상 현장 증상을 사내에서 재현하지 못해 검증이 막힘.

  • 조치 tc/netem 으로 특정 PLC IP 통신에만 손실을 겁니다. SSH 나 다른 통신에는 영향이 없습니다.

    tc qdisc del dev <NIC> root 2>/dev/null # 항상 먼저 제거
    tc qdisc add dev <NIC> root handle 1: htb default 30
    tc class add dev <NIC> parent 1: classid 1:1 htb rate 100mbit
    tc class add dev <NIC> parent 1:1 classid 1:10 htb rate 100mbit
    tc qdisc add dev <NIC> parent 1:10 handle 10: netem loss 5%
    tc filter add dev <NIC> protocol ip parent 1:0 prio 1 u32 match ip dst <PLC_IP> flowid 1:10
    tc qdisc del dev <NIC> root # 종료

watchdog 로그 판독​

상태가 바뀔 때만 이벤트 블록이 남습니다. grep "EVENT" 로 사건만 봅니다.

갈래신호뜻
LTECABLE_DISCONNECTED물리 링크
LTEROUTER_DOWN라우터 ping 실패
LTELTE_NO_RETURN_TRAFFIC송신은 있는데 수신 0 — 상행 단절
LTELTE_SIGNAL_LOST외부 ping 실패
PLCLINK_DOWN · ARP_L2_ISSUE링크·L2
PLCPHYSICAL_LAYER_ISSUECRC 증가 — 케이블·포트 물리
PLCPLC_NO_RESPONSE · PLC_SERVICE_DOWN무응답 · 포트 닫힘

⚠ 일부 NIC 은 rx_crc_errors 를 지원하지 않습니다. CRC:+0 은 폴백값이므로 물리 판정에 쓰지 마세요.


5. 값이 안 나오거나 이상함​

HMI 화면 값과 엣지 수집 값이 다름​

  • 원인 HMI 값은 이미 로직이 적용된 값일 수 있습니다.
  • 조치 3단으로 좁힙니다 — PLC 메모리 원본 → HMI 판넬(로직 적용) → 엣지(데이터 타입·수집주기·수식). 먼저 PLC 원본과 비교하고, 그다음 엣지의 타입·주기·수식을 확인해 최종 비교합니다.

카운터에 간헐적으로 이상한 중간값이 섞임​

  • 원인 PLC 스캔 주기 중 카운터 갱신 타이밍과 읽기 시점이 겹치면 상·하위 워드의 정합성이 깨진 중간값이 읽힙니다. 장애가 아니라 타이밍 특성입니다.

태그 주소를 넣었는데 계속 빈 값​

  • 원인 JSON 계열 주소에서 PATH 모드 표기($.)를 빠뜨려 KEY 모드로 떨어졌습니다. KEY 모드는 경로를 따라가지 않고 최상위 키 이름 그대로 찾습니다. 해당하는 것은 Kafka · MQTT · WebSocket 이고 HTTP 는 아닙니다.

  • 조치 세 가지를 확인합니다.

    • 배열 인덱스는 점과 숫자(.0.)이고 대괄호 표기는 지원하지 않습니다.
    • 필드명은 대소문자까지 정확해야 합니다(agvid 실패 / agvId 성공).
    • 와일드카드와 배열 전체 펼침은 지원하지 않습니다.
    TOPIC:$.body.list.0.battery ✅
    TOPIC:body.list[0].battery ❌

특정 태그만 계속 빈 값​

  • 원인 발신 측 페이로드의 필드명이 오타였습니다(status → stutaus). 정상 스펠링으로 등록하면 에러 없이 빈 값만 나옵니다.
  • 조치 등록 전에 실제 페이로드의 필드명 원문을 눈으로 확인합니다.
  • 함께 알아 둘 것 빈 문자열은 아예 적재되지 않습니다(알람 없는 시간대에 데이터 공백이 생깁니다). JSON null 은 문자열 "null" 로 적재되므로 숫자 타입으로 등록하면 파싱에 실패합니다.

발행 건수보다 수집 건수가 훨씬 적음​

  • 원인 설계상 정상입니다. 드라이버가 메시지를 마지막 값으로 덮어쓰고, 읽기는 큐 소비가 아니라 마지막 값 폴링 샘플입니다. 브로커 LAG 이 0 이면 다 받고 있는 것입니다.
  • 조치 전수집이 필요하면 큐 기반 재설계가 필요합니다. 계약 변경 사안입니다.

등록 직후 옛 데이터가 쏟아지거나 반대로 안 들어옴​

  • 원인 Kafka 의 auto-offset 방향입니다(기본 latest). latest 는 컨슈머 그룹 생성 뒤에 발행해야 잡히고, earliest 는 등록 순간 쌓여 있던 기존 메시지를 일괄 소비합니다. 두 값 외에는 조용히 latest 로 떨어집니다.
  • 주의 이건 Kafka 만 해당합니다. MQTT 에는 offset 개념이 없습니다 — 비슷한 자리가 clean-session 입니다.
  • 조치 검증은 실시간 발행으로 합니다.

데이터 추출이 0건인데 에러 로그도 없음​

  • 원인 jar 충돌 — 재패키징된 JSON 라이브러리가 표준 라이브러리와 충돌해 필요한 생성자가 없었습니다.
  • 조치 표준 jar 로 교체하고 충돌 jar 를 백업 이동한 뒤 캐시를 정리하고 재기동합니다.
  • 확인 정상은 조용한 성공입니다. 폴링 스레드가 살아 있고 LAG 이 0 이며 VALUE_NULL 로그가 멈추면 정상입니다. 성공 로그는 나오지 않습니다.

타입 예외가 납니다​

  • 증상 NumberFormatException 또는 Invalid tag data type.
  • 원인 등록할 때 타입을 일괄 Integer 로 넣었습니다.
  • 조치 값 성격대로 다시 나눕니다 — Double 은 전류·온도·전압·중량·속도·좌표, String 은 알람·상태·구역·방향·색, Integer 는 배터리·에러코드입니다. 엣지 태그 타입과 플랫폼 타입이 일치해야 합니다. 값이 문자열로 와도 선언 타입만 맞으면 정확히 파싱됩니다.

메타데이터를 바꿨는데 반영되지 않음​

  • 원인 캐시 reload 를 하지 않았습니다.
  • 조치 세 곳을 모두 다시 읽힙니다 — 플랫폼 서버, OPC-UA 플러그인, 엣지. 하나만 빠져도 정합성이 깨집니다. OPC 를 다시 등록해 태그 ID 가 재발급되면 플랫폼의 태그 잔재를 지우고 OPC 를 정지했다 시작해 재동기화합니다.

REST 로 등록했더니 드라이버가 브로커 접속조차 안 함​

  • 증상 「PLC 연결 timeout」 처럼 보이지만 TCP 는 정상이고 컨슈머 그룹조차 생기지 않음.
  • 원인 OPC 생성 요청 본문에 필수 필드가 빠져 내부에서 예외가 나고 주소 맵 스캔이 실패했습니다. 화면으로 등록하면 화면이 채워 주므로 REST 경로에서만 터집니다.
  • 조치 필수 필드 여덟 개를 모두 채웁니다 — opc_id · opc_name · opc_type · site_id · opc_agent_ip · opc_agent_port · timecycle · async. 주소 표기와 offset 방향도 함께 확인합니다.
  • 바뀐 것 예전에는 PUT 이 미지정 필드를 비워 버려 「삭제 후 재생성」이 안전했습니다. 2026-07-20 에 부분 병합으로 고쳐졌습니다 — 이제 보낸 필드만 바뀝니다. 다만 그래서 필드를 null 로 지울 수는 없습니다.

ping 은 되는데 수집이 0​

  • 원인 ping 은 되고 ARP 도 정상인데 TCP 포트만 닫혀 있었습니다. 읽기 에러 카운터가 480만인데 성공은 0 이었습니다.
  • 조치 PLC 측 통신 포트·모듈 조치 대상이며 watchdog 으로 해결되지 않습니다. 설비 담당에게 넘깁니다.

최신값을 조회했는데 옛 데이터가 나옴​

  • 원인 SELECT * ... LIMIT 5 는 파티션 순서라 옛 데이터가 먼저 나옵니다. 실시간 적재는 정상이었습니다.
  • 조치 WHERE tag_id=... ORDER BY timestamp DESC 로 확인합니다.

6. 자원 고갈 · 로그​

30일마다 온갖 오류가 동시에 터짐​

  • 증상 30일 가동 후 전방위 오류 폭발.

  • 원인 감시 타이머가 10초마다 docker ping 을 시도하는데 docker 가 없으면 실패 경로에서 파일 디스크립터 2개가 회수되지 않습니다. 예외를 로그로 남기지 않아 무증상으로 쌓입니다. 산수가 맞아떨어집니다 — 30.3일을 10초로 나누면 261,700회, 곱하기 2 는 523,400 이고 실측이 523,690 이었습니다.

  • 조치 정상 대조 장비와 같은 버전 docker 를 고정 설치합니다. 재부팅만 하면 30일 뒤에 재발합니다.

  • 확인

    P=$(pgrep -f catalina.startup.Bootstrap | head -1)
    ls /proc/$P/fd | wc -l # 정상 ~600, 누수 시 50만+
    wc -l < /proc/net/unix # 정상 ~200, 누수 시 50만+
    ls /var/run/docker.sock # 없으면 누수 진행 확정
2차 증상을 개별 버그로 오진하지 마세요

/proc/stat 실패, Mount point not found, JMX NPE, 「열린 파일이 너무 많음」, 큐 WAL 예외 (수집 데이터 유실 구간), 로그 폭증은 전부 파일 디스크립터 고갈에서 파생된 것입니다. 고갈 이전 로그에는 ERROR 가 0건이었습니다.

스레드·FD 가 계속 늘어나고 OOM 발생​

  • 원인 죽은 대상에 대한 무한 재연결. 대상이 ping 은 되는데 프로토콜 포트는 죽은 상태에서 OPC 수십 종이 1초 주기로 재연결하며 시도마다 클라이언트를 만듭니다. 실측 초당 2.25개 순증이었고 상시 스레드의 76% 가 그것이었습니다. 다른 장비에서는 드라이버 스레드가 40,900개까지 늘어 OOM 이 났고 수집이 3일 정지됐는데 종료 로그조차 없어 인지하지 못했습니다.
  • 조치 쓰지 않는 OPC 는 반드시 정지합니다. PLC 가 다운되면 같은 누수가 재현되므로 장기 가동 장비에서 특히 주의합니다.

같은 로그가 수만 건 쌓임​

  • 원인 폴링 주기가 하드코딩이라 끄는 설정이 없습니다.
  • 조치 클래스를 패치하지 말고 로깅 설정에 해당 패키지 WARN 로거를 추가해 억제합니다.

7. 배포 · 초기화​

고객사 장비에 설치 흔적을 남기지 않아야 했음​

  • 조치 파일을 올리는 대신 표준입력으로 스크립트를 투입합니다.

    ssh <호스트> 'bash -s' < install.sh

    서버에 설치본 파일이 아예 생기지 않습니다.

  • 확인 임시 디렉터리에 잔재가 없고 백업 파일이 생기지 않았으며, 24시간 내 새 파일은 의도한 산출물뿐인지 봅니다. 백업 원본은 로컬 보고서에 보존합니다.

한 줄 설치 명령이 404​

  • 원인 배포 경로가 개편됐고 도메인 최상위가 달랐습니다.
  • 함께 걸린 것
    • 심링크는 404 가 됩니다 — 포인터는 하드링크로 겁니다.
    • curl | bash 로 실행하면 스크립트 안의 read 가 EOF 를 만나 전체가 중단됩니다. 터미널을 물려 해결합니다.
    • 한 단계 실패가 이후 방화벽·튜닝·SSL·서비스 등록을 전부 건너뛰게 만들어, 해당 단계를 비필수로 바꿨습니다.

박스를 OS 만 남기고 초기화​

  • 조치 순서 컨테이너 삭제를 엔진 제거보다 먼저 합니다. 재세팅 소스가 있는지를 0번 안전장치로 두고 없으면 중단합니다.
방화벽은 절대 건드리지 마세요

원격 접속 중에 방화벽을 리셋하면 SSH 가 끊겨 콘솔 없이는 복구할 수 없습니다. 재세팅 스크립트는 필요한 포트를 다시 열 뿐 닫지 않습니다.

  • 의도적으로 안 건드리는 것 호스트명·로케일·타임존·부수 패키지입니다. 재세팅이 다시 설정합니다.

server.host 를 바꿨는데 데이터 방향이 안 바뀜​

  • 원인 그 장비는 pull 방식이었습니다. 플랫폼이 엣지의 태그 값 API 를 직접 읽어 갑니다. 엣지의 push 대상을 바꿔도 방향이 바뀌지 않습니다.
  • 조치 다른 플랫폼으로 받으려면 그쪽에 엣지 주소와 키로 pull 설정을 합니다.

엣지·플랫폼 세대가 달라 연동 불가​

  • 증상 API server is not responding 무한 반복. 포트는 전부 열려 있어 네트워크는 무죄.
  • 원인 신규 플랫폼이 새 API 만 여는데 구형 엣지가 옛 경로를 하드코딩으로 호출했습니다. 핸드셰이크가 선행돼야 발행이 시작됩니다.
  • 조치 엣지를 플랫폼과 같은 릴리스로 업그레이드합니다. 설정으로는 안 됩니다 — 핸드셰이크가 컴파일되어 있습니다.
  • 토큰 함정 저장과 배포는 다릅니다(화면에서 「배포」를 눌러야 합니다). 허용 IP 지정이 필요하고, 공개 ping 의 200 은 인증 증거가 아닙니다.