Posts Kafka를 활용한 대용량 이벤트 처리 구조 설계와 성능 비교
Post
Cancel

Kafka를 활용한 대용량 이벤트 처리 구조 설계와 성능 비교

목적

  • 서비스에서 처리량이 증가하거나 작업 시간이 길어지는 상황에서
    기존의 동기식 직접 DB 접근방식이 가진 한계를 확인하고
    Kafka 기반 비동기 처리 구조의 성능 및 안정성을 확인하기 위함

실험환경

  • 애플리케이션Kotlin Spring Boot 기반 API 서버
  • DB: MariaDB
  • Kafka: 단일 노드
  • 트랜잭션 타임아웃: 1분
  • 인위적 딜레이: 일부 실험에서 0.3초 지연 삽입
  • 성능 측정 도구: k6
    • vus: 1000(가상 유저 1000명)
    • durations: 5m (총 5분간 실행)
    • iterations: 3000 (총 요청 수:30000)

측정 기준

  • 처리 시간 (diffSec)
    • inventory: 첫 번째 행의 createdAt과 마지막 행의 createdAt의 차이
    • order: 동일한 행의 createdAt과 updatedAt의 차이
  • 실패율 (Failure Rate)
    • 부하 테스트 도구 k6 기준
    • rate: 실패율 (0.0 = 모두 성공, 1.0 = 모두 실패)
    • passes: 실패 요청 수 (예: HTTP 오류)
    • fails: 성공 요청 수
    • 추가적으로 DB에 실제 반영된 quantity 값도 함께 검토

실험 결과 요약

  • Inventory 삽입 (3000건)
    1
    2
    3
    4
    5
    6
    7
    
    | 실험       | 방식                        | 파티션/배치   | 락     | 처리 시간 (초) | 실패율 | 결과 |  
    |------------|-----------------------------|---------------|--------|----------------|--------|--------|  
    | inventory1 | 직접 DB 접근                | -             | 없음   | 30             | 0.0    | ✅     |  
    | inventory2 | Kafka + 단일 파티션         | 단건          | 없음   | 34             | 0.0    | ✅     |  
    | inventory3 | Kafka + 3파티션             | 단건          | 없음   | 27             | 0.0    | ✅     |  
    | inventory4 | Kafka + 3파티션             | 배치(20건)    | 없음   | 18         | 0.0    | ✅     |  
                
    
  • 단일 Order UDATE -딜레이 없음 (최초 삽입 1건, 갱신 3000건)
    1
    2
    3
    4
    5
    6
    
    | 실험   | 방식                  | 락         | Kafka 파티션 | 처리 시간 (초) | 실패율 | 결과 |  
    |--------|-----------------------|------------|----------------|----------------|--------|--------|  
    | order1 | 직접 DB 접근          | 비관적 락  | 없음           | 49             | 0.0    | ✅     |  
    | order2 | Kafka 컨슈머          | 없음       | 1개            | 52             | 0.0    | ✅     |  
    | order3 | Kafka 컨슈머          | 비관적 락  | 3개            | 38             | 0.0    | ✅     |  
                
    
  • 단일 Order UPDATE - 딜레이 0.3초(타임아웃 1분, 최초 삽입1건, 갱신 3000건)
    1
    2
    3
    4
    5
    6
    
    | 실험    | 방식               	       | 락         | Kafka 파티션 | 처리 시간 (초) | 처리된 quantity | 실패율 | 결과 |  
    |---------|----------------------------|------------|----------------|----------------|------------------|--------|--------|  
    | order1 | 직접 DB 접근               | 비관적 락  | 없음           | 303            | 328              | 0.972  | ❌     |  
    | order2 | Kafka 컨슈머                | 없음       | 1개            | 384            | 3001             | 0.0    | ✅     |  
    | order3 | Kafka 컨슈머                | 비관적 락  | 3개            | 333            | 3001             | 0.0    | ✅     |  
                
    

