ecsimsw
자주 사용하는 미들웨어의 통신 방법 1 - 메시지 브로커와 큐 본문
미들웨어
미들웨어는 애플리케이션 사이에서 데이터 흐름을 중계하거나 처리하기 위한 소프트웨어를 말한다. 사실 단순히 큐나 메시지 브로커만을 말하는 줄 알았는데, 정의에 따르면 WAS, GW, MQ, DBMS 등 내가 기존에 생각하고 있던 것보다 더 넓은 범위의 키워드로 생각된다.
요즘 이벤트 서버 성능 개선에 머리를 쓰고 있고, 서버를 구성하는 각 요소들의 성능 개선을 위해선 지금 어떻게 통신하고 있는지부터 알아야겠다는 생각이었다. 자주 사용하고 있는 미들웨어들의 기본 설정이나 통신 방식들을 정리한다.
# 메시지 브로커와 큐
1. Kafka
2. RabbitMQ
3. Redis pub/sub
4. AWS SQS
5. Mosquitto와 MQTT
# 웹 서버
6. Tomcat
7. Nginx
8. ALB
# DBMS
9. Mysql
10. MongoDB
Kafka
1. 프로토콜과 연결 유지
- TCP 기반의 바이너리 프로토콜로 통신, 최초 연결 시 핸드셰이크가 필요하다.
- Connection pooling으로 연결을 재사용하고, 클라이언트의 호출이 없거나, 하트 비트가 일정 시간 동안 없으면 연결을 종료한다.
2. Batch 기반의 Produce
- Kafka는 높은 처리량을 위해 메시지 배치 전송을 사용한다.
- 배치 주기와 크기를 기반으로 전송 단위를 설정할 수 있다.
- 그 주기와 크기가 너무 작으면 처리량이 낮아질 것이고, 반대로 너무 크다면 지연율이 높아지게 된다.
3. Producer 설정
- 기본 Producer 설정은 다음과 같다.
- batch size는 메시지 크기가 모였을 때 전송할 크기를 말하고, linger.ms는 배치를 처리하기 전 대기할 시간을 의미한다.
- 사이즈가 다 차지 않아도 대기 시간이 만족하면 배치가 실행되고, 반대로 대기 시간이 만족하지 않아도 크기가 넘어서면 배치가 실행된다.
- Link : The default changed from 0 to 5 in Apache Kafka 4.0 as the efficiency gains from larger batches typically result in similar or lower producer latency despite the increased linger.
batch.size = 16384 // 16KB
linger.ms = 5
4. Long polling 기반의 Consumer
- 카프카는 Long polling으로 메시지를 처리한다.
- 기준 시간 동안 대기하고, 대기 중 메시지 도착 시 또는 시간 초과 시 반환하길 반복한다.
- 이때도 하나의 메시지만 수신하는 것이 아닌, Batch로 지정된 수의 여러 메시지를 한 번에 가져와서, 하나씩 처리한다.
- 처리 후에는 Commit 처리로 토픽에 컨슈머 별로 저장되어 있는 Offset 위치를 변경한다.
max.poll.interval.ms = 300000 (5분)
max.poll.records = 500
enable.auto.commit = true
- 위는 관련된 카프카 4.0의 기본 설정이다.
- max.poll.interval.ms : Consumer가 poll() 호출 사이에 허용되는 최대 간격 (그 간격 안에 poll 없을 시 리밸런싱)
- max.poll.records : 한 번의 poll() 가져오는 최대 레코드 수 (전체 파티션 범위)
- enable.auto.commit : 자동 오프셋 커밋 사용 여부
* 처리량과 지연율에 대한 비유
처리량과 지연률을 화물 트럭으로 비유하자.
- 트럭에 적재되는 시간을 기다려 많은 짐을 실을 수록, 더 적은 운송 횟수로 짐을 옮길 수 있다.
- 반대로 짐이 적재된 시간과 도착한 시간의 간격이 길어진다.
- 전체 짐의 관점으로 보면 더 빠르게 전달되었지만, 각 짐을 사용하지 못하는 시간은 길어졌다.
처리량은 적은 횟수의 네트워크 처리로 더 많은 메시지가 전달되길 말하고,
지연율은 각 메시지가 전달을 시작한 시점부터, 목적지에 도달되는 시간을 말한다.
RabbitMQ
1. Push 기반의 낮은 지연성
- Consumer와 Queue는 연결을 유지하고 있다가, 큐에 메시지 도착 즉시 전달받는다.
- 브로커에서 Consumer에게 Push 하는 방식으로 메시지가 전달되고, 따라서 낮은 지연성을 갖는다.
- Producer가 Exchange에 메시지를 발행하면, Exchange에서는 바인딩 규칙에 따라 전체 혹은 일부 큐에 메시지가 전달된다.
Exchange의 라우팅 방식
- fanout : 브로드 캐스트
- direct : routing key에 맞는 큐로 전달
- topic : routing key의 패턴에 맞는 큐로 전달
- header : 메시지 헤더에 맞는 큐로 전달
2. 신뢰성
- 컨슈머에게 메시지가 전달되면, 브로커에서 해당 메시지는 UnAcked 상태로 해당 순서에 보관된다.
- 컨슈머는 처리 후 그 결과를 Broker에 ACK/NACK로 알린다.
- 만약 컨슈머가 처리 중 연결이 끊기거나 죽는 상황을 방지하기 위해 메시지는 TTL을 갖는다.
- NACK, Reject, Timeout 이 발생하면 브로커에선 해당 메시지를 Requeue 상태로 돌려 컨슘이 가능하도록 한다.
- DLQ 나 재시도 예외 처리로, 컨슈머가 무의미하게 특정 메시지를 반복 컨슘 - 재시도하는 것을 막는다.
3. 완벽하지 않은 순서 보장
- 메시지를 순서대로 수신하지만, 이전 메시지가 "처리 완료" 되어야 다음 메시지가 수신될 수 있는 구조는 아니다.
- 한 큐에 하나의 컨슈머만을 강제하지 않기에, 한 메시지가 앞선 메시지보다 먼저 처리될 수 있다.
- 또, Prefetch에 의해 한 컨슈머 안에서도 여러 메시지가 병렬 처리되는 과정에서 순서가 보장되지 않을 수 있다.
- 이를 해결하기 위해선 Prefetch를 1로 하고, 큐 당 컨슈머를 강제해야 하나, 이때의 낮아진 처리량에 주의한다.
4. Prefetch
- 한 컨슈머가 동시에 수신할 수 있는 메시지 수를 지정하여 처리량을 조정한다.
Redis Pub / Sub
1. RESP
- Redis pub / sub은 "REdis Serialization Protol" 기반의 단순 텍스트 프로토콜로 통신한다.
- TCP 위에서 동작하기에 핸드셰이크를 맺고, Keep-Alive로 연결을 유지한다.
2. 휘발성, 비신뢰성
- 수신자의 연결 상태와 상관없이 메시지를 발행한다.
- 수신자가 메시지를 정상적으로 수신/처리되었는지 확인하지 않는다. (Fire and forget)
- 메시지 히스토리를 기억하거나 큐잉을 하지 않고, Push 기반의 전달이 이뤄진다.
3. 채널 기반 라우팅, 브로드 캐스팅
- 채널 이름 또는 패턴 기반의 구독이 가능하다.
- 메시지가 Publish 되면 채널을 구독하는 모든 수신 측에 메시지가 전달된다.
AWS SQS
1. Pull 방식의 컨슘
- 컨슈머가 브로커에 질의하는 방식으로 메시지를 수신한다.
- Long polling과 Short polling 모두를 지원한다.
* Long polling vs Short polling
Short polling : 요청한 시점에 현재 상태를 응답 받음
Long polling : 응답 대기 시간 동안 변경 상황을 응답 받음
서버 부하나 실시간성에는 Long polling이 유리하나,
연결이 많아져 서버 리소스 부족으로 이어질 수 있고 구현 난이도가 높음
2. Batch 처리
- 송수신 모두 최대 10개의 메시지를 한 번에 발행 / 수신할 수 있다.
3. Visibility timeout
- 메시지를 수신하면 브로커에서 해당 메시지를 지우는 것이 아닌, 컨슘 불가능 상태로 표시한다.
- 컨슈머에서 처리를 마치면, 처리한 메시지를 지우는 요청을 전달한다.
- 제거되지 않은 메시지는 가시성 타임아웃 시간 이후에 메시지가 컨슘 가능 상태로 전환된다.
- 이 가시성 타임아웃 규칙을 이용하여 처리 실패된 메시지를 재시도 처리한다.
- DLQ 구성과 메시지 보관 기간을 조절하여 재시도 처리의 반복을 제한한다.
4. 높은 처리량을 지향하는 Standard 큐
- Standard queue는 메시지 순서를 보장하지 않는다.
- 처리량과 낮은 지연율 지향하고, 메시지 중복 처리 문제가 발생할 수 있다.
5. 신뢰성을 지향하는 FIFO 큐
- 메시지 Key를 기준으로 한 순서 보장이 가능하다.
- 동일 키끼리의 메시지는 순서가 보장되기에, HOL 블록킹 문제, 처리 지연 문제가 발생할 수 있다.
- 중복 방지 (동일 메시지 발행 제한)으로 큐 안에 동일한 메시지가 발행되는 문제를 피할 수 있다.
- 단, 메시지가 처리되는 도중 가시성 타임 아웃이 끊기면 해당 메시지를 다시 수신하게 되니 컨슈머 측에서의 중복 처리에 유의한다.
Mosquitto (MQTT)
1. 연결 유지, Push 방식
- 클라이언트와 브로커가 연결을 유지하고, 메시지가 발생하면 브로커에서 Push 한다.
2. 신뢰성
- 수신과 발행 측 중 더 낮은 QoS 설정을 따른다.
- 기본 설정은 QoS 0이다.
3. QoS
- QoS 0 : 수신이나 처리 결과를 보장하지 않는다. 즉시 전달 후 메시지 손실 (fire and forget)
- QoS 1 : 최소 한 번의 수신은 보장하지만, 중복 처리의 위험이 있다.
- 수신자가 메시지를 정상적으로 받으면 PUBACK을 날려 송신자에게 알린다.
- 지연이나 패킷 손실로 PUBACK을 못 받으면, 미리 설정된 주기 이후에 재전송한다.
- QoS 2 : 최소 한번 보장, 중복을 막는다.
- 수신자가 메시지를 정상적으로 받으면 PUBACK을 날려 송신자에게 알린다. 이는 수신은 했지만, 처리는 아직을 의미한다.
- 송신자가 최종 처리를 시작할 것을 주문한다. (PUBREL)
- 수신자가 최종 처리를 완료하고 이를 알린다. (PUBCOMP)
4. 메시지 보관
- Mosquitto는 메시지 보관이 필요할 때도 있지만, 영구 저장소의 목적은 아니다.
- Retain 메시지 : 센서값, 설정 정보 등 새로운 Subscriber에 최신 상태를 전달하기 위한 보관 메시지
- Offline 메시지 : QoS가 1 또는 2일 때, 구독자가 오프라인이 되는 경우를 대비한 보관, 재접속 시 전달
'Architecture > Infrastructure' 카테고리의 다른 글
Vault kubernetes injector 소개 (0) | 2024.05.31 |
---|---|
CDN URL 암호화, CloudFront signed url (1) | 2024.04.10 |
Nginx 엑세스 로그로 응답 시간 모니터링 (0) | 2024.03.20 |
AWS S3 의 비용이 부담된다면? Vultr Object storage 소개 (1) | 2023.12.31 |
Nginx 요청 호출 수 제한과 접근 가능 IP 제한 (0) | 2023.12.17 |