← 전체 글
네트워킹/약 16분 읽기/— 조회

DNP3가 프레임을 흘릴 때, 애플리케이션 계층 그만 뒤지고 한 층 내려가라

멈추는 DNP3 회선, 흘린 프레임, CRC 오류는 데이터 링크 계층에서 잡는다. 주소, 확인 서비스, 재시도·타임아웃, keep-alive 튜닝.

네트워킹SCADA문제 해결시운전태그

모두가 존재를 잊는 계층

DNP3 문제 해결은 대부분 클래스, 이벤트, 비요청 응답 이야기다. 이것들은 모두 애플리케이션 계층에 산다. 그 아래에 DNP3 데이터 링크 계층이 있고, 회선이 프레임을 흘리거나 멈추거나 CRC 오류를 남길 때 애플리케이션 계층으로는 고칠 수 없다. 한 계층 아래로 내려가야 한다.

데이터 링크 계층은 세 가지 일을 한다. 각 프레임을 특정 국(station)으로 주소 지정하고, 각 프레임을 CRC로 검사하며, 필요하면 잃어버린 프레임을 confirm하고 재전송한다. 깨끗한 유선 네트워크에서는 거의 무시해도 된다. 하지만 무선, 전용선, 멀티드롭 시리얼 루프에서는 데이터 링크 설정이 회선의 안정 여부를 좌우한다. 잘못 잡으면 회선은 평생 재전송만 하며 산다.

이 모든 것은 IEEE 1815(DNP3 표준)에 들어 있다. 클래스 폴링과 같은 문서, 다만 무선 경로가 흔들리기 전까지는 거의 아무도 펼치지 않는 장(章)이다.

소스와 목적지 주소

모든 DNP3 프레임은 16비트 소스 주소와 16비트 목적지 주소를 담는다. 마스터에 주소가 있고, 각 outstation에 주소가 있으며, 모든 회선의 양쪽 끝에서 서로 일치해야 한다.

흔한 실패는 지루하고 놓치기 쉽다.

  • 소스와 목적지가 뒤바뀜. 마스터는 outstation 4와 통신하도록 설정됐는데 outstation은 자신을 주소 5라고 알고 있으면, 오류 메시지가 아니라 침묵이 나온다. 아무것도 주소 지정되지 않았으니 아무것도 답하지 않는다.
  • 멀티드롭 회선의 중복 주소. 같은 주소로 답하는 두 outstation이 충돌해, 배선 결함처럼 보이지만 아닌 간헐적 잡음이 나온다.
  • 브로드캐스트 혼동. 0xFFF0–0xFFFF는 예약 주소이고, 0xFFFD·0xFFFE·0xFFFF가 브로드캐스트 목적지다. 실수로 이 중 하나를 자기 주소로 받은 outstation은 무시해야 할 프레임을 받아들인다. 유효한 국 주소는 0xFFEF(65519)에서 끝난다.

모든 국의 소스·목적지 주소를 포인트 맵 옆에 기록한다. 멀티드롭 루프에서는 주소가 가장 먼저 확인할 대상이다. 중복 하나가 루프 전체를 오염시키기 때문이다.

확인(Confirmed) 대 비확인(Unconfirmed) 데이터 링크 서비스

DNP3는 링크 계층에서 프레임을 보내는 두 가지 방식을 정의한다.

서비스동작언제 쓰나
비확인(Unconfirmed)프레임을 한 번 보내고 링크 계층 확인 없음신뢰할 수 있는 회선, 또는 애플리케이션 계층 confirm이 이미 커버할 때
확인(Confirmed)수신자가 각 프레임을 확인해야 하며 타임아웃 시 재전송최하위 계층에서 재시도를 원하는 잡음·손실이 많은 회선

여기에 함정이 있다. DNP3는 링크 계층과 애플리케이션 계층 양쪽에 confirm이 있다. 둘 다 켜면 모든 메시지가 두 번 확인되어 트래픽이 두 배가 되고, 느린 회선을 더 나쁘게 만들 수 있다. 대부분의 현대 시스템은 비확인 링크 서비스를 쓰고, 이벤트의 애플리케이션 계층 confirm에 의존한다. 데이터 손실이 실제로 문제가 되는 곳이 거기이기 때문이다.

