MSA에서는 각 서버가 서로 통신함으로써 여러 도메인이 엮인 요청을 처리할 수 있도록 한다. 이때 서버간 통신을 위해 일반적인 IPC인 REST를 사용할 수 있지만, REST는 동기 프로토콜이기 때문에 호출한 서비스가 응답할 때까지 클라이이언트가 대기해야한다는 단점이 있다. 따라서 서비스가 동기 프로토콜로 통신하면 그만큼 애플리케이션 가용성은 저하될 수밖에 없다. 서비스가 모두 HTTP 통신을 사용한다면, 어느 하나의 서버가 내려갔을때 제대로 동작할 수 없다.
이를 해결하기 위해 비동기 만 있는 서비스를 정의해서 해결할 수도 있지만, 어쩔 수 없이 서비스에 동기 API를 포함시켜야 할 경우가 많다. 이런 경우에는 동작을 조금 우회한 비동기 처리 기법을 사용할 수 있다.
클라이언트가 요청 메시지를 주문 서비스에 전송하여 주문을 생성한다. 그러면 주문 서비스는 다른 서비스와 메시지를 비동기 방식으로 교환하고 최종적으로 클라이언트에 응답 메시지를 전송한다.
메시징 채널을 통해 메시지를 전송해서 서로 비동기 통신하기 때문에, 응답을 대기하며 블로킹될 필요가 없다.
이런 아키텍처에서는 서버가 메시지를 소비할 수 있는 시점에 메시지 브로커(MQ)에 있는 메시지를 꺼내와 자유롭게 처리할 수 있기 때문에 매우 탄력적이다.
서비스에 동기 API가 있는 경우 사용할 수 있는 방법이다.
데이터 복제는 서비스 요청 처리에 필요한 데이터를 레플리카, 즉 복제본을 만들어 가지는 구조이다. 실제 소비자, 음식점 DB를 가진 서비스가 발행하는 이벤트를 구독하여 복제본을 최신 데이터 상태로 유지한다면 동기식으로 서비스와 통신할 필요 없이 요청을 처리할 수 있다.
데이터 복제는 때에 따라 유용하게 쓰일 수 있다. (예를 들어 주문 서비스가 음식점 서비스에서 수신한 데이터를 복제해서 메뉴 할목을 검증하고, 단가를 매기는 경우 등 간단한 유효성 검증을 위한 데이터가 필요할때 등이 있다.) 하지만 물론 대용량 데이터의 레플리카를 만드는 것은 엄청나게 비효율적이기 때문에 상황에 따라 적절히 사용해야한다.
이 방법 또한 동기 API를 쓰는 경우 취할 수 있는 방법이다. 간단하게 표현하자면, 일단 동기 요청에 대해 반환한 후 비동기적으로 실제 동작을 수행하는 방법이다.
요청 처리 도중 동기 통신을 제거하기 위해서 사용자에게 들어온 요청은 다음과 같이 처리한다.
- 로컬(주문서비스)에서 사용 가능한 데이터로 요청을 검증한다.
- 메시지를 OUTBOX 테이블에 삽입하는 식으로 DB를 업데이트한다.
- 클라이언트에 응답을 반환한다.
서비스는 요청 처리 중에 다른 서비스와 동기적 상호작용을 하지 않는 대신, 다른 서비스에 메시지를 비동기 전송한다. 이렇게 하면 서비스를 느슨하게 결합할 수 있다.
주문 서비스를 위와 같이 구현한다면 먼저 주문을 PENDING 상태로 생성하고, 다른 서비스와 메시지를 교환하여 주문을 비동기 검증한 다음 이후 동작을 수행할 수 있다. createOrder를 호출하면 벌어지는 이벤트의 순서는 다음과 같다.
- 주문 서비스: 주문을 PENDING 상태로 생성한다.
- 주문 서비스: 주문 ID가 포함된 응답을 클라이언트에 반환한다.
- 주문 서비스: ValidateConsumerInfo 메시지를 소비자 서비스에 전송한다.
- 주문 서비스: ValidateOrderDetails 메시지를 음식점 서비스에 전송한다.
- 소비자 서비스: ValidateConsumerInfo 메시지를 받고 주문 가능한 소비자인지 확인 후, ConsumerValidated 메시지를 주문 서비스에 보낸다.
- 음식점 서비스: ValidateOrderDetails 메시지를 받고 올바른 메뉴 항목인지, 그리고 음식점에서 주문 배달지로 배달 가능한지 여부를 확인 후 OrderDetailsValidated 메시지를 주문 서비스에 전송한다.
- 주문 서비스: ConsumerValidated와 OrderDetailsValidated를 받고 주문 상태를 VALIDATED로 변경한다.
주문 서비스가 ConsumerValidated와 OrderDetailsValidated 메시지를 받는 것이 어떤 순서인지는 크게 상관 없다. 이 서비스는 메시지를 수신하는대로 주문 상태를 변경할 수 있다. 주문 서비스는 주문 검증을 마친 후 주문 생성 프로세스를 최종적으로 마친다. 혹여 다른 서버가 내려가는 사고가 발생하더라도 주문 서비스는 계속 주문을 생성하고 클라이언트에 응답할 수 있다. 나중에 소비자 서비스가 재가동되면 큐에 쌓인 메시지를 처리해서 밀린 주문을 다시 검증하기만 하면 되기 때문이다.
이 경우, 클라이언트가 주문 생성 성공 여부를 알아내려면 주기적으로 폴링하거나 주문 서비스가 알림 메시지를 보내주어야한다.