미들웨어 트러블슈팅 마스터 가이드: Redis, RabbitMQ, Kafka 성능 및 장애 해결
Dev
마지막 업데이트

미들웨어 트러블슈팅 마스터 가이드: Redis, RabbitMQ, Kafka 성능 및 장애 해결


현대 백엔드 아키텍처에서 캐시(Redis), 메시지 브로커(RabbitMQ), 분산 이벤트 스트림(Kafka)은 데이터의 병목 현상을 방지하는 필수 요소입니다. 하지만 이러한 미들웨어 컴포넌트가 장애를 일으킬 때, 원인은 컨슈머 애플리케이션에 있으나 증상은 브로커의 대기열 지연이나 리더 이탈로 나타나는 등 원인 추적이 매우 어렵습니다.

본 가이드에서는 복합 미들웨어 환경에서 장애가 발생했을 때의 신속한 계층 분류부터 Redis, RabbitMQ, Kafka의 핵심 트러블슈팅 해법을 종합 분석합니다.


1. 장애 첫 10분 진단 및 타겟 라우팅

장애 인지 시, 완벽한 분석을 시도하기 전에 터미널에서 신속하게 각 컴포넌트의 대표 상태 지표를 확인하여 디버깅 방향을 분기해야 합니다.

# 1. Redis 메모리 사용 상태 및 단편화 확인
redis-cli INFO memory

# 2. RabbitMQ 큐의 대기 메시지(ready) 및 Ack 대기 메시지(unack) 통계 조회
rabbitmqctl list_queues name messages_ready messages_unacknowledged consumers

# 3. Kafka 컨슈머 그룹의 오프셋 지연(Lag) 및 컨슈머 상태 파악
kafka-consumer-groups --bootstrap-server localhost:9092 --describe --group my-consumer-group
  • 상태/캐시 만료 비정상, 지연 시간 급증: Redis 축
  • 특정 큐에 메시지가 계속 쌓이거나 Ack 응답 유실: RabbitMQ 축
  • 컨슈머 그룹 Lag 급증, 잦은 리밸런스 현상: Kafka 축

2. Redis 캐시 계층 장애 해결

Redis는 싱글 스레드 이벤트 루프로 동작하므로, 시간 복잡도가 높은 명령이나 단일 초대형 키(Big Key)를 다룰 때 이벤트 루프가 차단되어 전체 커넥션 타임아웃을 유발합니다.

빅 키 (Big Keys) 탐색 및 비동기 삭제

  • 진단: --bigkeys 옵션을 이용해 메모리를 가장 많이 차지하는 키 목록을 식별합니다.
    redis-cli --bigkeys
  • 삭제 기법: 대용량의 Set, List, Hash 데이터를 단일 DEL 명령어로 지우면 지우는 동안 이벤트 루프가 멈춥니다. 대신 UNLINK 명령어를 사용해 메모리 해제 연산을 백그라운드 스레드로 위임하십시오.

OOM (Out Of Memory) 장애 해결

Redis 메모리가 가득 차면 OOM command not allowed when used memory > 'maxmemory' 에러가 발생합니다.

  • Eviction 정책 설정: redis.conf에서 maxmemory-policyallkeys-lru 또는 volatile-lru로 설정하여 만료 주기가 가깝거나 오래 사용되지 않은 키를 자동으로 추방하도록 조율합니다.
  • 메모리 단편화 제어: active-defrag yes 설정을 활성화하여 Redis 재시작 없이 메모리 단편화를 백그라운드에서 정리합니다.

3. RabbitMQ 메시징 큐 장애 해결

RabbitMQ는 메시지의 복잡한 라우팅과 확실한 전달(Delivery) 보장에 최적화되어 있으나, 컨슈머의 장애나 설정 미비로 큐가 임계점까지 차오르면 브로커 전체가 Blocked 상태로 빠집니다.

데드 레터 익스체인지 (Dead Letter Exchange, DLX) 활용

