대규모 시스템 설계 기초 2 (4장)
가상 면접 사례로 배우는 대규모 시스템 설계 기초 2 (4장) 의 내용 중, 인상적이었던 부분을 발췌 및 요약합니다.
분산 메시지 큐
메시지 큐를 사용하면 다음과 같은 이득을 얻을 수 있다.
- 결합도 완화
- 규모 확장성 개선 : 생산자와 소비자 시스템 규모를 트래픽 부하에 맞게 독립적으로 늘릴 수 있다.
- 가용성 개선
- 성능 개선 : 비동기 통신이 기능하다.
메시지 큐 vs 이벤트 스트리밍 플랫폼
데이터 장기 보관, 메시지 반복 소비 등의 부가 기능을 갖춘 분산 메시지 큐도 있긴 하지만, 이 부가 기능은 통상적으로 이벤트 스트리밍 플랫폼에서만 이용 가능하다.
메시지 모델
가장 널리 쓰이는 메시지 모델은 일대일과 발행-구독 모델이다.
일대일 모델
이 모델에서 큐에 전송된 메시지는 오직 한 소비자만 가져갈 수 있다.
발행 구독 모델
토픽에 따라서, 해당 토픽을 구독하는 모든 소비자에게 메시지가 전달되낟.
파티션
토픽에 보관되는 데이터의 양이 커진다면, 토픽을 샤딩할 수 있다. 이를 파티션 기법이라고 한다. 토픽을 여러 파티션으로 분할하고, 메시지를 모든 파티션에 균등하게 나눠 보내야 한다.
소비자 그룹
하나의 소비자 그룹은 여러 토픽을 구독할 수 있고 오프셋(토픽마다 읽은 메시지를 표기하기 위한 번호)을 별도로 관리한다. 데이터를 병렬로 읽다보니 메시지 처리 순서를 보장할 수 없다. 이를 해결하기 위해서는 하나의 소비자 그룹 안에서 하나의 소비자만이 하나의 토픽 내 메시지를 소비하도록 할 수 있다. 이 제약사항을 도입하면 일대일 모델에 수렴하게 된다.
데이터 저장소
메시지 큐의 트래픽 패턴은 읽기와 쓰기가 빈번하게 일어난다. 이를 위해서 데이터베이스보다 쓰기 우선 로그를 사용해보자. 세그먼트 단위로 나누는 파일을 쓰는 방법을 사용해보자.
일괄 처리
일괄 처리는 성능 개선에 유리하다. 운영 체제로 하여금 여러 메시지를 한 번의 네트워크 요청으로 전송할 수 있기 때문이다. 또한, 디스크에 더 큰 규모의 순차 쓰기 연산이 발생하므로, 디스크의 높은 접근 대역폭을 달성할 수 있다.
푸시 vs 풀
브로커가 데이터를 소비자에게 보내는 방식과, 소비자가 데이터를 브로커에서 가져가는 방법이 있다.
푸시 모델은 낮은 짖연을 가지지만, 소비자에게 큰 부하를 걸 수 있다.
풀 모델은 메시지를 소비하는 속도를 소비자가 알아서 결정하며, 일괄 처리에 적합하나다. 그러나 브로커에 메시지가 없어도 소비자에서 계속 데이터를 가져가려고 시도한다. 이에 따라서 컴퓨팅 자원을 낭비한다.
소비자 재조정
어떤 소비자가 어떤 파티션을 책임지는지 다시 정하는 프로세스다. 소비자가 새롭게 합류하거나, 기존 소비자가 그룹을 떠나거나 파티션이 조정되는 경우에 시잓될 수 있다.
이는 코디네이터가 중요한 역할을 한다. 코디네이터느 소비자로부터 오는 박동(heartbeat) 메시지를 살피고 각 소비자의 파티션 내 오프셋 정보를 관리한다.
복제
분산 시스템에서 파티션은 자신의 복재체를 가지고 있어야 예기치 못한 사고에 대응할 수 있다. 파티션에 대해서 리더를 선출하고, 리더에 대해서 지속적으로 동기화를 하는 사본을 구성할 수 있다.
동기화된 사본은 ISR 이라고 일컫는다. 이 때, 사본과 리더 사이에 메시지 개수 차이를 통해서 ISR 상태 여부를 판별한다. 리더 사본의 합의 오프셋 값이 사본의 오프셋과 동일한지에 따라서 ISR 여부의 판단이 가느하다.
ACK
생산자는 브로커가 메시지를 저장한 뒤에, 메시지 수신 확인 응답을 받는다. 이 때 ACK=all,ACK=1,ACK=0 과 같은 상황이 있을 수 있다. ACK=all 은 모든 브로커의 가장 느린 ISR 에도 메시지가 저장된 이후이다.
ACK=1 은 리더에 저장된 경우이며, ACK=0 은 수신확인 메시지를 기다리지 않는 경우이다.
메시지 전달 방식
최대 한 번
메시지를 최대 한 번만 전달하는 방식이다. 메시지가 전달 과정에서 소실되더라도 다시 전달되는 일은 없다. ACK=0 으로 메시지를 생산하며, 소비자는 메시지의 처리 전에 오프셋을 갱신한다.
소비자가 장애로 죽으면 메시지는 다시 소비될 수 없다.
최소 한 번
같은 메시지가 한 번 이상 전달될 수 있도록 하는 방법이다. ACK=1 또는 ACK=all 구성을 이용한다. 소비자는 메시지를 받고 성공적으로 처리한 후에야 오프셋을 갱신한다.
이 때, 메시지를 중복 처리할 수 있는데 메시지마다 고유한 키가 있는 경우 해당 키가 이미 데이터베이스에 있는 메시지는 처리하지 않고 버리면 될 것이다.
정확히 한 번
구현하기 가장 까다로운 전송 방식이다.
메시지 필터링
메시지 필터링을 위해, 메시지의 payload 를 읽는 방식은 적절하지 못하다. 메시지의 메타 데이터에 태그를 두는 방법을 고려해보자.
메시지의 지연 전송 및 예약 전송
소비자에게 보낼 메시지를 일정 시간 만큼 지연시킬 수 있다. 브로커 내부의 임시 저장소에 넣어 두었다가 시간이 되면 토픽으로 옮길 수 있을 것이다. Rocket MQ 는 특정 시간 동안 메시지 전송을 지연하는 기능을 제공한다.
프로토콜
메시지 생산, 소비, 박동 메시지 교환 등에 대한 프로토콜을 살펴보자. 유명한 프로토콜로는 AMQP 나 카프카 프로토콜 등이 있다.