센로그

5. ZeroMQ 본문

CS/풀스택서비스네트워킹

5. ZeroMQ

seeyoun 2023. 10. 15. 16:28

◆ ZeroMQ란?

소켓 통신을 기반으로, 사용하기 편하게 만들어놓은 비동기 메시징 라이브러리.
다양한 형태와 방법, 서비스에 대해 메시지를 주고받을 수 있는 오픈소스 라이브러리이다.

 

결국 통신을 하다보니, 어느 정도 정해진 틀이 잡힌 것이다.

그래서 그 설계를 여러곳에 쓰고, 다시 쓰고 하다보니 ...

"이런 설계를 많이 쓸거면, 미리 라이브러리로 만들어놔서 편하게 쓰면 않을까?"

소켓을 밑에 깔고, 그 위에 1:N이나 M:N 통신을 쉽게 짤 수 있도록 미리 만들어놓은 게 ZMQ

 

설계 자체를 재활용하는 느낌

 


◆ 프로토콜의 위치

ZMQ의 등장에 대해 설명하기 위한 배경.

 

통신 프로토콜들은 어디에 위치할까?

 

 

과거) Kernel 에 위치

  • 전통적으로 OSI7 레이어에서, L1 은 하드웨어에 들어가고, L2/L3/L4 는 운영체제 안에 들어간다.
    따라서 TCP, UDP, IP 같은 프로토콜들은 운영체제 커널에 위치해 있었다.
  • 때문에 어플리케이션의 통신을 할 때, Socket API를 사용해서 커널(커널 내부의 TCP/IP 따위)과 어플리케이션을 연결해줬다.

 

현재) Application Layer에 위치

  • TCP/IP 이외에도 다양한 미들웨어, 플랫폼 sw등이 나왔는데, 그런것들은 주로 운영체제 상위에 있는 어플리케이션 계층에 존재한다.

 

 

위치에 따른 장단점

  • 성능:
    - 운체 안에 있는게 성능이 좋은 경우가 많다. 운체 커널은 수많은 전문가들의 리뷰로 개선해온, 믿을 수 있는 부분이기 때문. 따라서 메모리를 얼마나 빨리 많이 읽고 쓸 수 있는지,  계층 사이에 얼마나 많은 데이터를 주고 받는지에 관한 건 커널 안에서 처리할 때가 성능이 좋은 경우가 많다.
  • 개발 및 발전 용이성:
    - 그러나, 커널 안에 집어넣으면 개발 난이도가 올라감.
    - 그리고 운체는 누군가 소유자(MS, 애플.. 등) 가 있다는 것도 고려해야 함. 내가 새로운 통신 프로토콜을 만들고 싶더라도, 실제로 운체에 집어넣으려면 소유하고 있는 쪽에서 승인을 해줘야 하니까, 새로운 걸 넣기 어려움.
    - 또 유저 커뮤니티 같은걸 생각해봤을 때, 어플리케이션으로 구분하면 수많은 사람들이 함께 개발할 수 있고, 오픈소스화 할 수 있고, 수시로 업데이트할 수도 있다. 따라서 요즘은 (ZMQ처럼) 앱 형식으로 하는게 트랜드임.

 

★ 이번에 다룰 ZMQ 프로토콜은 운체 커널이 아닌, 어플리케이션 레이어 위에 존재한다.

 


◆ ZMQ 특징

  • Universal: 지원하는 언어와 플랫폼이 많당. C, C++, C#, Python, Java, Go, Java, Swift …많음. 짱많음.
  • Multi-Transport: 지금까지 사람들이 짜왔던 통신 프로그램을 좀 더 쉽게 만드는 게 ZMQ의 목적이라 했으니, 사람들이 현재 사용하고 있는 Transport 계층들 위에서 돌아갈 수 있다. TCP, UDP, ... 등을 지원한다는 뜻이다.
  • Smart: ZMQ의 클라-서버는, 1:1 당연 되고, 1:N도 별도의 작업 안해도 바로 된다. 추가로 다양한 편리한 기능을 제공한다. (비동기로 바꾸는 기능도 미리 다 만들어놨다. connection 여부와 관계없이 일단 보내기 누르고, 연결되면 보내지는 기능 자동으로 할 수 있음.)
  • 이외에도 오픈소스 커뮤니티가 활성화 되어 있고, 가이드와 예제가 많이 존재된다.

 


