반도체 산업의 물류 자동화를 위한 필수 요건 중 하나는 반도체 장비와의 실시간 통신이며 반도체 장비와의 실시간 통신은 SECS 표준 프로토콜을 이용합니다.
물류 자동화 서버 엔지니어로 일하며 경험하고 개인적으로 개선되었으면 하는 부분의 개선을 통해 반도체 장비와 통신하며 메세지와 매핑된 객체를 이용하여 Byte를 Object로 변환하는 서버를 개발하고 그에 대한 기록을 남겨보려고 합니다.
반도체 장비와의 통신은 시나리오 기반이며 시나리오는 메세지들의 통신으로 이루어져 있습니다.
Send/Reply 과정을 통해 메세지를 송수신하며 시나리오를 진행합니다.
Send 메세지를 수신하면 그에 맞는 Reply 메세지를 응답해야 하고 이 과정에서 타임아웃이 적용되며 default timeout은 보통 5초로 설정합니다. 타임아웃을 초과하면 시나리오 자체가 중단되어 버리기 때문에 이는 생산성에 큰 영향을 줄 수 밖에 없었고 그래서 기존 서버는 Send 메세지를 수신 후 즉시 Reply 메세지를 발송하고 Send 메세지의 정보를 메인 서버로 보내주는 방식을 적용했습니다. 그러다 보니 Convertion Server의 스레드 처리 시간에 따라 메인 서버로 넘어가는 메세지의 순서가 역전되는 상황이 발생하는 경우가 있었습니다.
이와 같은 문제를 개선하기 위해선 메인서버의 작업이 종료된 후 작업 결과에 따른 reply가 가장 이상적이나 네트워크의 지연이나 처리 속도 등에 따른 영향으로 timeout이 발생할 것 같아 메인서버에서 메세지를 수신하면 Reply를 응답하는 방식으로 개선할 예정입니다.
1. 기본 개념
먼저 반도체 장비와의 통신 과정은 SECS 통신 인터페이스를 설계하고 그 구조에 맞게 데이터를 입력하여 전송하게 됩니다.
예를 들어 다음과 같은 인터페이스일 경우 반도체 장비와의 데이터 통신은 소켓 통신을 이용한 byte 전송을 하며 byte는 설계된 인터페이스를 SECS 프로토콜을 이용해 byte array로 변환하여 송수신 합니다.
다음은 예시입니다.
위 사진이 SECS 인터페이스이고 인터페이스를 SECS 프로토콜을 이용해 byte로 변환 및 16진수로 출력한 값이 아래 사진입니다.
먼저 메세지의 형식을 매핑하고 그 형식에 맞게 변환하는 방법은 XML, Json 등 다양한 방법이 있지만 저는 ORM 매핑에서 아이디어를 얻어 이러한 메세지 인터페이스와 자바 오브젝트를 매핑하여 데이터를 수신했을 때 매핑된 오브젝트를 찾고 해당 오브젝트를 생성하는 방식으로 적용해보려고 합니다.
사용 기술
- nio :논블록 IO를 이용해 네트워크 통신을 진행함.
- annotation binding : 어노테이션을 이용해 선언한 클래스를 매핑해 줌
- reflection : byte의 변환 데이터를 getter와 setter를 이용해 Object에 넣어줌
- proxy : byte를 수신했을 때 매핑된 Class를 찾아서 자동으로 Object를 생성하고 안에 값을 채워넣어줌
- multi threading : Processor와 MessageHandler, Listener, Sender 등 멀티 스레드를 통한 성능 향상
- cache 기능 탑재(개발 예정) : 자주 사용하는 메세지는 메모리를 유지하고 자주 사용하지 않는 메세지는 gc로 비워지도록 함.
- 서버 이중화(개발 예정) : 서버 이중화를 통해 평상시에는 로드 밸런싱을 통해 부하를 분산하고 한 서버가 다운되더라도 기능을 수행하는데 문제가 발생하지 않도록 하여 가용성을 높임.
1. message binding
SECS 프로토콜 상에서 메세지는 전송하려는 데이터의 목적에 맞게 다양하게 존재합니다.
메세지는 Header와 Body로 이루어져 있고 Header에서는 메세지의 형식을 지정하고 Body에 실제 데이터를 입력합니다.
Java Annotation을 이용하여 메세지를 매핑하게 된다면 이 Header를 통해 매핑된 메세지를 찾을 수 있습니다.
먼저 Java Annotation을 사용하기 위해 어노테이션을 생성하고 매핑하려는 메세지 오브젝트를 생성합니다.
어노테이션으로 작성된 자바클래스를 AnnotationBinder를 이용해 읽고 매핑 정보를 담은 객체를 만듭니다.
이 객체는 byte 형식 메세지를 Class 형식의 메세지로, Class 형식의 메세지를 byte 형식의 메세지로 변환할 수 있는 매핑 정보들을 갖고 있습니다.
이러한 매핑된 객체들을 MetadataImpl에 저장하여 MessageHandler가 필요할 때 마다 꺼내서 사용이 가능하도록 합니다.
매핑된 결과물
2. client networking
반도체 장비는 종류별로 여러 대가 존재하고 같은 종류(그룹)의 장비들은 모두 동일한 인터페이스를 적용합니다. 예 STK SECS, OHT SECS 등등.
그래서 같은 인터페이스를 적용하는 장비들은 모두 동일한 서버와 연결하여 매핑 클래스 생성을 최소한으로 하고자 했습니다. 이렇게 적용할 경우 Many-to-one 구성이 되며 메세지의 통신은 Send/Reply가 기본이기 때문에 일반적인 상황의 경우 Reply를 받지 않으면 다음 Send를 발송하지 않습니다. (시나리오 대로 메세지 통신이 이루어 져야 하기 때문)
한 쪽의 과도한 Send로 인해 스레드가 처리 가능한 트래픽을 초과하여 Queue에서 메모리 오버플로우가 발생할 확률이 낮을 것으로 보고 Non Block I/O로 개발하였습니다.
Acceptor와 Processor를 분리하여 소켓 연결 요청과 입출력 처리 스레드를 분리하여 개발하였고 Processor는 각각의 연결된 반도체 장비의 I/O를 담당하며 이는 메세지 브로커의 역할과 비슷합니다.
또한 서버 모드 선택 기능을 개발하여 다양한 환경에서 원하는 기능만 적용하여 사용할 수 있도록 했습니다.
networking mode
- server mode : 서버 모드일 경우 연결된 클라이언트의 정보를 관리하고 , manage control message & auto reply, data message auto reply 등의 기능을 제공함.
- broker mode(개발 예정) : 클라이언트로 부터 받은 메세지를 바로 변환하여 host한테 보내는 오직 메세지 미들웨어 역할만 하는 성격이 더 강한 순수 브로커 역할만 수행하는 모드
active mode
- active(개발 예정) : 클라이언트의 역할을 수행함. SocketChannel.connect()를 통한 커넥션을 진행
- passive : 서버의 역할을 수행함. ServerSocketChannel.accept()를 통한 커넥션을 진행
Acceptor 클래스는 클라이언트 소켓이 요청한 accept를 처리하거나 active 모드일 경우 클라이언트의 역할을 수행하기 위해 accept 요청을 서버 소켓으로 시도합니다.
클라이언트로부터의 연결을 accept 하고 연결된 소켓을 이용하여 I/O를 담당할 Processor를 1:1 매칭 시킵니다.
프로세서는 호스트 서버로부터 받은 메세지를 변환하여 장비로 보내거나 장비로 부터 받은 SECS 메세지를 변환하여 호스트 서버로 전송하는 역할을 담당합니다.
3. byte converting
반도체 장비로부터 메세지를 수신하면 ConversionChannel의 Queue에 메세지를 추가하고
MessageHandler는 메세지를 꺼내 변환 작업을 수행한 후 호스트 서버로 발송합니다.
변환 과정 실행 결과
개발 예정인 기능들과 디테일한 예외 처리 등 추가 개발해야 할 부분들이 아직 남아 있기 때문에 틈틈이 개발하며 지속 업데이트 할 수 있도록 하겠습니다.
'project' 카테고리의 다른 글
[C++] 에이스타(A*) 알고리즘을 구현한 최단 경로 이동 시뮬레이션 개발 (0) | 2023.07.12 |
---|---|
[Go] Golang을 이용한 칼만 필터 적용 구현 및 시뮬레이션 (0) | 2023.07.11 |
[Project] 오픈 API 데이터 통합 수집 배치 프로그램 (0) | 2022.09.29 |
[Project] Develop Database Middleware server project (0) | 2022.07.14 |