인프런 커뮤니티 질문&답변
카프카 질문
작성
·
26
1
안녕하세요 카프카 관련하여 질문드립니다.
카프카로 DB Insert 요청을 비동기 처리할 경우 트래픽이 급증하면 데이터베이스가 감당할 수 있는 QPS를 초과하여 과부하가 발생할 수 있습니다. 실무에서는 이러한 상황을 어떻게 대응하는지 궁금합니다.
감사합니다.
답변 2
0
ssunn0812님 안녕하세요~
우선 답변이 늦어서 죄송합니다. (_ _)
질문 주신 내용에 대해 답변드려보겠습니다.
실무에서는 이 문제를 해결하기 위해 여러 가지 전략을 조합해서 사용합니다.
1. 컨슈머의 '처리 속도' 자체를 조절하기
가장 기본적이고 직접적인 방법입니다. DB가 처리할 수 있는 양만큼만 컨슈머가 작업을 수행하도록 조절하는(Throttling) 것입니다.
- 배치 크기 조절 ( - max.poll.records): 카프카 컨슈머는 한 번에 여러 개의 메시지(배치)를 가져와서 처리합니다. 이- max.poll.records옵션 값을 의도적으로 낮게 설정(예: 500개 -> 50개)하면, 한 번의 루프에서 DB로 보내는- INSERT쿼리의 수가 줄어듭니다. 이는 DB의 부하를 즉각적으로 낮춰주는 가장 간단한 튜닝 방법입니다.
- 컨슈머 사이드 Rate Limiting: 컨슈머 애플리케이션 코드 내에 Google Guava의 - RateLimiter같은 라이브러리를 사용하여 "초당 1000개의 트랜잭션만 처리"하도록 명시적으로 제한을 걸 수 있습니다.
2. 'Backpressure'를 구현하여 능동적으로 방어하기
단순히 속도를 줄이는 것을 넘어, DB의 '상태'를 확인하고 컨슈머의 동작을 일시적으로 멈추는, 더 지능적인 방법입니다.
- Circuit Breaker 적용 : 강의의 핵심 주제인 '견고한 시스템'과 직결됩니다. 컨슈머가 DB에 - INSERT를 시도할 때, DB에서 커넥션 타임아웃이나 응답 지연 같은 오류가 일정 비율 이상 발생하면 Circuit Breaker를 'Open' 상태로 전환합니다.
- pause()와- resume()의 활용: Circuit Breaker가 Open이 되었을 때가 중요합니다. 이때 컨슈머는 단순히 에러를 로그에 남기고 다음 메시지를 처리하려 하면 안 됩니다. (그러면 DB는 계속 공격당하겠죠.) 대신, 카프카 컨슈머의- pause()메서드를 호출해야 합니다.- consumer.pause()가 호출되면, 컨슈머는 브로커에게 "나 지금 바쁘니(혹은 내 뒷단이 아프니) 메시지를 더 이상 주지 마"라고 신호를 보냅니다.
- 컨슈머는 브로커로부터 새로운 메시지를 받아오지 않고(poll X), Circuit Breaker가 닫힐 때까지(예: 1분 뒤) 대기합니다. 
- 이후 DB 상태가 정상으로 돌아와 Circuit Breaker가 'Close'되면, 그때 - consumer.resume()을 호출하여 다시 메시지 처리를 시작합니다.
 
이 pause()/resume()와 Circuit Breaker의 조합이 DB 과부하를 막는 가장 세련되고 효과적인 실무 기법입니다.
3. 실패한 메시지 처리 및 재시도 전략
트래픽 급증으로 인해 DB가 처리하지 못한 메시지는 어떻게 해야 할까요?
- 재시도 최대 횟수 제한: DB가 아파서 실패한 요청을 컨슈머가 곧바로 재시도(retry)하면, 이는 불난 집에 부채질하는 격입니다. DB 부하를 더욱 가중시켜 '재시도 폭풍(Retry Storm)'을 일으킵니다. 
- Dead Letter Queue (DLQ): 일반적으로 3회 정도의 재시도(exponential backoff 적용) 후에도 실패하는 메시지는, 처리를 포기하고 별도의 'Dead Letter Queue (DLQ)' 토픽으로 보냅니다. - 이렇게 하면 컨슈머는 일단 해당 메시지의 오프셋을 커밋(commit)하고 다음 메시지를 처리할 수 있게 되어, 전체 파이프라인이 막히는 것을 방지합니다. 
- DLQ로 간 메시지들은 나중에 개발자가 원인을 분석하거나, DB 부하가 적은 새벽 시간에 별도의 배치 작업으로 재처리할 수 있습니다. 
 