◆ ZeroMQ에서 Zero의 의미

  • zero broker (brokerless)
    브로커가 없다.
    "특정 서버가 반드시 있어서, 그걸 무조건 써야한다" 라는 게 없다는 .
    , “분산“ 형태이다. 정해진 내장이 없다~ 내가 정할 수 있고, 수시로 바뀔수도 있다.
  • zero latency
    지연이 별로 없고 빠르다.
  • zero cost
    공짜다.
  • zero administration
    지도감독할 대상이 없다.

 

기본적으로 비동기를 지원하며, 수많은 다른 sw들과 동시에 주고받을 수 있다.

여러 개의 분산된 컴퓨터들 위에서 내가 만든 프로그램들이 흩어져서 통신 가능.

 

※ ZMQ와 반대되는 서비스로 RabbitMQ가 있다.

RabbitMQ는 브로커가 있음.
중앙집중형 Broker 기반 메세징 라이브러리로, 중앙에서 모두에게 뿌리는 작업(대량 이메일/문자 발송 등)을 한다.

ex) 재난문자
특정 서버를 이용해 재난문자 보내면, 통신사의 서버에 전달되어서, 쌓아두고 있다가 보냄.
지역정보도 요청하면, 지역을 고려하여 보냄. 방송을 하는거임. Cell broad casting

서버가 있고, 오면 대기하고 있다가, 여기서 하나씩 끄집어내서 전달함.
전달되는 모든것들은 이 브로커를 통과함

 


◆ ZMQ Sockets

4장에서 배웠던 소켓은 TCP, UDP를 사용했는데, 얘네를 활용해서 1:1, N:1, 멀티스레딩 등 내가 원하는 기능을 직접 일일이 다 구현해야 했다. ZMQ 소켓은 이런 많이 쓰는 기능들을 편리하게 쓸 수 있도록 미리 구현하여 제공한다.(1:1뿐만 아니라 many-to-many에 관한 통신 기능을 기본적으로 제공한다~. (비동기적으로))

 

■ ZMQ 소켓?

ZMQ는 기존에 있던 소켓 API를 흉내낸 것이 많다.

  • 버클리 소켓 API에서의 소켓이라는 이름도 따왔고, 실제로 일부 소켓에서 했던 개념들을 제공해준다.
  • 안에 있는 정보도 사실상 버클리 소켓과 비슷하다. 메시지를 주고 받기 위한 큐가 있고, 이 큐를 관리함으로써 메시지를 주고 받는다.
  • 기존처럼 소켓을 만들고 없애는 과정도 있고, 코드상으로는 소켓을 열고 닫히기 전에 데이터를 주고받는게 일반적이다. (그러나 실제로는 레이어 간 비동기를 지원한다.) 
    소켓에 옵션도 줄 수 있다. 좀 더 재밌고 쉽게 되어있음. 기존 소켓 통신에서는 TCP인지 UDP인지와 같이 '주고 받는 방식'에 대한 옵션이 있었다면, ZMQ에서는 '통신 서비스 측면'에서의 옵션을 줄 수 있다.

 

 

 ZMQ 소켓의 비동기성!

두가지 측면에서 볼 수 있다.

  • 별다른 처리 없이도, 기본적으로 전송과 수신을 동시다발적으로 할 수 있다.
  • 기존 소켓 프로그래밍에서는, 연결과 해제 사이에 반복문이 돌아가서 메시지를 주고받았다. 따라서 와이파이가 바뀐다거나 해서 연결이 끊어지면 걍 처음부터 다시 해야 했음.
    그러나 ZMQ의 경우 꼭 그렇진 않다. L1이나 L2 연결이  끊어졌다거나, 아직 연결이 완료되지 않았어도, 어플리케이션 입장에서는 이와 상관없이 데이터 송수신을 진행하도록 함. 어플리케이션간 입장에서, 실제 연결 설정 해제 및 재설정과 상관없다는 것. WiFi가 끊어져서 다시 연결을 잡더라도, 사용자가 열심히 적어놨던 게 없어지지 않고 쌓여있다가 연결되면 보냄.

 

 

 

