프로세스 간의 통신 : 서비스와 서비스가 서로 통신하기 위해서는 인터페이스(interface)가 존재해야 하고, 인터페이스가 요구하는 방식대로 커뮤니케이션해야 합니다.
동기 / 비동기 :
HTTP 프로토콜은 기본적으로 TCP(또는 UDP) 연결을 만들고, 이 위에서 요청에 따라 즉시 응답이 오는 형태로 구현이 되어 있습니다. 즉 동기적인 응답을 제공합니다.
세상에는 요청에 따른 응답이 즉시 도착하는 커뮤니케이션만 존재하지 않습니다. 문자 메시지를 생각해 보면 발신자는 수신자가 즉시 메시지를 보고 답장하리라고 기대하지 않습니다. 이러한 패턴은 비동기적인 커뮤니케이션입니다.
HTTP는 비동기 아닌가요?
HTTP는 컴퓨터와 컴퓨터 사이의 네트워크 통신이고, 이는 네트워크 지연에 따라 즉시 응답이 오지 않을 수도 있기 때문에 이를 비동기로 인식할 수 있습니다. 하지만 프로세스 간 통신의 관점에서 HTTP는 동기적인 메커니즘으로 분류합니다. 왜냐하면, 어쨌든 서로 통신하는 두 컴퓨터는 모두 켜져 있어야 하며, 클라이언트는 서버가 제 때 응답을 줄 것이라고 기대하기 때문입니다.
일대일 및 일대다 통신 :
뉴스레터 구독 서비스는 1:1로 커뮤니케이션하지 않고 구독자 모두에게 동일한 메시지를 제공하는 형태, 즉 일대다 커뮤니케이션 방식을 취합니다.
HTTP는 서버가 여러 클라이언트를 상대할 수는 있지만, 그것은 여러 번의 1:1 커뮤니케이션이지, 동시에 여러 클라이언트를 상대하는 1대다 커뮤니케이션이 아닙니다.
프로세스 간의 직접/간접 연결 :
중간에 메시지 브로커가 두 프로세스 사이에 위치해서 오고 가는 메시지 자체를 관리하는 형태의 연결 방식도 있습니다. 이 경우 비동기적인 처리는 물론이고, 설사 둘 중 하나의 프로세스가 실행 중이 아니더라도 서로 메시지를 주고받을 수도 있습니다.
대표적인 테이터 교환 포맷 JSON
JSON의 탄생 배경 : JSON은 JavaScript Object Notation의 줄임말로, 데이터 교환을 위해 만들어진 객체 형태의 포맷입니다.
전송 가능한 조건 (transferable condition)
- 수신자(reciever)와 발신자(sender)가 같은 프로그램을 사용한다.
- 또는, 문자열처럼 범용적으로 읽을 수 있어야 한다.
객체는 타입 변환을 이용해 String으로 변환할 경우 객체 내용을 포함하지 않습니다. JavaScript에서 객체에 메서드(message.toString())나 형변환(String(message))을 시도하면, [object Object]라는 결과를 리턴합니다.
이 문제를 해결하는 방법은 객체를 JSON의 형태로 변환하거나 JSON을 객체의 형태로 변환하는 방법입니다. 이를 위한 메서드는 다음과 같습니다.
- JSON.stringify : Object type을 JSON으로 변환합니다.
- JSON.parse : JSON을 Object type으로 변환합니다.
- 자세한 내용은 JSON 공식 문서를 참고하세요
let transferableMessage = JSON.stringify(message)
console.log(transferableMessage) // `{"sender":"김코딩","receiver":"박해커","message":"해커야 오늘 저녁 같이 먹을래?","createdAt":"2021-01-12 10:10:10"}`
console.log(typeof(transferableMessage)) // `string`
JSON으로 변환된 객체의 타입은 문자열입니다. 발신자는 객체를 직렬화한 문자열을 누군가에게 객체의 내용을 보낼 수 있습니다. JSON.stringify와 정반대의 작업을 수행을 하는 메서드 JSON.parse를 사용할 수 있습니다.
JSON.parse를 적용하는 이 과정을 역직렬화(deserialize)한다고 합니다.
JSON은 서로 다른 프로그램 사이에서 데이터를 교환하기 위한 포맷입니다.
JSON의 기본 규칙
동기식 요청 / 응답 통신 REST
REST는 HTTP로 소통하는 프로세스 간 통신 규약입니다. REST API는 웹에서 사용되는 데이터나 자원(Resource)을 HTTP URI로 표현하고, HTTP 프로토콜을 통해 요청과 응답을 정의하는 방식입니다. 현대에 있어서 HTTP 메시지의 body 부분을 JSON의 형태로 다루는 것이 보통이며, 이때 HTTP 헤더의 Content-Type의 값(MIME 타입)은 application/json으로 설정합니다.
REST의 장점 :
- 포스트맨, curl 등의 도구를 사용해 간편하게 테스트가 가능합니다.
- 요청/응답 통신을 직접 지원합니다.
- 시스템 아키텍처가 단순합니다.
REST의 단점 :
- 요청/응답만 지원합니다.
- 메시지를 주고받기 위해서는 클라이언트와 서버 프로세스가 둘 다 실행 중이어야만 합니다.
- 요청 한 번으로 여러 리소스를 조회하기 어렵습니다.
- 메서드만으로는 한 번의 요청을 통해 이루어지는 다양한 작업들을 대표하기 어렵습니다.
메시지 브로커를 이용한 비동기식 통신
- 요청을 보내는 즉시 수신자로부터 응답이 오길 기대하는 "동기적 방법"
> 클라이언트-서버 아키텍처의 REST(HTTP)가 대표적
- 요청을 일단 보내놓고 수신자가 받을 때까지 보관했다가 처리하는 "비동기적 방법"
> 수신자가 받기 전에 누군가는 메시지를 보관해놓아야 한다 → 메시지 브로커 (메시지 큐)
메시지 브로커가 필요한 이유 :
분산 애플리케이션에서 프로세스 간의 느슨한 결합(loosely coupled)을 제공하는 것이 가장 큰 장점입니다.
느슨한 결합 (loose coupling)이 주는 장점
프로세스 간의 의존성을 줄일 수 있음
- 시스템을 유지보수하기 쉽게 만듦
- 시스템의 유연성이 증가됨
- 보다 쉽게 서비스를 테스트할 수 있음
- 일부 시스템의 실패가 전체 시스템의 실패로 이어지지 않음
프로그래밍 세계에서는 항상 느슨한 결합이 주된 관심사
- UI : 컴포넌트화
- 객체 지향 프로그래밍 : 의존성 주입 (Dependency Injection)
- 마이크로서비스 : 메시징 시스템을 이용한 비동기 커뮤니케이션
주요 용어 :
- 메시지를 보내는 사람이 생산자(producer), 메시지를 받는 사람이 소비자(consumer)
- 메시지를 보내는 것을 발행(publish), 메시지를 받는 것을 소비(consume)
메시지 브로커의 특징 :
- 프로그램 간의 직접 연결 없음: less dependency, fault tolerant
> 소비자 프로세스가 죽어있어도 생산자는 메시지를 보낼 수 있음
> 생산자 프로세스가 죽어있어도 소비자는 메시지를 수신할 수 있음
- 메시지 브로커에 있는 메시지는 소비자(수신자)가 꺼낼 때까지 안전하게 보관됨: durability
> (프로세스가 죽어 있어도) 메시지는 소비하기 전까지는 사라지지 않음
> 따라서, 프로그램 간 통신은 시간과 독립적임
- 통신이 이벤트에 의해 구동될 수 있음
> 큐의 상태에 따라 프로그램을 제어할 수 있습니다. 예를 들어 메시지가 큐에 도착하는 즉시 프로그램이 시작되도록 설정할 수 있습니다. 또는 예를 들어 큐에서 특정 우선순위 이상의 메시지가 10개가 되거나 임의의 우선순위의 메시지가 10개가 될 때까지 프로그램이 시작되지 않도록 지정할 수 있습니다.
- 확장에 용이함
> 메시지 브로커는 여러 큐를 만들거나, 수평적으로 확장하여 메시지 부하 증가를 처리할 수 있습니다.
메시지 브로커의 단점 :
프로세스 간의 직접 연결에 비해 아키텍처가 복잡합니다.
메시지 브로커 선택의 기준 :
메시지 브로커의 종류로는 Apache Kafka, Amazon Kinesis, Amazon SQS 등이 있습니다.
- 프로그래밍 언어 지원 여부
- 메시징 표준 지원 여부
- 메시지 순서 보장 여부
- 전달 보장 여부: 어떤 종류의 전달을 보장하는가?
- 영속성: 브로커가 고장 나도 문제가 없도록 메시지가 디스크에 저장되는가?
- 내구성: 소비자가 메시지 브로커에 다시 접속할 경우, 접속이 중단된 시간에 전달된 메시지를 받을 수 있는가?
- 확장성
- 지연 시간
메시지 큐가 필요한 실제 사레:
O2O (online to offline) 서비스를 구현할 때
- 컴퓨터가 할 수 있는 일은 대부분 수평 확장으로 해결 가능
- 그러나, O2O 서비스는 결국 사람이 해야 하므로, 주문 메시지를 메시지 큐에 모아놓고, 이벤트를 처리하는 주체가 주문을 차근차근 진행해야 함
'마이크로서비스' 카테고리의 다른 글
Devops Day 44 (5.8) 마이크로서비스_CQRS (0) | 2023.05.09 |
---|---|
Devops Day 43 (5.4) 마이크로서비스_도메인 주도 설계 실습 Sprint (0) | 2023.05.05 |
Devops Day 43 (5.4) 마이크로서비스_도메인 주도 설계와 모놀리식 분해 전략 (0) | 2023.05.05 |
Devops Day 42 (5.3) 마이크로서비스_마이크로서비스 구조와 특징 (0) | 2023.05.04 |