아래 3.1, 3.2 장은 익숙한 내용이 많아서 생략한다.
출처 :
메시지는 헤더와 본문으로 나뉘어짐.
헤더에는 뭐가들어가지? :
headless 도 있다. payload header 를 활용해야 한다.
커맨드
: RPC 요청과 동등함. 작업 + 매개변수이벤트
: 도메인객체의 상태 변화. (도메인이벤트)점대점 (1:1) :
커맨드
메시지를 다룸발행/구독 (1:N) :
이벤트
메시지를 다룸점대점 채널을 요청채널 + 응답채널 로 만들어서 요청/응답 처리를 구현할수 있다.
요청시에는 MessageId: msgId
를 전달하고, 응답시에 CorrelationId: msgId
로 응답하면서 쌍을 맞췄다.
또한 요청시에 ReturnAddress 로 어디로 보낼지도 적혀있다.
메시징은 기본적으로 비동기
이고, 만약 동기식으로 만들려면 블락을 걸면 된다.
이런 설명이 있긴 한데.. 굳이 메시징을 동기적으로 할일은 없을듯 하다.
메시징 시스템으로도 충분히 모든 상호작용 패턴을 구현할수 있음을 알려주기 위한 의도로 보인다.
점대점과 다를바 없이 응답 채널을 활용하면 된다.
ReturnAddress 가 없고 CorrelationId 만 추가하면 관심있는 컨슈머가 읽어가면 된다.
응답 채널은 점대점을 써도 되고 발행/구독을 활용해도 된다.
REST, 오픈API 와 달리 표준이 없으므로 자유롭게 기술하면 된다.
비동기 작업
방식과 발행 이벤트
방식 2가지를 그림으로 볼수있다.
채널명을
커맨드 채널
이벤트 채널
이라고 명시했는데 괜찮은것 같다.
브로커리스 메시징
아키텍처도 있지만 일반적으로 브로커
기반 이 낫다.
(sqs 도 브로커 기반)
안쓰지만 대략 특징만 짚어보자.
장점
단점
sqs, kafka, kinesis, rabbitmq 등 메시지가 지나가는 중간지점이 있으면 모두가 해당한다.
어떤 메시지 브로커를 쓸지 결정할때 검토 사항
장단점이 있을수밖에 없다.
속도가 빠르면 메모리에만 쓰면서 내구성을 보장하지 않는다던지, 순서보장이 안된다던지..
하지만 순서 유지
및 확장성
은 필수 이다.
카프카 또는 키네시스 쓰자
채널을 부르는 명칭은 브로커 마다 다르다.
점대점 채널
과 펍섭 채널
을 구분해서 명칭이 있는 브로커들도 있지만 내게 익숙한 브로커들은 딱히 다르지 않다.
장점 :
단점 :
카프카를 쓰면 위 단점 극복이 가능
채널이 샤딩 가능한 브로커 쓰자
특성상 1번만 전달하는것은 불가능하다.
컨슈머가 처리를 하는중 ack 보내기 직전에 죽는다던지, 네트워크 실패라던지 등의 이슈로 브로커가 재전송 하기도 한다.
카프카의 경우 오프셋으로 폴링해오는 구조라서 재전송은 아니더라도 ack 보내기 전에 죽는것에 대해서 2번 폴링하는 경우는 막을수 없을것 같다.
적어도 한 번 전달
을 보장 해주는 브로커를 쓰자. (sqs 도 보장해준다)
이미 취소된 오더를 다시 취소되도 문제없게 설계하면 된다.
하지만 이렇게 멱등한 로직은 잘 없는편이다.
중복처리 하는 테이블에 pk 를 두어 저장하여 한번만 실행되도록 보장하게 한다.
특정 목적으로만 만들어졌기에 dedicated table 이라고도 불리며, 중복처리를 하는 테이블이기에 once table 이라고도 불린다.
서비스의 트랜잭션만 성공하고 이벤트발행을 실패하면 아주 불안정안 상태가 발생한다.
두 작업이 원자적으로 실행되어야 한다.
트랜잭셔널 아웃박스 패턴
을 쓴다.
테이블을 임시큐로 쓰는 방법이다.
OUTBOX 테이블
에 메시지 저장OUTBOX 에 저장된 메시지를 주기적으로 폴링해서 발행후 삭제한다.
RDBMS 를 쓰고 있고 규모가 작을 경우 쓸수 있는 가장 간편한 방법.
DB 폴링에는 비용이 유발된다.
DB 트랜잭션 로그를 테일링 하는 방법.
transaction log miner 로 트랜잭션 로그를 읽어 변경분을 메시지로 브로커에 발행하는것
REST 는 동기식이라는 치명적인 단점 존재.
레이턴시가 x2 되는것을 차치하고서라도 가용률에 영향을 끼친다.
서비스가 각각 99.5% 라면, 3제곱시 98.5%
다음처럼 이벤트들을 이용하면 어느쪽도 응답을 대기하지 않고 블로킹되지 않는다.
(요청채널과 응답채널을 만드는 방법)
비동기 통신으로 바꾸면 가용률에 영향을 끼치지 않는다.
통신하는 2개의 서비스가 모두 살아있을 필요도 없다.
만약 외부로 의존하는 API 가 있다면 복제해서 레플리카를 두어 자기 완비형
으로 만들수도 있다.
다만 대용량 데이터의 레플리카를 만드는 것은 대단히 비효율적이다.
가령 소비자 서비스에 있는 엄청난 양의 소비자 데이터를 주문 서비스에 그대로 복제하는것은 실용적이지 않다.
요청 처리 도중 동기 통신을 제거하려면 다음과 같은 흐름으로 처리하면 된다.
트랜잭셔널 아웃박스 패턴
+ (폴링 발행기
or 트랜잭션 로그 테일링
)