바인드나 커넥트는 누가 하나?

기존 소켓 프로그래밍에서, 바인드는 서버에서 호출하고, 커넥트는 클라에서 호출했다.

일반적으로는 그렇다. 그러나 꼭 그렇지만은 않다는 게 ZMQ의 특징.

 

ZMQ는 분산 처리라고 했다. 반드시 어딘가에 고정된 서버가 존재할 필요는 없는 형태.
본인이 서버 역할을 하면서, 클라 역할도 하는 애들도 존재함. 또는 아예 서버, 클라라고 불리지 않는 애들도 존재한다는 것. 

 

이렇듯 ZMQ에서 서버-클라 구조가 없으면, 바인드는 누가 실행하고 커넥트는 누가 실행함

→  connect : 보통은 임시로 나타나고 시간이 지나면 없어지는 동적인 애들이 커넥트 하도록 하는 걸 권장함

  bind : 시간적으로 가장 오래 있거나, 다른 애들에 비해 잘 움직이지도 않고 유지되는 애들(마치 서버처럼, 그러나 서버 역할은 아닌)의 경우 바인드 하도록 하는 것을 권장함. (Most stable한 애들이 바인드 하도록 함. 딱 보기에 얘가 생긴 건 클라같긴 한데, 시간적으로 가장 오래 있다면? 얘가 바인드해야 한다는 것.)

 


◆ ZMQ 메시징 패턴들

ZMQ는 다양한 메시지 패턴들을 제공한다.

 

다음 세가지 메시지 패턴들에 대해 알아볼 것임.

  • Request-Reply
    : 전형적인 클라-서버 구조. 1:1, 1:N, N:1 다 지원 가능
    양방향 통신
  • Pub-Sub
    : 구독한 유저들에게 공지하는 방식.
    단방향 통신
  • Pipeline
    : 여러 유저들에게 순차적으로 작업을 받고(PULL), 전달하는 방식(PUSH)
    단방향 통신

 


◆ [ZMQ 패턴] Request-Reply 패턴

전형적인 클라-서버 구조

앞쪽에서 ZMQ에 대한 전반적인 이해 및 이론적인 부분에 대해서 알아봤다.

지금부터는 실질적인 코드들을 ZMQ 패턴별로 알아볼 것임.

 

우선 1:1 Request-Reply 패턴을 보자.

 

< 목적 >

1:1, 1:N 등 전형적인 서버-클라 구조의 통신을 구현하기 위한 패턴이다.

양방향 통신.

 

< 구현 방법 >

ZMQ에 미리 구현되어있는, REQ-REP패턴의 소켓을 사용할것임.

이때 클라는 기본적으로 동기적으로 작동한다. (하나 보내고 하나 기다리는거. 두개의 메세지를 연속으로 보내는 등의 다른 sequence가 실행되면 send와 recv의 호출에서 -1을 리턴한다.)

 

 

ex)다음 예제는 간단하게 클라가 "hello"를 보내면, 서버가 "world"를 돌려주는 코드를 ZMQ를 활용해 작성한 예제이다.

 

1. 서버 코드

  • 서버든 클라든, 기본적으로 zmq를 사용하려면 context 객체를 생성해야 한다. 

 

  • reply를 해줘야하는 서버쪽이므로, zmq.REP 방식의 소켓을 만든다.

 

  • 바인드할 때 사용된 *는 이 컴퓨터의 기본 IP주소를 의미하고, : 뒤의 숫자는 포트 번호이다.

 

  • 그리고 무한루프 안에서 메시지를 주고 받는다.
    메시지 받고, 출력하고, 1초쉬고, "World" 메시지 보내는 동작을 한다.

 

 

2. 클라 코드

 

  • 클라도 마찬가지로 context를 생성한다.

 

  • 소켓 생성시, 클라이므로 서버와는 다르게 zmq.REQ 방식을 쓰도록 한다.

 

  • 이후 커넥트해서, 바인드하고 있는 서버로 접속한다.

 

  • 반복문 안에서 "Hello"를 10회 보내고, 이때마다 돌아오는 응답을 받도록 한다. (동기식)

 

 