요약하자면,
실무에서는 1) max.poll.records 같은 옵션으로 기본 처리량을 튜닝하고, 2) DB 상태를 모니터링하는 Circuit Breaker를 구현하며, 3) DB 장애 시 pause()를 호출하여 컨슈머를 능동적으로 멈추는(Backpressure) 방식을 가장 많이 사용합니다. 그리고 4) 반복적으로 실패하는 메시지는 DLQ로 격리하여 시스템 전체의 안정성을 확보합니다.
이러한 장치들을 통해 트래픽이 급증하더라도 카프카 토픽에 메시지가 좀 쌓일지언정(Lag 발생), 최종 관문인 DB가 다운되는 최악의 장애 상황을 방지할 수 있습니다.
다만 시스템 요구사항에 따라 위 내용이 적용 불가능한 상황도 있을겁니다. 상황에 따라 적절한 방식을 도입해야하고, 필요하다면 DB가 받는 부하를 분산하는 방법도 적용해보면 좋습니다.
DB 부하 분산 전략을 위한 핵심 키워드들은 다음과 같습니다.
- Read / Write 분리 (CQRS) 
- 데이터베이스 복제 (Replication): Read 부하 분산을 위한 'Read Replica(읽기 전용 복제본)' 활용 
- 데이터베이스 샤딩 (Sharding / Partitioning): Write 부하의 근본적인 분산 
- 캐시 (Cache) 활용: Redis, Memcached 등을 이용해 DB 조회 자체를 줄이기 
혹시 질문에 대한 답변이 됐을까요?
추가적으로 궁금한 내용 있으면 질문 남겨주세요.
감사합니다.
0
안녕하세요, 인프런 AI 인턴입니다. ssunn0812님.
카프카를 통해 DB Insert 요청을 비동기 처리하는 상황에서 트래픽이 급증할 경우, 데이터베이스 과부하를 방지하기 위한 여러 가지 방법이 있습니다. 다음의 방법들을 통해 실무에서 이러한 문제를 해결할 수 있습니다:
- Throttling: 처리할 수 있는 최대 QPS를 초과하지 않도록 카프카 컨슈머 레벨에서 데이터를 제한합니다. 즉, 한 번에 많은 양의 데이터를 처리하지 않고 일정 수만큼의 데이터만 처리하도록 합니다. 
- Batch Processing: 여러 개의 Insert 요청을 모아서 한 번에 처리하는 방식을 사용합니다. 이렇게 하면 네트워크 호출의 횟수를 줄이고 데이터베이스의 부하를 줄일 수 있습니다. 
- Backpressure: 시스템의 현재 상태를 고려하여 생산자와 소비자의 속도를 조절하는 기법입니다. 과부하 시에는 카프카 컨슈머가 데이터를 느리게 소비하거나 일시 중지하도록 합니다. 
- Load Balancing: 여러 데이터베이스 인스턴스를 사용하여 데이터베이스 부하를 분산시키는 방법입니다. 이를 통해 한 데이터베이스 인스턴스의 과부하를 방지할 수 있습니다. 
- Hystrix 사용: ‘서킷 브레이커’ 패턴을 적용하여, 데이터베이스 과부하 발생 시 요청을 차단하고 시스템을 보호할 수 있습니다. 
관련 주제에 대해 더 깊이 있는 논의를 확인할 수 있는 유사한 질문과 답변 링크도 공유합니다:
- Redis를 활용한 캐시와 트랜잭션 관리: 이 링크는 Redis 및 트랜잭션 관리 방식에 대한 논의들을 포함하고 있으며, 데이터 일관성과 멱등성을 어떻게 보장할 수 있는지 좋은 포인트들을 제공합니다. 
- 비동기 분리에 관한 논의: 비동기 처리 방식에서의 데이터 일관성 및 장애 해결 방안에 대한 여러 가지 접근 방법을 확인할 수 있습니다. 
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.





