01 카프카란?

등장 배경

  • 서비스마다 데이터를 직접 주고받으면 연결이 늘고, 한 시스템의 장애가 다른 시스템으로 번진다. LinkedIn은 대량의 로그·이벤트를 여러 시스템에 안정적으로 전달하려고 Kafka를 만들었다.

핵심 개념

  • Kafka: 이벤트를 분산 커밋 로그에 기록하는 이벤트 스트리밍 플랫폼. 메시징에도 쓰이지만, 소비했다고 기록이 즉시 사라지는 큐와 저장 방식이 다르다.
  • Producer → Topic(Partition) → Consumer: 프로듀서가 이벤트를 쓰고, 브로커가 파티션에 저장하며, 컨슈머가 읽는다.
  • 저장 구조: 토픽 → 파티션 → 세그먼트 파일. 레코드는 파티션 로그 끝에 추가되고, 파티션은 브로커 간 복제할 수 있다.
  • 파티션: 순서 보장·병렬 처리의 단위. 같은 키를 같은 파티션에 보내면 키별 입력 순서를 유지한다. 일반 컨슈머 그룹의 병렬 소비 상한은 파티션 수다.
  • 컨슈머 그룹·오프셋: 그룹마다 독립적으로 읽고, 그룹 안에서는 파티션 하나를 한 컨슈머가 맡는다. 읽은 위치는 오프셋으로 추적하며, 커밋한 그룹 오프셋은 Kafka에 저장된다. 그룹을 추가해 같은 로그를 읽을 수 있지만, 재읽기는 데이터 보관 범위 안에서만 가능하다.

왜 로그가 중요한가?

  • 성능: 순차 쓰기·배치 처리, OS 페이지 캐시 활용, 가능한 경로의 제로 카피로 처리량을 높인다. 제로 카피는 TLS 연결에선 사용되지 않는다.
  • 로그 ↔ 테이블: 키별 변경 로그를 순서대로 적용하면 현재 상태(테이블)를 만들 수 있다. 테이블 변경을 로그로 발행하면 CDC 같은 변경 피드가 된다. Kafka Streams의 KTable은 이런 최신 키별 상태의 뷰다.
  • 주의: 로그 순서만으로 분산 시스템 전체의 일관성이 보장되지는 않는다. 같은 파티션의 순서, 결정적 처리, 복제·장애 처리 조건이 맞아야 같은 결과를 얻는다. Event Sourcing은 이벤트를 원본으로 저장하는 방식, CQRS는 읽기·쓰기 모델 분리로 서로 필수 관계가 아니다.

로그 정리

  • Retention (delete): 시간·크기 기준으로 오래된 세그먼트를 삭제한다. 클릭·활동 이벤트처럼 이력 자체가 중요한 데이터에 적합하다.
  • Log compaction (compact): 키별 이전 값을 정리하고 최신 값을 남겨 현재 상태를 복원한다. 삭제를 뜻하는 tombstone과 보관 설정은 별도 고려가 필요하다. 전체 변경 이력을 영구 보존하는 방식은 아니다.

다른 메시징 도구와 차이

독립 소비·순서·병렬 처리 자체는 Kafka만의 기능이 아니다. 차이는 데이터를 어떻게 보관하고 확장하는지에 있다.

도구독립 소비·순서·병렬 처리Kafka와 비교해 선택할 이유
RabbitMQ 일반 큐여러 큐에 복사해 독립 소비. 같은 큐의 소비자는 작업을 나눔작업 분배, 복잡한 라우팅·재시도에 적합. 보통 확인된 메시지는 큐에서 삭제하므로 장기간 재읽기용 로그와는 다름
RabbitMQ Streams / Super Streams독립 재읽기 가능. Super Streams는 파티션별 순서·병렬 처리 지원Kafka와 기능이 많이 겹침. 기존 RabbitMQ 인프라·프로토콜이 있으면 좋은 선택. 스트리밍 처리 생태계와 장기 데이터 파이프라인은 별도 비교 필요
Redis Streams여러 컨슈머 그룹이 독립 소비. 한 스트림을 여러 컨슈머가 나눠 처리이미 Redis를 운영하고 규모가 감당되면 단순함. 단일 스트림은 Kafka 파티션처럼 자동 분산되지 않으며, 여러 컨슈머의 처리 완료 순서는 달라질 수 있음. 보관량·메모리·샤딩 고려
AWS SQS한 큐는 작업 분배. 독립 소비는 보통 SNS→여러 큐. FIFO는 MessageGroupId별 순서·그룹 간 병렬 처리완전 관리형 작업 큐에 적합. 처리 후 삭제하는 모델이라 한 로그를 여러 그룹이 원하는 시점부터 재읽는 용도와 다름. Standard 큐는 순서 보장 없음