※ 위에서 구현한 Req-Rep 패턴을 1:N으로 발전시키려면 어떻게 해야 할까?
→ 아무것도 안해도 됨.
기본적으로 ZMQ에서 지원해줌. 위 코드 그대로 실행하면 클라 여러 개 동시에 연결하고 실행할 있음!!

 


◆ [ZMQ 패턴] Publish-Subscribe 패턴

어딘가에 구독을 하면, 거기서 구독자들에게 데이터를 뿌리는 것.

 

< 목적 >

publisher가 자신의 구독자들에게 업데이트된 정보를 일방적으로 배포하는 방식을 구현하기 위한 패턴이다.

 

이 패턴에 대해 몇가지 특징이 있다.

  • 기본적으로 Pub-Sub 쌍들은 비동기로 작동한다.
  • 원웨이 전달이다. pub은 send만 하고, sub은 recv만 한다. (클라쪽에서 send 하려고 하면 에러 뜸)
    → 그 순간에 그 기능에 대해서만 서버-클라 역할인 거지, 완전히 고정된 것은 아니다. 유연하게 생각해야 함!

 

 

< 구현 방법 >

서버-클라 구조에서는, 서버가 항상 먼저 살아났기 때문에 항상 서버가 바인드를 했었는데, 
이제부터는 조금 다르다.

"누가 누구에게 접근할 것인가?" 를 기준으로 바인드를 할 것임.

접근을 당하는 애들이 주로 바인드를 하고 기다리게 된다.

 

Pub-Sub 패턴에서는 퍼블리셔가 바인드를 한다. (퍼블리셔 == 서버인 것은 아니다.)

구독자들은 바인드하고 기다리고 있는 퍼블리셔에다가 커넥트를 한다.

그러면 퍼블리셔가 일방적으로(원웨이) 구독자들에게 정보를 푸쉬하는 방식이다.

이때 퍼블리셔는 모든 구독자들에게 같은 정보를 보내므로, 구독자가 원하는 정보만 받기 위해서는 소켓 옵션을 사용해 필터링해야 한다.

 

 

ex)

날씨를 주기적으로 방송하는 예시를 볼 것이다.

날씨 정보를 가지고있는 컴퓨터(Publisher)가 있고, 이 컴퓨터에 접속한 사용자들(Subscriber)에게 동일하게 날씨 정보를 보내도록 할 것임. 

 

이때 Pub및 Sub의 동작은 다음과 같다.

  • Publisher : 내가 보낼 날씨가 어느 지역의 날씨인지에 대한 zip 코드(우편번호) 정보가 있고, 온/습도를 보낼 것
  • Subscriber : 소켓 옵션을 줘서, 서버로부터 오는 정보 중에서 우리 지역(특정 zip 코드)의 날씨만 보도록 한다. 

ZMQ에서 이런 기능들을 미리 다 구현해놔서 쉽게 사용할 수 있도록 제공하고 있다.

 

 

1. Publisher 코드

 

날씨를 퍼블리시하는 서버 역할을 한다. 날씨는 그냥 확인용으로 랜덤 넘버 만들어서 제공한다.

 

  • context 만들고, 소켓은 zmq.PUB 패턴을 사용하도록 만든 후 바인드한다.

 

  • 무한루프 안에서 send_string()을 통해 문자열을 보낸다. 이때 클라들에 대한 정보는 따로 없고, 그냥 모든 클라들한테 같은 정보를 뿌린다.

 

 

 

 

2. Subscriber 코드

 

  • context 만들고, 소켓은 zmq.SUB 패턴을 사용하여 만든 후 퍼블리셔에 커넥트한다.

 

  • zip_filter라는 걸 사용한다. 날씨 서버가 보내주는 정보 중에서, 본인이 원하는 정보만 취사선택해서 받고 싶기 때문이다. 코드에서는, 만약 시스템에서 입력 파라미터를 입력했으면 그걸 쓰고, 안 줬으면 기본값으로 10001로 설정하도록 했다. 이 필터를 통과하는 경우에만 소켓의 recv 함수에 읽힌다.

 

  • setsockopt_string()을 통해서, 필터를 줘서 이에 해당하는 것만 읽도록 한다. 
    코드에서는 입력 파라미터(또는 10001번)와 zip code가 같은 정보만 읽어올 것이다.

  • for문에서 20번동안 반복하도록 한다. (서버에서 계속 랜덤으로 생산해내는 정보들 중에서, 내 zip code랑 맞는 게 나오면 받아오는 걸 20번 반복한다.)

 

  • 맨 마지막은 받은 온도들의 평균을 보여주는 코드임. (큰 의미는 없음)

 

