PLC의 reject counter가 12에서 19로 뛰었는데, SCADA 트렌드는 12 → 19로 한 번에 올라간 것으로 보였다. 회선에서 값이 유실된 게 아니다. 클라이언트가 중간 값을 남겨 달라고 요청하지 않았을 뿐이다. 이 동작은 monitored item의 숫자 세 개가 정하는데, 대부분은 아무도 일부러 설정하지 않는다.
OPC UA Part 4(Services 규격)는 이 값들을 MonitoringParameters라고 부른다. samplingInterval, queueSize, discardOldest 플래그, 그리고 DataChangeFilter다. Sampling과 publishing은 사람들이 흔히 다투는 설정이고, queue는 빠른 전환을 조용히 삼키는 설정이다.
같은 숫자가 아닌 숫자 세 개
Sampling, publishing, queue size를 "더 빠르게"로 뭉뚱그리면 위의 reject counter 문제가 나온다. 셋은 다른 질문에 답한다.
| 파라미터 | 의미 | 답하는 질문 |
|---|---|---|
samplingInterval(item별) | 서버가 source value를 확인하는 주기 | 서버/PLC가 이 속도를 실제로 감당하는가 |
| Publishing interval(subscription별) | subscription이 notification을 내보내는 주기 | 클라이언트가 고르게 받는가, burst로 받는가 |
queueSize(item별) | publish 사이에 대기할 notification 개수 | 중간 값이 필요한가 |
discardOldest(item별) | queue가 찼을 때 무엇을 버릴지 | 최신 값을 남길지, 순서를 남길지 |
| DataChangeFilter | 어떤 변화만 notification으로 만들지 | 노이즈와 의미 있는 변화를 나눴는가 |
값이 빠진다고 queueSize를 1로 둔 채 publishing interval만 줄이면 publish 사이의 burst에는 아무 소용이 없다. Queue는 여전히 값 하나만 담는다. 클라이언트가 더 자주 publish할 뿐이다. Publish 두 주기 사이에 변화 열 개가 들어오고 queue가 하나만 담으면, publish를 아무리 빨리 해도 아홉 개는 사라진다.
위 표의 "item별"에 주의한다. samplingInterval과 queueSize는 subscription이 아니라 각 monitored item에 설정한다. 같은 subscription 안에서도 빠른 counter와 탱크 레벨에 다른 파라미터를 줄 수 있고, 줘야 한다.
Live 값은 queue size 1이 맞는 기본값이다
대부분의 SCADA 포인트는 live 상태값이다. 운전자는 지난 화면 갱신 이후의 모든 값이 아니라 지금 값과 그 품질을 본다. 이런 값은 queueSize 1이 맞다. 더 키우면 서버 메모리만 쓴다. 다음이 해당한다.
- Overview 화면의 탱크 레벨.
- 현재 운전 여부만 쓰는 모터 running feedback.
- 천천히 움직이는 온도.
- 어차피 히스토리언이 별도로 수집하는 HMI 표시용 값.
queueSize 1에서도 물리는 게 하나 있다. Quality다. 통신이 5초 끊겼다가 들어온 새 Good 값이, 그 사이 값이 Bad/Uncertain이었다는 사실까지 지워서는 안 된다. 히스토리언이 기록이라면 StatusCode 변화도 notification으로 잡히도록 구독해야 한다. DataChangeFilter의 Trigger 설정(StatusValue냐 StatusValueTimestamp냐)이 이걸 정한다.
순서가 실제로 중요한 태그만 queue를 키운다
'최신 값'만으로 부족한 태그는 몇 개뿐이다. 모든 포인트를 부풀리지 말고 그런 태그에만 깊은 queue를 준다.
- Reject가 몰릴 때 튀는 counter(도입부의 그 값).
- Auto cycle 시작 중 여러 상태를 지나가는 step number.
- 1초 안에 warning → fault → reset으로 바뀌는 diagnostic word.
- MES나 report가 읽는 batch phase 전환.
- 시운전 중 지켜보는 고속 test tag.
각각 최악의 burst를 숫자로 적어 둔다. 설비가 2초에 상태를 20번 바꿀 수 있고 publish가 1초에 한 번이면 queueSize 2로는 못 담는다. publish 사이 예상 변화 하나당 슬롯 하나에 여유를 더한 정도가 필요하다. 그리고 서버가 실제로 준 값을 확인한다. CreateMonitoredItems는 RevisedQueueSize와 RevisedSamplingInterval을 반환하고, 서버는 요청보다 적게 줄 수 있다. 요청값이 아니라 revised 값을 기록한다.
Discard policy: discardOldest는 진짜 결정이다
Queue가 차면 서버는 무언가를 버린다. discardOldest = true(기본값)는 queue에서 가장 오래된 notification을 버리고, false는 들어오는 값을 버린다.
discardOldest | 맞는 경우 | 대가 |
|---|---|---|
true(기본값) | 현재값을 좇는 live 표시 | 중간 이력이 사라진다 |
false | sequence의 앞 순서 보존 | 클라이언트가 실제 공정보다 늦어질 수 있다 |
대부분의 live HMI 값은 true가 이해하기 쉽다. 화면이 최신 상태로 수렴한다. SOE(sequence of events) 작업에서는 false가 첫 fault 전환을 남기지만, 복구가 느리면 화면이 오래돼 보인다. 어느 쪽이든 중요 태그라면 이유 없이 벤더 기본값에 두지 않는다.
사람들이 놓치는 부분: 서버가 버렸다는 걸 알려 준다. Data change가 버려지면 OPC UA는 해당 queue에서 다음에 전달되는 값의 StatusCode에 Overflow InfoBit을 세운다(Part 4의 DataChangeNotification 처리). 클라이언트는 별도 서버 카운터 없이도 monitored item별로 손실을 감지할 수 있다. 단, StatusCode를 Good/Bad로 뭉개지 않고 InfoBits를 실제로 읽어야 한다. 드라이버가 severity만 남기고 나머지를 버리면 overflow 플래그를 못 보고, 버려진 값이 깨끗한 데이터처럼 보인다.
"가끔 값이 빠진다"를 실제 티켓으로 만드는 진단
Queue 문제는 재현 안 되는 간헐적 데이터 손실처럼 보인다. 다음을 시운전 화면이나 유지보수 문서에 남기면 추적된다.
- Subscription 개수와 monitored item 개수(서버가 광고하는
MaxMonitoredItemsPerSubscription과 비교). - Revised publishing interval과 keep-alive count.
- 늦은
PublishResponse또는 늘어나는 publish request backlog. - 서버가 제공하는 queue overflow counter, 그리고 Overflow InfoBit을 달고 온 값의 수.
- 거절된
CreateMonitoredItems요청(서버가MaxMonitoredItemsPerCall이나 세션 한도에 걸림). - 클라이언트 수신 queue 깊이 또는 처리 지연.
- Source timestamp와 client receive time 차이.
부하 시험은 태그 하나가 아니라 실제 조합으로 한다. 빠른 test value를 바꾸면서 가장 무거운 HMI 화면을 열고 히스토리언 수집도 같이 돌린다. 화면 여러 개를 열 때만 overflow가 늘면 PLC 태그가 아니라 클라이언트 처리 경로가 못 따라오는 것이다.
Alarm은 빠른 Boolean이 아니다
알람의 active/inactive Boolean을 data change로 구독하면 상태는 얻지만 event는 못 얻는다. Condition ID, acknowledge, 전환 detail 같은 알람 이력에 필요한 정보는 담기지 않는다. 그건 Event 모델(Part 9, Alarms & Conditions)에 있고, DataChangeFilter가 아니라 EventFilter를 쓰는 event monitored item으로 전달된다.
알람이 많은 사이트에서는 다음을 확인한다.
- Event subscription을 data subscription과 별도로 잡았는가.
- Acknowledge, return-to-normal, shelving이 모두 timestamp와 함께 남는가.
- Event queue 동작과 historical event가 단절을 견디는가(시험할 것).
- HMI alarm summary가 sampled Boolean 하나에 기대지 않는가.
알람 순서가 중요하면 알람 경로를 알람 경로로 시험한다.
느낌이 아니라 기록을 남기는 시운전 시험
Test tag 두 개면 대부분 잡힌다.
- 1초마다 1씩 증가하는 태그.
- 최대한 빠르게 10번 증가하는 burst 태그.
- 운영에 쓸 파라미터 그대로 구독한다(요청값이 아니라 revised 값).
- Source timestamp, value, StatusCode(InfoBits 포함), receive time을 기록한다.
- 가장 무거운 HMI 화면과 히스토리언 collector를 동시에 켠다.
- Reconnect 복구가 요구 사항이면 시험 중 client를 끊고 다시 붙인다.
- 예상 증가 횟수와 실제 수신 횟수를 비교하고, Overflow 비트를 달고 온 값의 수를 센다.
결과에는 어떤 변화가 의도적으로 버려졌고 어떤 것이 문제인지가 적혀야 한다. "화면에서 대충 맞아 보였다"는 시운전 기록이 아니다.
결국 핵심은 queue 동작을 각 태그의 용도에 맞추는 일이다. Live 표시, 히스토리언 수집, 알람/event, sequence 진단은 서로 다른 파라미터를 원한다. Class로 나누고 각 class에 부하를 걸어 시험한다. 기본값은 당신의 공정이 아니라 서버 벤더가 고른 값이기 때문이다.