증상은 보통 go-live 몇 주 뒤에 나온다. 한 channel의 PLC 하나가 끊기는데, 갑자기 같은 channel의 다른 device까지 전부 stale로 읽힌다. Operator는 얼어붙은 overview 화면을 보고 network 장애라고 말한다. 대부분 아니다. Scan class 문제다. 그 channel의 모든 tag가 같은 공격적인 주기로, 같은 넉넉한 timeout 뒤에서 polling되니 죽은 device 하나가 channel 전체를 끌어내린다.
"모든 tag 1초 scan"이라는 평평한 기본값이 시작점이다. 설정도 쉽고 설명도 쉬워서 그대로 운영까지 살아남는다. 동시에 PLC 통신 module이 포화되고, TCP-to-serial gateway가 밀리고, historian은 정밀해 보이지만 trend가 쓸 정보는 하나도 없는 sample로 채워지는 이유이기도 하다.
Scan class는 driver 체크박스가 아니라 제어 판단이다. Trip permissive, valve command feedback, tank level, 일 생산량 totalizer, maintenance 가동시간 counter가 같은 update rate를 가질 이유는 없다. Channel에 부하가 걸렸을 때 이들을 동급으로 두면, permissive가 늦게 도착하는 동안 maintenance 시간 counter는 제때 갱신되는 상황이 벌어진다.
Driver 기본값이 아니라 쓰임새로 tag를 묶는다
Tag는 operator와 제어 로직이 실제로 쓰는 방식으로 묶는다.
| Tag 종류 | 보통의 scan 접근 |
|---|---|
| Command feedback, interlock status | Operator 조작과 timeout 판단에 필요한 속도 확보 |
| Alarm, safety 관련 표시 | 빠르고 안정적으로 읽고 stale quality를 명확히 표시 |
| Analog process value | 화면 refresh가 아니라 공정 변화 속도 기준 |
| 느린 설비 status | Sequencing에 쓰지 않으면 중간 주기 |
| Total, counter, maintenance hour | 느린 주기 또는 가능하면 event 기반 |
| 설정값, limit, recipe value | 화면 open 시, 변경 시, 또는 느린 background read |
| Diagnostic tag | 평소에는 느리게, troubleshooting 때만 빠르게 |
한 달에 한 번 여는 maintenance 화면에만 나오는 tag가 운전 내내 operator가 보는 running-state 화면과 같은 속도로 polling될 필요는 없다. 시작점으로 나는 interlock feedback과 heartbeat는 250500 ms, analog process value는 화면이 아니라 loop에 맞춰 12초, 느린 status는 5초, totalizer와 가동시간 counter는 30~60초 또는 event 기반으로 둔다. 숫자는 현장마다 움직이지만 요점은 그 폭이다. 하나가 아니라 서너 개의 class다.
Tag가 아니라 request를 센다
부하를 정하는 건 tag 개수가 아니라 request 개수다. 잘 정렬된 Modbus block read 하나가 연속된 holding register 100개를 한 transaction으로 가져오는 반면, 주소가 흩어져 있으면 같은 tag 100개가 작은 read 수십 개가 된다. RS-485 장비를 Modbus TCP로 감싸는 gateway는 SCADA 요청 하나를 9600 또는 19200 baud의 느린 downstream transaction 여러 개로 직렬화한다. TCP 쪽은 즉답처럼 보이지만 진짜 병목은 serial 쪽이다.
Scan rate를 확정하기 전에 아래를 본다.
- Channel당 device 수와 물리 경로를 어떻게 공유하는지.
- Tag 수가 아니라 block optimization 이후의 read request 수.
- 장비가 실제로 안정적으로 처리하는 최대 request 크기(과한 read를 잘라내거나 거부하는 PLC도 있다).
- 정상 부하일 때 그리고 device가 retry 중일 때의 response time.
- Operator 조작, recipe download, batch transition 때의 write traffic — write는 같은 channel에서 read를 밀어내는 경우가 많다.
- 그 endpoint에 붙는 다른 client 전부: engineering tool, historian, redundant 짝, dashboard, 두 번째 SCADA.
Ethernet에 단독으로 붙은 PLC 하나에는 1초 class가 문제없다. 같은 설정을 RS-485 meter 여섯 대를 먹이는 Modbus TCP gateway에 복사하면, serial bus가 물리적으로 불가능한 초당 수십 transaction을 요구한 셈이다.
무엇을 먼저 늦출지, network가 정하기 전에 정한다
Load shedding을 정하지 않으면 driver와 network가 timeout, retry, reconnect storm 형태로 대신 정한다. 공유 channel의 timeout 계산을 보라. Timeout 3000 ms에 retry 2회면 죽은 device 하나가 scan cycle마다 그 channel을 약 9초씩 잡는다. Meter 하나가 죽어서 overview 전체가 얼어붙는 원리가 이거다. Timeout을 줄이고 retry를 제한하고, driver가 지원하면 연속 N회 실패한 device는 "down"으로 표시해서 다시 응답할 때까지 slot을 차지하지 못하게 한다.
내가 기본으로 쓰는 순서는 이렇다.
- Command feedback, critical alarm, heartbeat tag는 필요한 주기를 유지한다 — 절대 양보하지 않는다.
- Diagnostic tag와 maintenance tag를 먼저 늦춘다.
- Background total과 counter를 다음으로 늦춘다.
- Platform이 지원하면 닫힌 화면의 detail tag는 demand polling으로 내린다.
- 나쁜 device 하나가 channel을 독점하지 못할 만큼 timeout을 짧게 유지한다.
Protocol이 raw polling보다 나은 레버를 주는 경우가 많다. DNP3(IEEE 1815)는 이걸 위해 만들어졌다. 전체 static image는 주기적 integrity poll(Class 0)로 몇 분에 한 번 받고, event 데이터는 Class 1/2/3으로 우선순위 순서대로 예외 기반으로 올라오게 두면 모든 point를 빠르게 polling할 필요가 없다. OPC UA(Part 4)는 monitored item의 sampling interval과 subscription의 publishing interval을 분리한다. 값을 250 ms로 sampling하되 변화는 1초로 묶어 publish하고, publish 사이에 값이 유실되지 않게 queue size를 잡는다. 둘 다 모든 것을 빠르게 polling하지 않으면서 변화에 대한 빠른 응답을 유지하게 해 준다. 어떤 platform은 priority scan class나 demand polling을 직접 노출하고, 어떤 것은 channel을 나누거나 subscription group을 따로 만들어야 한다. 방법은 달라도 원칙은 같다. 낮은 가치의 polling이 높은 가치의 표시를 늦추면 안 된다.
오래된 값을 조용히 보여 주지 않는다
Scan class가 느려지거나, 멈추거나, 실패하면 operator가 오래된 값을 live 값처럼 보면 안 된다. Project에는 stale-data 기준이 있어야 한다.
기준은 구체적이어야 한다.
- 1초 주기의 critical status는 세 번 연속 update가 없으면 stale.
- 10초 주기의 utility meter는 1분이 지나면 stale.
- 일 단위 counter는 더 긴 지연을 허용하되 마지막 update time을 보여 준다.
- Demand polling maintenance 값은 "현재 polling 안 함" 또는 last-read timestamp를 보여 준다.
Stale quality는 process alarm과 다르다. 느린 diagnostic tag마다 alarm banner를 채우면 operator가 무시한다. 대신 운전 판단에 영향을 주는 위치에서는 stale 상태가 분명해야 한다.
화면 성능과 장비 polling을 분리해서 본다
Operator는 보통 "화면이 느리다"고 말한다. 실제로는 device polling이 정상이고 화면 자체가 무거운 경우가 있다. Animation, embedded trend, script, faceplate가 너무 많을 수 있다. 반대로 화면을 여는 순간 demand read가 폭증해서 장비를 밀어붙이는 경우도 있다.
두 계층을 따로 시험한다.
- 화면을 닫은 상태에서 driver statistics를 본다.
- 화면을 열고 request rate, response time, timeout count 변화를 기록한다.
- 화면을 닫으면 부하가 원래대로 내려가는지 확인한다.
- 숨겨진 tab, popup, 화면 밖 component가 계속 polling하는지 본다.
- HMI render time과 protocol response time을 따로 비교한다.
이렇게 해야 graphics 성능 문제인지, 통신 capacity 문제인지 갈라진다.
자주 보는 실패 패턴
| 증상 | 가능성이 큰 원인 |
|---|---|
| 한 장비가 죽으면 같은 channel의 모든 장비가 느려짐 | Timeout과 retry가 channel을 오래 잡고 있음 |
| 큰 화면을 열 때만 값이 늦어짐 | Demand polling 또는 display-bound tag가 burst load 생성 |
| Historian sample은 많은데 쓸모 있는 변화가 적음 | Scan rate가 공정 변화보다 빠르거나 compression 기준 부적절 |
| Recipe download 중 critical feedback이 늦음 | Write burst와 느린 tag가 같은 통신 경로를 공유 |
| FAT에서는 정상인데 현장에서 gateway가 흔들림 | 추가 client나 serial device가 부하 시험에 빠짐 |
| Operator가 stale 표시를 무시함 | Stale 기준이 너무 시끄럽거나 운전 판단과 연결되지 않음 |
인수인계 전 부하 시험
Interface 완료라고 말하기 전에 부하 시험을 한 번은 돌린다.
- 정상 생산 화면을 연 상태.
- 가장 큰 overview 화면과 detail 화면을 같이 연 상태.
- Historian collection이 켜진 상태.
- 운영 구성과 동일하게 redundant server 또는 standby node가 붙은 상태.
- 운영 중 engineering workstation 접속을 허용한다면 그 client도 붙인 상태.
- Channel 안에 느리거나 끊긴 device가 하나 있는 상태.
- Polling 중 recipe download, command sequence, batch transition이 발생하는 상태.
이때 driver request rate, timeout count, response time, communication server CPU를 기록한다. 완벽한 network에서만 숫자가 괜찮다면 scan class 설계가 끝난 것이 아니다.
프로젝트 노트에 남길 항목
Driver channel이나 OPC UA subscription group마다 짧게라도 기록한다.
- 포함된 device와 예상 protocol path.
- Scan class와 각 class에 들어가는 tag 종류.
- Priority 또는 load-shedding 동작.
- Timeout과 retry 설정.
- Tag 종류별 stale-data threshold.
- 최악 화면과 disconnected-device 시험 결과.
단순 tag count보다 이런 기록이 더 쓸모 있다. 다음 engineer가 어떤 데이터는 반드시 빨라야 하고, 어떤 데이터는 의도적으로 늦춰도 되는지 바로 알 수 있다.