< Subscriber가 원하는 정보만 선택적으로 수신하는 방법 >

subscriber 소켓에 옵션(setsockopt_string())을 줘서, 본인이 원하는 정보만 받도록 할 수 있다.
수신을 원하는 정보에 대한 필터를 설정하고, 이 필터를 통과하는 경우에만 소켓의 recv 함수에 읽힌다.

 

 

▼ 실행 결과

더보기

실행하면 이런 식으로 동작한다.

 

 


◆ [ZMQ 패턴] Pipeline 패턴 (feat. Pub-Sub 패턴)

여러 유저들이 병렬적으로 작업을 받고(PULL), 전달하는 방식(PUSH)

 

PUB-SUB과 비슷하지만 조금 다른 패턴이다.

PUB-SUB은 통상 PUB 하나이고 SUB이 여러 개였다면, PUSH-PULL은 파이프라인 형태로 나타나는 경우가 많다

※ 파이프라인 방식이란?
동시다발적으로 여러 개의 작업을 같이 실행하고, 그의 결과를 취합해서 하나의 결과를 가져오는 방식.

 

쉽게 말해, PUB-SUB에서는 1:N으로 퍼져나가는 모양이었다면,

파이프라인은 하나의 일을 쪼개는 과정(1:N)쪼개진 것들을 하나로 모으는 과정(N:1)이 있다.

  • Fan-Out : 하나의 일을 쪼개는 과정 (1:N)
  • Fan-In : 쪼개진 일들을 하나로 모으는 과정 (N:1)

 

이런 sw를 짤 때 유용한 ZMQ 패턴이 바로 파이프라인 패턴(PUSH-PULL 패턴)이다.

 

 

< 목적 >

 

여러 유저들이 병렬적으로 작업을 받고(PULL), 전달하는 방식(PUSH)을 구현하기 위한 패턴이다.

 

벤틸레이터가 세 워커에게 task를 PUSH하면, 세 워커는 이 task를 PULL하고, 처리한 결과들을 싱크에게 PUSH한다. 

싱크는 본인이 원하는 타이밍에 이들을 PULL한다.

원하는 타이밍이라는 것은, 정보를 받을 때 누구로부터 먼저 받을 것인지 조절할 수 있다는 뜻이다. (큐에 담아둠)

예를들어 Fair Queuing 같은 경우는 모두 동일한 순서로 받도록 하는 것. 특정 워커에게 먼저 받도록 설정할 수도 있다.

 

Push/Pull 소켓 쌍으로 단방향 통신에 사용된다.

 

< 구현 방법 >

클라들이 서버에 주기적으로 자신의 상태를 보내고, 서버가 이 정보를 다른 클라들에게 뿌리는 방식을 구현해보자.

 

우선 서버 및 클라의 동작은 다음과 같다.

  • 서버 : 
    클라들이 주기적으로 보고하는 상태 정보를 PULL한 후, 다시 모든 클라들에게 PUB한다.
  • 클라 :
    주기적으로 자신의 상태 정보를 서버에게 PUSH한다. 서버가 PUB한 전체 클라들의 상태를 SUB하여 수신한다.
    (예제에서는 본인이 PUSH한 정보도 예외 없이 수신하도록 한다.)

 

※ 참고
기능이라는 측면을 기억해야함. 기능에 따라 역할이 달라지는 것이다.
예제에서 서버는 풀¹한 정보를 퍼블리시² 할 것임. 동시에 기능이 2개 들어간 것이다.
→ 하나의 프로세스가 여러 개의 ZMQ패턴들을 가지고 있을 수 있다는 것을 잊지 말자!

 

 

이제 코드를 보자.

 

 

1. 서버 코드