확인 링크 서비스는 기본값이 아니라 의도적으로 쓴다. 애플리케이션 계층 타임아웃을 기다리기보다 재시도가 빠르고 국소적으로 일어나길 원하는, 물리적으로 정말 나쁜 회선에서 의미가 있다. 괜찮은 회선에서는 순수한 오버헤드다.

재시도와 타임아웃

링크 계층 확인이 켜져 있거나 애플리케이션 계층이 응답을 기다릴 때, 타임아웃과 재시도 횟수가 부하 상황에서 회선의 거동을 정한다. 이 손잡이들이 가장 자주 잘못 설정된다.

중요한 세 가지 설정.

  • 응답 타임아웃: 마스터가 요청을 포기하기 전에 응답을 기다리는 시간. 너무 짧으면 느린 무선 왕복이 아직 전송 중인데도 실패로 선언된다. 너무 길면 정말로 죽은 outstation이 폴 주기 전체를 멈춘다.
  • 재시도 횟수: 회선을 실패로 선언하기 전에 프레임이나 요청을 다시 보내는 횟수. 나는 2, 많아야 3으로 둔다. 멀티드롭 루프에서 너무 많으면 죽은 outstation 하나가 뒤의 모든 국을 몇 초씩 막는다. 영영 답하지 않을 국에 재시도 다섯 번은 매 스캔마다 타임아웃 다섯 번을 버리는 것이고, 그게 모든 스캔에 곱해진다.
  • 문자 간·프레임 간 타이밍(시리얼): 수신자에게 한 프레임이 끝나고 다음이 시작되는 지점을 알리는 간격. RS-485에서는 Modbus RTU와 똑같이 턴어라운드 타이밍과 상호작용한다.

핵심 긴장은 모든 폴링 프로토콜과 같다. 빠른 타임아웃은 반응이 좋아 보이지만 느린 회선에서 거짓 실패를 만든다. 느린 타임아웃은 참을성이 있지만 나쁜 국 하나가 스캔을 끌어내리게 둔다. 응답 타임아웃은 실제 가장 느린 회선의 왕복 시간에 여유를 더해 설정하며, 추측이 아니라 측정한다. 위성이나 store-and-forward 무선 경로는 몇 초일 수 있고, 유선 LAN은 밀리초다. 이것은 매뉴얼에서 베끼는 값이 아니라 물리 회선에 맞춰 조정하는 값이다.

Keep-alive와 죽은 링크 감지

TCP 기반 DNP3 링크는 outstation이 사라진 뒤에도 오랫동안 "연결됨"으로 보일 수 있다. 오래된 TCP 소켓은 침묵을 스스로 알아채지 못하기 때문이다. DNP3는 링크 계층 keep-alive(마스터가 주기적으로 보내는 상태 요청)를 정의해, 조용한 링크도 계속 시험받게 한다.

확인할 것.

  • keep-alive 주기를 수십 초 수준으로 잡아 — 나는 TCP outstation에 30초를 쓴다 — 조용하지만 끊긴 링크가 몇 분 뒤가 아니라 빨리 잡히게 한다. 주기는 트레이드오프다. 짧으면 실패를 더 일찍 잡지만, 조용히 두고 싶은 회선에 트래픽을 더한다.
  • keep-alive에 응답이 없을 때 마스터가 실제로 outstation을 오프라인으로 선언하고, 이를 운전원이 볼 수 있는 통신 상태 태그에 반영하는지 확인한다.
  • 시리얼 링크에는 오래될 소켓이 없지만 같은 발상이 적용된다. 평소 수다스러운 outstation이 조용해지면 integrity 폴이나 상태 요청으로 살아 있는지 확인한다.

끊겼는데도 "온라인"으로 보이는 링크는 오프라인으로 보이는 링크보다 나쁘다. 운전원이 오래된 데이터를 믿기 때문이다. keep-alive는 바로 그것을 막으려고 존재한다.

프레이밍과 CRC 오류

모든 DNP3 프레임은 CRC 블록으로 보호된다. 프레임이 손상되어 도착하면 데이터 링크 계층이 이를 거부하고, 설정에 따라 송신자가 재전송한다. CRC 오류 카운트가 오르는 것은 물리 문제의 가장 이른 경고다.