실패율 상세

  • k6 실패율 계산 기준
    • rate: 실패율 (0.0 = 100% 성공, 1.0 = 100% 실패)
    • passes: 실패 요청 수 (예: HTTP 500 등)
    • fails: 성공 요청 수
    • 실패율 = passes / (passes + fails)
  • 실패 발생 실험: order1(직접 DB 접근 + 딜레이)
    • 요청 기준 성공률: 약 2.8%(84/3001)
    • 실제 DB 반영 성공 수량: 328건
      • 일부 실패 응답이 DB에는 성공적으로 반영된 것으로 추정

결론

  • Kafka 기반의 비동기 처리 구조는 직접 DB 접근 방식에 비해
    다음의 이점을 갖는다.
  • 높은 안정성
    • 직접 DB 접근 방식은 요청이 몰릴수록 트랜잭션 충돌, 락 경합, 커넥션 부족등의 이슈로 인해 실패율이 높아지는 경향이 있다.
    • 특히 급격하게 트래픽이 몰려 DB 커넥션이 부족해지고 트랜잭션 처리 시간이 길어질 경우 실패율이 급격히 올라가며, 동시에 DB 부하도 높아져 다른 기능에 영향을 준다.
    • 반면 Kafka 비동기 구조에서는 모든 요청을 큐잉하고 순차적으로 처리하기 때문에 요청량이 일시적으로 급증하더라도 상대적으로 안정적으로 처리 흐름을 유지할 수 있다.
  • 수평적 확장성
    • Kafka는 파티션을 추가 및 컨슈머 수를 늘리고,
      배치 처리(batch)를 도입함으로써
      처리 성능을 선형적으로 확장할 수 있다.
    • 실제 실험에서도 Kafka 파티션 수를 늘리고 배치 처리까지 도입하자
      처리 시간(diffSec)이 눈에 띄게 줄어들었다.
    • 즉, 트래픽이 늘어나더라도 유연하게 대응할 수 있는 구조이다.
  • DB 부하 감소 및 시스템 전반의 응답성 향상
    • Kafka 구조는 비동기 방식으로 동작하기 때문에, 사용자 요청 시점에 DB에 직접 접근하지 않는다.
    • 내부 처리 과정에서 병목이 발생하더라도, 요청을 Kafka가 우선 수신하고 처리하므로 DB에는 상대적으로 여유 있는 요청만 전달된다.
    • 이로 인해 과도한 동시 요청이 DB에 몰리는 상황을 효과적으로 방지할 수 있다.
    • 실험 결과에서도 이런 차이는 명확히 드러난다.
    • 직접 DB 접근 방식에서는 트래픽이 몰려 DB 타임아웃이 발생한 이후부터는 조회 요청까지 큰 지연을 겪었다.
    • 반면 Kafka 기반 구조는 처리 작업과 조회 요청이 서로 영향을 받지 않기 때문에, 초기 몇 초를 제외하고는 조회 응답 시간이 안정적으로 유지되었다.

번외 - 스티키 파티셔너 vs 라운드로빈 파티셔너

  • 기존 실험에서는 프로듀서에서 파티션 키를 설정하지 않았기 때문에
    기본 설정인 스티키 파티셔너를 사용했다.
  • 이번에는 파티션을 3개 사용하는 테스트 시나리오만 모아,
    프로듀서에서 랜덤 키를 설정하여 라운드로빈 파티셔너를
    사용하도록 실험하였다.
  • 두 파티셔너 간의 처리 시간 차이 비교
    1
    2
    3
    4
    5
    6
    7
    
    | 항목 | Sticky 파티셔너 | Round-Robin 파티셔너 | 차이  |  
    |------|------------------|------------------------|--------|  
    | Order3 (딜레이 없음, 갱신) | 38초 | 39초 | +1초 |  
    | Order3 (딜레이 있음, 갱신) | 333초 | 346초 | +13초 |  
    | Inventory3 (파티션 3개, 삽입) | 27초 | 32초 | +5초 |  
    | Inventory4 (파티션 3개, 배치 삽입) | 18초 | 25초 | +7초 |  
                
    
  • 모든 항목에서 Sticky 파티셔너가 Round-Robin 파티셔너보다
    더 빠른 처리 속도를 보였다.

참고

This post is licensed under CC BY 4.0 by the author.