매우 간단하다.

  • 두가지 기능을 가져야 함. publisher, collector
    따라서 각 기능을 가진 패턴을 사용해 소켓을 두 개 열도록 함.
    • publisher - 구독자들에게 정보를 퍼블리시 하는 기능. (zmq.PUB)
    • collector - 클라들의 상태 정보를 모아와서 관리하는 기능. (zmq.PULL)
  • 서버쪽에서 publisher와 collector을 각각 바인드함. ( 클라들은 살았다,죽었다하는 경우가 많을 것이기 때문.)
  • 반복문 안에서, collector가 PULL해서 받은 정보를 예의상 화면에 한번 보여준 후,
    publisher가 모든 클라들에게 PUB해줌

 

2. 클라 코드

 

 

  • 서버의 퍼블리셔에 구독할 subscriber 소켓을 만듦. (zmq.SUB 사용)
  • subscriber 소켓 옵션을 통해 특정 정보만 받을 수 있었는데, 예시에선 전부 받도록 함.
    참고) b' ' 는 뭐냐?
    • b는 이 다음에 오는 문자가 아스키코드라는 뜻임. 통신할 땐 유니코든지 아스키코든지 이런거 신경써야함
    • ' '는 오는 거 다 받겠다는뜻

 

  • 자기 정보를 푸시할 퍼블리셔 소켓(zmq.PUSH 사용)도 만들어서, 서버의 컬렉터에다 커넥트 해줌

 

  • 반복문 안에서, subscriber.poll은 내가 받을 데이터가 있는지 물어보겠다는 의미.
    수신 버퍼에 내가 받을 데이터가 있어? 확인해서
    - 있으면 바로 받고,
    - 없으면 100ms까지만 기다려보고 생기면 받는다. 
    zmq.POLLIN은 플래그. 수신 버퍼에 데이터가 있으면 true 반환

 

  • 그리고 만약 받을 게 없으면, 랜덤 넘버 하나 뽑은 후 이 값이 10보다 작으면 서버의 컬렉터에다 PUSH하도록 하는 예제 코드이다. (업데이트 내용 보고)

 


◆ [ZMQ 패턴] Dealer-Router 패턴

딜러들이 라우터에게 요청하면, 라우터가 이를 받아서 작업을 처리하고, 다시 돌려주는 형태.
이때 처리는, 라우터 본인이 직접 하거나, 다른 워커에게 맡긴다.

 

잘 이해가 안될 수 있으니 예시를 들어보자.

 

웹 서버의 경우 이런 구조에 해당할 수 있다.

웹 클라들이 많아서, 이 많은 애들이 보낸 요청들을 한 서버가 다 처리하기 힘듦!!

 수많은 웹 서버들이 일을 나눠서 똑같은 데이터로 똑같은 처리들을 하도록 한다. 

웹 브라우저들이 보낸 HTTP 요청을 일단 웹 서버 한 놈이 다 받아서 워커 중 하나한테 넘기고, 완료한 작업을 받아서 다시 클라에게 돌려주는 것. 어떤 워커에게 넘기든 같은 역할 할거니까 누구한테 넘기든 상관없음.(그렇지 않고 워커들이 기능이 다르다면, 적절한 워커한테 전달하면 됨.). 이때 웹 서버 한 놈이 하는 역할은 로드밸런서(워커들에게 최대한 균등하게 일 시키기)

 

< 목적 >

클라이언트와 서버의 관계가 N:1이고, 서버와 워커와의 관계가 1:N일 때 사용할 수 있다.

계층화된 느낌. 위에서 아래로 요청하고 다하면 다시 아래에서 위로 보내주는.

  • 라우터는 클라 N으로부터 받은 정보를 처리한 후, 다시 그 N으로 돌려주는 역할을 함. (어디서 보낸 건지 기억)
  • 딜러는 그냥 보내고 싶을 때 보내고, 처리 다 되면 받는 거.

 

클라들라우터 기능을 하고 있는 서버에게 요청을 것임. 그러면 서버에 있는 딜러가 클라로부터 받은 일을 워커에게 보내면, 워커가 일을 한 후 다시 라우터에게 돌려주고, 딜러는 다시 일을 요청했던 클라에게 돌려준다. (PUSH-PULL과는 다름. PUSH-PULL은 각자 본인 역할밖에 못함. 받는 애는 보내진 못함여기서는 서버의 딜러가 워커에게 요청을하면, 워커도 처리해서 딜러에게 보낼 수 있다. 그리고 다시 클라에게 돌려줌)

 