CRC·프레이밍 오류가 오는 곳.

  • 시리얼: 잘못된 baud rate, 잘못된 패리티, 아슬아슬한 RS-485 바이어싱·종단, 또는 잡음을 주입하는 접지 루프. 증상은 어떤 때는 통과하고 어떤 때는 실패하는 간헐적 프레임이다.
  • 무선: 페이딩, 간섭, 또는 잡음 바닥 근처에서 도는 링크. 오류가 계속 나기보다 날씨나 시간대에 몰려 나타난다.
  • TCP: TCP 자체 체크섬이 있어 드물지만, 불안정한 게이트웨이나 시리얼-TCP 변환기가 터널링 전 시리얼 쪽에서 프레임을 손상시킬 수 있다.

마스터나 게이트웨이가 링크 계층 오류 카운터를 노출하면 트렌드로 본다. CRC 오류가 서서히 오르는 것은 링크가 완전히 끊기기 훨씬 전에 무선 경로나 커넥터가 나빠지고 있다는 첫 신호일 때가 많다. 그 트렌드는 별도 진단 태그를 둘 가치가 있다.

시리얼 멀티드롭 특유의 문제

멀티드롭 시리얼 DNP3(한 RS-485 루프에 여러 outstation)는 모든 데이터 링크 문제를 하나의 공유 매체에 몰아넣는다. 몇 가지 규칙이 안정을 지킨다.

  • 루프는 마스터 하나만 구동한다. 같은 루프를 폴링하는 두 마스터는 충돌한다.
  • 모든 outstation은 고유 주소가 필요하며, 도면에서 가정만 하지 말고 실제로 확인한다.
  • 턴어라운드 타이밍은 다음 프레임이 시작되기 전에 각 outstation이 전송을 멈출 시간을 줘야 한다. RS-485의 Modbus RTU와 똑같다.
  • 재시도 횟수는 적당히 유지한다. 공유 루프에서 죽은 국 하나에 대한 공격적 재시도는 건강한 모든 국의 시간을 훔친다.

멀티드롭 루프가 "느리다"면, 원인은 대개 한 outstation이 반복해서 타임아웃되고 마스터가 매 스캔마다 그 국에 재시도 예산을 태우는 것이다. 아픈 국을 찾으면 루프 전체가 빨라진다.

시운전 체크리스트

위 계층을 믿기 전에 데이터 링크 계층부터 점검한다.

  1. 각 회선의 양쪽 끝에서 마스터와 모든 outstation의 소스·목적지 주소를 확인한다.
  2. 멀티드롭 루프에서는 모든 outstation 주소가 고유하고 브로드캐스트 주소로 설정된 국이 없는지 확인한다.
  3. 확인 대 비확인 링크 서비스를 의도적으로 정하고, 링크 계층과 애플리케이션 계층 양쪽의 이중 확인을 피한다.
  4. 응답 타임아웃을 가장 느린 회선의 측정 왕복에 여유를 더해 설정하고, 기본값을 쓰지 않는다.
  5. 재시도 횟수를 죽은 국 하나가 멀티드롭 루프를 멈추지 않을 만큼 적당히 잡는다.
  6. TCP 링크는 keep-alive 주기를 설정하고, outstation이 응답을 멈출 때 마스터가 오프라인으로 선언하는지 확인한다.
  7. 통신 상태 태그가 링크 건강을 반영해, 운전원이 오래된 데이터를 실시간으로 착각하지 않게 한다.
  8. 가능하면 링크 계층 CRC·오류 카운터를 물리 경로가 나빠지는 조기 경고로 트렌드한다.
  9. 주소, 서비스 종류, 타임아웃, 재시도 횟수, keep-alive 설정을 포인트 맵과 함께 기록한다.

정작 잠 못 이룰 링크 실패는 오프라인이 되는 쪽이 아니라, 커넥터가 부식하고 CRC 카운트가 오르는데도 아무도 트렌드하지 않은 채 "온라인"으로 버티는 쪽이다. 현장을 떠나기 전에 그 오류 카운터를 태그에 연결하라. 포인트 맵에서 한 점을 쓸 뿐이고, 그게 전화 한 통과 누군가 실행에 옮기는 오래된 값 사이의 차이다.