프로젝트 소개
작년에 같이 공모전에 나간 친구가 공장을 원격으로 관리하는 웹 프로그램 제작을 맡게되었는데 거기서 서버를 만들 사람이 필요하다고 하여서 참여하게 되었다. 간단하게 프로젝트 얘기를 하자면 공장에서 돌아가는 기계를 관리하는 PLC가 있고 이 PLC를 웹 서버를 통해서 원격으로 관리하는 프로그램이다. 촉박한 제작 기간으로 인하여 공모전 참여로 인해 조금이나마 익숙한 Node.js를 이용하여 서버를 제작하기로 하였다.
주요 기능
- Modbus TCP/IP 를 이용하여 PLC와 일정 주기마다 통신
- 각 페이지에 맞는 데이터를 PLC에서 받아온다.
- 페이지에서 모달 창이 열리면 해당 모달창에 맞는 데이터를 PLC에서 받아온다.
- PLC에 있는 데이터를 가지고 로그 생성한다.
- 현재 운전 상태를 나타내는 값을 PLC로 부터 읽어온다.
- 알림 발생 상태를 PLC로 부터 받아온다.
- 읽기/쓰기를 통해서 PLC와 서버가 서로 상태를 확인한다.
- Socket.io를 이용한 프론트와 서버의 통신
- PLC로 부터 받은 데이터/상태나 혹은 DB 값, 메세지 등을 socket 통신을 이용해서 전달한다.
- 원격 관리를 위한 프론트에서의 입력을 받아서 그 값이나 상태를 서버로 전달하고 서버는 처리 결과를 다시 프론트로 전달한다.
- 데이터베이스에 알람 메세지 및 알람 업데이트, 로그 생성
- PLC로 부터 읽어온 데이터 값의 변화에 따라서 DB에 알람 생성 혹은 알람 업데이트를 한다.
- PLC로 부터 받은 수압 데이터를 가지고 로그를 생성하여 DB에 저장한다.
- Modbus 통신 연결 문제 발생시 재연결
- 위 과정 중 PLC와의 연결이 모종의 이유로 끊어졌을시에 일정 주기마다 다시 PLC와의 연결을 시도한다.
※ 각 Interval들의 주기는 다음과 같다.
page data interval : 3.7s
logging data interval : 1.1s
alarm data interval : 1.7s
modal data interval : 3.1s
alive signal intreval : 2.3s
drive mode interval : 2.9s
plc reconnect interval : 60s
개발 중 문제점 및 해결책
위 기능들을 개발하다 발생한 문제점과 그에 대한 해결책을 얘기해본다.
※ TransactionTimeout
해당 에러는 read or write 동작을 위해서 Buffer에 원하는 동작을 정의한 후에 tcpport를 통해서 plc에 전달하는 과정까지 걸리는 시간이 timeout으로 설정한 시간보다 오래걸리면 나오는 에러이다.
※ PortNotOpen
해당 에러는 상대 Client로부터 close, error와 같은 이벤트를 받은 상태에서 해당 Client에게 write하는 동작을 취하면 나오는 에러이다.
주의!!
위 에러에 대한 내용은 작성자가 라이브러리 코드를 보고 분석한 내용이라 틀릴 수 있음
Modbus 통신 문제
-
- Modbus 프로토콜을 이용하여 PLC와 통신시 반복적으로 TransactionTimeOut 에러가 나오는 문제가 발생
- 페이지 이동, 입력, Interval 주기가 같을 때 등 특정 상황에서 특히 더 자주 발생하는 것으로 파악
- 하나의 Modbus 자원을 가지고 통신을 하는데 통신 처리 중 같은 자원으로 다른 요청이 들어와서 생기는 문제로 파악(뇌피셜)
- 그리고 더 나아가서 해당 문제가 발생하고나서도 문제가 해결되기 전에 짧은 주기로 인하여 다른 요청들이 계속 실행되어서 연결 자체가 끊어지고 서버가 다운되는 문제 발생
- 문제 해결을 위해서 isRunning, isConnected와 같은 Flag를 만들어서 연결이 끊어졌을 때, 다른 요청을 처리 중일때는 Modbus 자원을 사용하지 않고 넘어가는 방식 사용
- Modbus 통신 자원 분배 문제
- 위의 Flag 방식을 사용하여 TransactionTimeOut에러가 나오는 것은 거의 해결하였지만 Modbus 자원 분배 문제 발생
- 위 방식에서는 Flag를 통해서 에러는 안나오지만 문제 상황때 문제 해결까지 기다리는 것이 아니라 그냥 return을 하여 해당 메서드에서는 빈 배열을 반환시키고 다음 주기의 메서드에서 값을 구하는 방식으로 동작하기 때문에 발생한 문제로 파악
- 근본적인 원인으로 Interval 간의 주기가 같은 것과 다른 자원이 Modbus 통신 자원을 사용 중일때 기다리지 않고 다음 주기로 넘어가는 것으로 파악
- 그래서 Flag 방식을 보완하기 위해서 방법을 찾아보던 중 async-mutex라는 라이브러리가 있다는 것을 알게되어 isRunning 대신 mutex를 사용하여 다른 요청이 자원을 사용 중이면 기다리게 만들고 각 Interval간 주기를 전부 다르게 하여 문제 해결
- Interval로 인한 메서드 중복 실행 문제
- 기존의 방식이 PLC와의 연결 여부에 상관 없이 계속 Interval을 통해서 메서드들을 이벤트 큐에 넣는 방식이였는데 이 방식이 평소에는 괜찮지만 PLC와의 연결이 끊어지면 필요 없는 메서드들이 게속 이벤트 큐에 등록되어 정작 가장 중요한 PLC 재연결 메서드가 의도대로 실행되지 않는 문제가 발생
- 원래는 기존의 Interval을 통해서 메서드 실행전 PLC와의 연결이 끊어진 상태면 재연결을 시도하고 아니면 Modbus 자원을 그대로 받아서 통신하는 방식으로 연결을 유지
- 이때 각 메서드에서 Modbus 자원을 받는 것을 반복문을 통해서 최대 5번 반복하고 재연결 메서드 안에서는 재연결 시도를 3번 반복하는 방식으로 동작 즉 Modbus 자원을 받는 반복 한번당 최대 재연결을 3번 시도한다.
- 문제는 PLC와 연결이 끊어진 상태에서 하나의 메서드 실행전에 Modbus 자원을 받기를 5번 모두 시도를 하고 다음 메서드로 넘어가서 다시 5번 시도하는 방식으로 돌아가지 않고 이벤트 큐에 너무 많은 메서드들이 등록되어 각 메서드에서 반복문이 다 돌지 못하고 1번씩만 실행되고 다음 메서드의 첫번째 시도로 넘어가는 문제가 발생.
- 그리고 해당 문제가 쌓여서 궁극적으로는 PLC가 다시 켜저도 재연결이 바로되지 않고 일정 시간(10분 이상)이 소요, 또한 너무 많은 재연결 시도로 인하여 TransactionTimeOut 에러와 PortNotOpen 에러가 발생하여 서버가 다운되는 경우도 발생
- 그래서 Flag를 통해서 PLC와의 연결이 끊어짐을 감지하면 기존의 Interval들은 전부 clearg하고 재연결을 시도하는 Interval을 따로 만들어 해당 Interval만 돌아가도록 만듬
- 즉 기존의 Interval에 PLC와의 통신과 재연결 시도까지 책임이 있었다면, 재연결을 시도하는 Interval을 만들어서 기존 Modbus 자원 사용을 하는 Interval은 끊김 감지만 하고 clear한 뒤 재연결 Interval에서만 재연결을 시도하도록 책임을 나누어서 문제를 해결
- PLC와 재연결시 연결 시간 오래 걸림
- 3번의 문제 해결을 과정을 통해서 재연결 자체는 안정성 있게 잘 되지만 재연결까지의 시간이 오래걸리는 문제가 남아있음
- 이 문제는 PLC가 연결되어 있을때 이벤트 큐에 등록된 메서드들을 전부 처리하고 재연결 시도를 하기 때문에 발생하는 문제로 파악. 즉 PLC가 연결된 기간이 길수록 재연결까지 걸리는 시간이 길어질 수 있다는 가능성 발생
- 이를 해결하기 위해서 PLC 재연결 Interval에게 process.nextTick을 이용하여 현재 실행중인 이벤트 루프가 끝나고 다음 루프 시작때 바로 재연결을 시도하는 것으로 문제 해결. 이를 통해서 기존에 7분 넘게 걸리던 첫 재연결 시도를 30~60초로 줄여서 약 86% 개선
- 또한 PLC 재연결 메서드에서 Modbus를 통한 재연결 자체가 2분 걸리는 문제가 있었음.
- 이 문제는 connectTCP API(Modbus를 이용한 PLC연결 API)를 호출하기 전 Modbus 객체에 timeout을 5초로 설정하여 문제를 해결. 이를 통해서 기존에 2분 걸리던 timeout을 5초로 줄여서 재연결까지 걸리는 전체 시간을 획기적으로 줄임.
- 또한 이 문제를 해결하면서 로컬에서와 서버 환경에서의 timeout 시간이 다르다는 것을 알게 되었는데 이는 Modbus 라이브러리의 구현 방식으로 인한 것으로 파악. Timeout을 따로 설정하지 않으면 라이브러리에서 운영체제에 따라서 Timeout시간을 다르게 설정한다는 것을 알게 되었음. 예를 들어 Mac 운영체제에서는 timeout이 약 7~8초 정도 걸리지만 cafe24 호스팅 환경에서는 2분이 걸림.
느낀 점
짧은 시간내에 실제로 사용할 수 있을 만한 프로그램을 만들면서 다양한 문제에 부딪혔다. 설계와 모르는 부분(Modbus protocol)에 대한 공부를 할만한 시간이 나오지 않아서 개발부터 하면서 설계와 기반 지식에 대한 중요성을 느끼게 되었다. 또한 공유 자원을 보호하는 다양한 방법에 대해 생각해보고 구현해보는 과정을 통해서 공유 자원에 대한 중요성과 개인 프로젝트나 과제 프로젝트에서는 크게 중요하게 생각하지 않았던 작은 부분에서 발생한 문제가 서버에 큰 문제를 발생하는 것을 보고 공유 자원에 대한 중요성을 다시 한번 깨닫게 되었다.
'Node.js(Express)' 카테고리의 다른 글
| [Node.js] 게시판 글 수정하기(사진 포함) (0) | 2024.02.07 |
|---|---|
| [Node.js] SNS 만들기 - Multer로 Multipart/Form-Data로 사진 전송 게시글 작성 (0) | 2024.02.02 |
| [Node.js] SNS 만들기 - Nodemailer를 이용한 사용자 인증 (0) | 2024.01.22 |
| [Node.js] JWT 사용하기 - access token, refresh token (0) | 2024.01.20 |
| [Node.js] JWT에 대해 알아보기 (0) | 2024.01.18 |