< 구현 방법 >

 

ex)

예제 코드에서 구현할 내용은 다음과 같다.

 

  1. 클라가 요청한 정보를 서버가 라우터 소켓으로 받는다.
  2. 이 정보를 프록시를 통해 라우터와 1:1연결한 딜러로 전달하고, 딜러는 누구든 상관없으니 적절한 워커에게 전달한다. (inproc; 컴퓨터 메모리를 통해 전달)
  3. 워커는 처리 후 다시 딜러에게 보내며(inproc), 딜러는 프록시를 통해 라우터에게 전달하고, 라우터는 다시 클라에게 전달하는 작업을 한다.

 

 

 

1. 서버 코드

서버 - 라우터 코드

 

 

 

  • frontend 는 클라와 메세지를 주고 받을 zmq.ROUTER 소켓으로 만들고,
    backend는 메모리를 통해 메세지를 주고 받을 zmq.DEALER 소켓으로 만듦.

 

  • inproc: 컴퓨터 안의 메모리를 사용해서 데이터를 주고받는 거. 예제에서는 얘네가 하나의 실행파일이기 때문에, TCP/UDP같은 복잡한 거 쓰지 않고 이걸 사용해서 백앤드로 바인딩 및 연결을 한다. 

 

  • For문이 지정한 워커 개수만큼 돌아가면서 워커를 생성하고, 시작시키고, 워커 리스트 에넣음

 

  • zmq.proxy : 서버 내에서, 라우터 소켓에서 받은 건 딜러 소켓으로, 딜러 소켓에서 받은 건 라우터 소켓으로 forward한다는 뜻. 다른 처리는 아무것도 안하고 걍 서로 전달만 해줌.

 

 

 

서버-워커 코드 및 메인

  • Init에서, 전달받은 워커의 id, 쉐어할 contex가지고옴. 컨텍스트는 서버에서 만든거 재사용함. 
    얘는 딜러역할만 함-백앤드로 연결.

 

이제 메인~

  • 워커를 스레드로 실행할건데, 몇 개의 워커를 띄울지 정해 놓음.(메인 아규먼트로)

 

  • 메인에서 띄워야 할 객체는 하나(라우터)이며, 라우터 안에서 워커 만들고, 시작하고, 리스트에 집어넣는 행위를 함.

 

 

 

2. 클라 코드

 

  • identify는 본인의 아이디를 의미. 

 

  • zmq.DEALER 패턴을 사용한 소켓을 만듦

 

  • zmq.Poller()을 만들고, socket 변수에 등록했다.
    이 의미는, 나는 지금부터 socket(딜러 소켓)에서 어떤 데이터든 온다면  그걸 읽을거야! 라는 선언.

 

  • reqs 변수를 통해 몇 개나 보냈는지 카운팅함. while문에서 딜러 소켓을 통해 본인의 요청을 라우터에 전달함. 
    코드의 경우, 본인의 몇번째 요청인지에 대한 변수 reqs를 전달함.

 

  • Poll은 내가 버퍼에 받은 게 있으면 끌고 오는 것. 근데 이때, 딕셔너리 형태로 저장했다?
    → 슬립 함수로 쉬는 동안 워커가 1개 이상의 결과를 돌려줄 수도 있으므로, 여러개를 처리하기 위한 목적. 
    그리고 나서 sockets로부터 하나하나 끄집어내서 읽는다.

 

※ 폴러 작동방식

(1)폴러 만들고, (2)본인이 읽고자하는 소켓과 이벤트를 등록하고, (3)읽어온다.

 

 

'CS > 풀스택서비스네트워킹' 카테고리의 다른 글

7. gRPC  (0) 2023.12.08
6. HTTP/1.1  (0) 2023.10.16
4. Socket  (0) 2023.09.30
3. OSI Arghitecture L4  (0) 2023.09.30
2. OSI Architecture (L1~L3)  (0) 2023.09.07
Comments