Q.메시지 큐를 왜 쓰나요?
호출하는 쪽과 처리하는 쪽을 시간적으로 떼어내기 위해서입니다.
| 얻는 것 | 내용 |
|---|
| 응답 시간 단축 | 즉시 필요 없는 일을 뒤로 넘긴다. 이메일, 썸네일 생성 |
| 부하 완충 | 갑작스러운 유입을 큐가 받아 두고 소비자가 자기 속도로 처리한다 |
| 장애 격리 | 소비자가 죽어도 메시지는 남는다 |
| 결합도 감소 | 발행자가 소비자를 몰라도 된다 |
| 확장 | 소비자를 늘려 처리량을 올린다 |
| 재처리 | 실패한 작업을 다시 처리할 수 있다 |
두 번째가 큐의 고유한 값입니다. 초당 1만 건이 몰려도 소비자가 초당 1천 건만 처리할 수 있다면, 동기 호출로는 실패하지만 큐가 있으면 시간을 늘려 전부 처리합니다.
세 번째도 중요합니다. 동기 호출에서 상대가 죽으면 그 요청은 사라지지만, 큐에 넣었으면 상대가 복구된 뒤 처리됩니다.
흔한 실수: 성능을 위해 쓴다고만 답하는 것. 전체 처리 시간은 오히려 늘어납니다. 짧아지는 것은 사용자가 기다리는 시간입니다. 그리고 그 대가로 즉시 결과를 알 수 없게 됩니다.
Q.메시지 큐를 쓰면 안 되는 경우는 언제인가요?
| 상황 | 이유 |
|---|
| 결과를 즉시 알려줘야 한다 | 로그인 검증, 잔액 조회. 비동기로 만들 수 없다 |
| 순서가 엄격히 중요하다 | 큐는 파티션 단위로만 순서를 보장한다 |
| 호출 한 번으로 끝난다 | 큐를 두면 운영할 것만 늘어난다 |
| 강한 트랜잭션이 필요하다 | DB 와 큐를 원자적으로 묶을 수 없다 |
| 지연을 감당할 수 없다 | 큐를 거치면 최소 수십 밀리초가 더 든다 |
세 번째가 실무에서 가장 흔한 오용입니다. 서비스 두 개 사이의 단순한 조회에 큐를 두면 응답을 되받기 위한 구조를 또 만들어야 하고, 그것은 그냥 동기 호출보다 복잡합니다.
큐를 도입하면 함께 따라오는 것들도 있습니다.
| 따라오는 비용 | 내용 |
|---|
| 중복 처리 대비 | 멱등성을 만들어야 한다 |
| 실패 처리 | 재시도와 실패 큐를 설계해야 한다 |
| 관측 | 트레이스가 끊기고 지연을 따로 재야 한다 |
| 운영 | 브로커 자체가 장애 지점이 된다 |
흔한 실수: 결합도를 낮추려고 모든 통신을 큐로 바꾸는 것. 흐름이 보이지 않아 장애 때 어디까지 진행됐는지 알기 어려워집니다.
Q.메시지 유실을 어떻게 방지하나요?
유실될 수 있는 구간이 세 곳입니다. 각각을 막아야 합니다.
| 구간 | 유실 상황 | 대응 |
|---|
| 발행 | 브로커에 도착 전에 실패 | 저장 확인 응답을 기다린다. 재시도한다 |
| 브로커 | 저장 전에 노드가 죽는다 | 복제본을 두고 과반 저장을 확인한다 |
| 소비 | 처리 전에 완료 표시를 한다 | 처리 성공 후에 표시한다 |
세 번째가 가장 흔한 원인입니다. 메시지를 받자마자 완료로 표시하고 처리 중에 죽으면 그 메시지는 사라집니다. 처리가 끝난 뒤 표시해야 합니다.
첫 번째에서는 DB 쓰기와 발행을 묶는 문제가 함께 옵니다. 커밋과 발행 사이에 죽으면 데이터는 있고 이벤트는 없으므로, 이벤트도 같은 트랜잭션에 저장해 두고 별도 프로세스가 발행하는 구조를 씁니다.
| 설정에서 볼 것 | 내용 |
|---|
| 발행 확인 수준 | 리더만 받았는지, 복제본까지 받았는지 |
| 복제 수와 최소 동기 복제 수 | 하나가 죽어도 남는지 |
| 소비자 완료 표시 시점 | 자동 표시를 끄고 처리 후 수동으로 |
흔한 실수: 유실을 0으로 만들려는 것. 대가는 지연과 처리량입니다. 어떤 데이터는 유실을 감수하는 편이 합리적이고, 그 판단이 먼저입니다.
Q.컨슈머 랙이 계속 쌓이면 어떻게 대응하나요?
쌓인다는 것은 처리 속도가 유입 속도보다 느리다는 뜻입니다. 원인을 나눠 봅니다.
| 확인 | 내용 |
|---|
| 유입이 늘었는가 | 발행량 지표를 본다 |
| 처리가 느려졌는가 | 메시지당 처리 시간을 본다 |
| 소비자가 죽었는가 | 인스턴스 수와 재시작 이력 |
| 특정 파티션만 쌓이는가 | 키가 한쪽에 몰렸거나 그 소비자만 문제 |
| 재시도가 반복되는가 | 처리 못 하는 메시지가 앞을 막고 있다 |
네 번째와 다섯 번째가 자주 놓치는 원인입니다. 전체 랙만 보면 원인이 안 보입니다.
| 대응 | 내용 |
|---|
| 소비자 증설 | 파티션 수까지만 효과가 있다 |
| 파티션 증설 | 그 위로 늘리려면 필요하다 |
| 처리 최적화 | 건별 DB 접근을 묶음 처리로 |
| 막는 메시지 격리 | 실패가 반복되면 실패 큐로 보내고 넘어간다 |
| 발행 조절 | 급하지 않은 발행을 줄인다 |
첫 번째의 한계가 중요합니다. 파티션 수가 소비자 수의 상한이라, 파티션 4개에 소비자 10대를 붙이면 6대는 아무것도 하지 않습니다.
흔한 실수: 랙 숫자만 보고 판단하는 것. 건수보다 따라잡는 데 걸릴 시간이 실제 지표입니다. 100만 건이 쌓였지만 처리 속도가 유입의 두 배면 곧 사라지고, 1만 건이지만 처리가 더 느리면 계속 늘어납니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
메시징 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.