실무에서 Kafka를 선택하는 이유

  • 공유 이벤트 이력: 주문 이벤트를 결제·알림·분석 서비스가 각자 소비하고, 새 서비스를 붙이거나 장애 후 보관 범위 안의 데이터를 다시 처리해야 할 때. 서비스마다 큐를 따로 복제할 필요가 없다.
  • 지속적인 대량 수집: 로그·클릭·CDC처럼 유입이 계속 많고, 보관·재처리도 필요할 때. 파티션을 브로커에 분산하고 배치·순차 I/O로 처리량을 키운다. 처리량·지연은 배치 크기, 복제, 디스크, 네트워크와 설정에 따라 달라진다.
  • 데이터 파이프라인·상태 처리: 같은 이벤트 흐름을 여러 시스템에 연결하거나, Kafka Connect·Streams 등으로 변환·집계·조인·상태 복원을 구성할 때.
  • 선택 비용: 파티션 키와 개수, 보관 기간, 컨슈머 지연, 재처리·중복 처리, 클러스터 운영을 설계해야 한다. Kafka가 항상 더 빠른 것은 아니다. 특히 RabbitMQ Streams도 로그·파티션·높은 처리량을 지원한다.

언제 쓰나?

  • Kafka: 여러 소비자가 공유할 이벤트 이력 + 지속적인 대량 처리·재읽기·데이터 파이프라인이 함께 필요할 때.
  • 다른 도구: 단순 비동기 작업은 SQS·RabbitMQ 큐, 이미 Redis를 쓰는 제한된 규모의 스트림은 Redis Streams, 기존 RabbitMQ 기반 스트리밍은 RabbitMQ Streams부터 검토. 즉시 응답이 필요한 요청은 HTTP 같은 동기 호출.

참고: Kafka 소개 · Kafka 설계 · RabbitMQ Streams · Redis Streams · SQS FIFO · SNS→SQS · 카프카의 탄생과 미래


참고) HTTP와 Kafka

  • HTTP vs. Kafka

    • HTTP
      • 전화에 비유
      • 요청을 하면 응답이 온다
      • 한 번에 하나의 서버에만 요청 가능
    • Kafka
      • 메시지에 비유
      • 요청만 할 수 있다
      • 한번 요청을 하면 해당 요청에 관련된 모든 서버(컨슈머)에게 요청이 전달 된다.
  • HTTP 요청 응답식으로 운용하는 MSA

    • ex) 회원 모듈에서 해당 회원의 프로필 정보를 보여줄 때, 올해 결제금액을 보여줘야한다면
      • -> 회원 서비스에서 결제 서비스로 HTTP 요청을 통해 알아낼 수 있다
    • 문제: MSA 라면 각각 데이터베이슬르 운용하고, 회원 모델을 각각 운용할 수 있을 것이다.
      • ex) 장바구니와 알림 서비스에서는 빈번하게 회원 정보를 얻어내야 하는 상황이 있어서 회원정보를 각각 유지하고 사용
      • => 회원 생성·수정·삭제 발생 시, 회원 모델을 운용하는 각 서비스에 매번 생성·수정·삭제 동기화를 HTTP 요청으로 해주어야 한다.
    • 이렇게 매번 다른 서비스에 '전화'를 거는 것보다는, 단톡방에 '메시지'로 공지하는게 편하다. 특정 서비스가 바빠서 이벤트를 당장 수신하지 못하더라도, 추후 확인 가능하다.
    • => 카프카를 사용하는 이유