컨슈머가 메시지 처리에 실패(Nack)하거나 메시지 수명(TTL)이 만료되었을 때, 해당 메시지를 무한 루프로 재시도하지 않고 별도의 장애 수거용 익스체인지(DLX)로 격리하여 보관하는 패턴입니다.

  • 큐 선언 시 바인딩 예시:
    const args = {
      'x-dead-letter-exchange': 'my-dlx-exchange',
      'x-dead-letter-routing-key': 'dead-letter-routing-key'
    };
    channel.assertQueue('my-work-queue', { arguments: args });

쿼럼 큐 (Quorum Queues) 도입

  • 클래식 큐의 한계: 미러드 클래식 큐는 고가용성 네트워크 장애 시 스플릿 브레인(Split-Brain) 및 데이터 유실 가능성이 존재합니다.
  • 쿼럼 큐: Raft 합의 알고리즘 기반으로 동작하여 데이터 일관성을 강력하게 보장하며, 복제본 간의 동기화 신뢰성이 매우 높습니다. 고가용성이 필수적인 결제 및 주문 처리 흐름에 강력히 권장됩니다.

4. Apache Kafka 이벤트 스트림 장애 해결

Kafka는 대량의 정렬된 이벤트 스트림 데이터를 영속 저장하고 순차 분배하는 분산 커밋 로그 시스템입니다. 컨슈머 및 프로듀서의 세밀한 네트워크 시간 설정이 장애를 결정합니다.

프로듀서 재시도(Producer Retries) 및 멱등성 보장

프로듀서가 메시지를 브로커에 전송한 뒤 일시적인 네트워크 순단으로 ACK 응답을 받지 못하면 동일 메시지를 다시 전송하여 중복 데이터가 쌓일 수 있습니다.

  • 멱등성 프로듀서 (Idempotent Producer) 활성화:
    enable.idempotence=true
    acks=all
    max.in.flight.requests.per.connection=5
    이 설정을 켜면 브로커가 프로듀서 ID와 메시지 시퀀스 번호를 기반으로 중복 메시지를 필터링하여 단 한 번만 로그에 적재(Exactly-Once)합니다.

리더 불균형 (Leader Imbalance) 트러블슈팅

브로커 서버가 예기치 않게 재시작되거나 네트워크 단절이 일어났을 때, 파티션의 리더(Leader) 권한이 특정 브로커에만 과도하게 쏠려 특정 서버에 CPU/네트워크 부하가 집중되는 현상입니다.

  • 자동 복구 설정: Kafka 브로커의 server.properties 설정에 아래 항목을 구성합니다.
    auto.leader.rebalance.enable=true
    leader.imbalance.per.broker.percentage=10
    leader.imbalance.check.interval.seconds=300
  • 수동 리밸런싱 실행: 즉시 리더 분배를 원할 때는 CLI 도구를 사용하여 강제 조율을 실행합니다.
    kafka-leader-election --bootstrap-server localhost:9092 --election-type preferred --all-topic-partitions

FAQ

Q. Redis UNLINKDEL은 구체적으로 무엇이 다른가요?

DEL은 삭제 요청을 받는 순간 메모리 공간 해제 작업을 이벤트 루프 메인 스레드에서 즉시 실행하므로, 기가바이트 단위의 키를 지울 때는 수초 동안 서버가 멈춥니다. UNLINK는 임시 공간에 키 이름만 해제해 둔 뒤, 실제 데이터가 차지하는 공간 해제는 백그라운드 스레드에서 점진적으로 진행하므로 서비스 무중단 삭제를 보장합니다.

Q. Kafka 리밸런스가 너무 잦은데 어떻게 해결하나요?

컨슈머 애플리케이션의 비즈니스 로직 연산이 무거워 max.poll.interval.ms 시간(기본 5분) 내에 다음 poll()을 호출하지 못하면, 브로커는 컨슈머가 죽었다고 간주해 리밸런스를 유발합니다. 한 번에 가져오는 레코드 양(max.poll.records)을 줄이거나 처리 로직 내 스레드 풀을 결합하여 처리 루프 시간을 단축해야 합니다.

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.