[Apache Kafka] 메시지 처리 동작 원리 + Offset과 Commit

2025. 4. 9. 20:44
반응형

 

Apache Kafka는 대용량의 이벤트 데이터를 처리하기 위한 분산 스트리밍 플랫폼이다. Kafka를 사용하는 대부분의 상황에서는 메시지를 안정적으로 읽고 필요한 처리를 수행한 뒤 중복 없이 다음 메시지를 이어서 처리하는 것이 중요하다.

 

이 과정의 핵심 개념이 바로 OffsetCommit이다. 이번 포스팅에서는 Kafka의 메시지 처리 흐름을 이해하는 데 필수적인 Offset과 Commit에 대해 정리하고, 자동 커밋과 수동 커밋 방식의 차이와 선택 기준에 대해서 소개한다.

 

 

 


Offset

 

Kafka의 메시지는 Topic 내부의 Partition에 저장되며 각각의 메시지에는 고유한 일련번호가 붙는다. 이 번호를 Offset이라고 하며 Partition 내에서의 메시지 위치를 나타낸다.

 

예를 들어, Partition 0에 저장된 메시지 중 가장 첫 번째 메시지의 Offset은 0이며, 이후 순차적으로 증가한다.

 

Kafka의 Consumer는 이 Offset을 기준으로 메시지를 읽는다. 즉, "현재 내가 어디까지 메시지를 읽었는가"를 추적하는 단위가 Offset이다. 이 값을 적절히 관리하면, Consumer는 재시작하더라도 이전에 읽은 위치부터 다시 이어서 메시지를 소비할 수 있다.

 

  • Offset은 Partition 내에서 각 메시지의 고유한 순번이다.
  • Consumer는 Offset을 기준으로 메시지를 순차적으로 읽는다.
  • Offset 정보를 저장하고 활용함으로써 메시지를 이어서 안정적으로 처리할 수 있다.

 

 

 


Kafka의 순서 보장

 

 

  1. Kafka는 Partition 단위로 메시지의 순서를 보장한다.
  2. 각 Partition의 메시지는 Offset을 기준으로 순차적으로 저장된다.
  3. 메시지 순서를 보장해야 한다면 동일한 Key를 설정하여 같은 Partition에 할당하여 순서 보장이 가능하다. 
    • Producer가 Key를 명시한 경우 : 같은 Key를 가진 메시지들은 해시 기반으로 항상 같은 Partition으로 전송된다. (단 Producer가 기본 설정(DefaultPartitioner)을 사용할 때)
    • Key를 지정하지 않은 경우 : Kafka는 Round-Robin 방식으로 메시지를 여러 Partition에 분산시킨다. 즉 순서를 보장할 수 없다.

 

Kafka는 메시지의 순서를 보장하기 위해 Partition과 Offset 개념을 함께 활용한다. 각 Partition 내에서는 메시지가 순차적으로 기록되며, 각 메시지는 고유한 Offset을 가진다.

 

이 Offset은 순차 증가하기 때문에 하나의 Partition에서 메시지는 항상 입력된 순서대로 소비된다. 따라서 특정 유형의 메시지의 순서를 보장해야 한다면 Key를 설정하여 같은 Partition으로 전송되도록 설정하면 된다.

 

 

 

 

 


Kafka의 메시지 소비 원리

 

메시징 시스템으로서 Kafka가 가지는 주요 특징은 다음과 같다.

Pub/Sub 구조, 1:N 메시지 전달 : 하나의 메시지를 여러 Consumer Group이 독립적으로 소비할 수 있다.
메시지 보존: 메시지는 소비된 후에도 일정 기간 동안 삭제되지 않으며, 디스크에 저장된다.
순서 보장: 파티션 내에서는 메시지의 순서가 보장된다.
전송 방식: Consumer가 poll()을 통해 스스로 메시지를 가져가는 Pull 방식이다 (Offset 기반).

 

https://medium.com/gong-tech-blog/how-we-use-kafka-to-maintain-tenant-data-isolation-at-scale-ad501f2dc572

 

Kafka의 동작

  • Kafka의 메시지 소비는 기본적으로 Pull 기반으로 작동한다.
  • Consumer는 주기적으로 poll() 요청을 보내며, 아직 읽지 않은 메시지를 요청하고 가져온다.
  • Kafka는 해당 Consumer Group이 마지막으로 커밋한 Offset을 기준으로 이후의 메시지를 전달한다.
  • 한편 Kafka는 소비된 메시지를 바로 삭제하지 않고 일정 기간 동안 보존한다.

 

동일한 메시지를 다수의 Consumer들이 읽을 수 있는 이유

  • 각 Consumer Group은 독립적인 Offset 정보를 관리하기 때문에 여러 Consumer Group이 하나의 Topic을 구독하더라도 서로 다른 시점부터 동일한 메시지를 읽을 수 있다.
  • 메시지가 소비되더라도 삭제하지 않기 때문에 특정 Consumer Group에서 해당 Offset의 메시지를 읽지 않았다면 소비 가능하다.
  • RabbitMQ나 Amazon SQS 같은 메시지 큐는 메시지를 한 번 소비하면 즉시 삭제하는 구조다. 기본적으로는 1:1 전달 방식이며, 메시지를 여러 Consumer가 동시에 소비하기 위해서는 별도의 설정이나 구조가 필요하다.

 

 

 

 

 


Commit

 

Kafka에서 메시지를 읽었다는 것은 단순히 데이터를 가져온 것일 뿐, 처리가 완료되었다는 의미는 아니다. 메시지를 정상적으로 처리 완료했음을 Kafka에 알리기 위해서는 Commit 작업이 필요하다.

 

 

  1. Commit은 메시지 처리 완료의 표시다 : Kafka에 "이 Offset까지는 정상적으로 처리되었음"을 알리는 작업이다.
  2. Commit이 있어야 다음 메시지를 받을 수 있다 : Kafka는 커밋된 Offset을 기준으로 다음 메시지를 Consumer에게 전달한다.
  3. Commit 정보는 Kafka 내부 토픽에 저장된다 :  __consumer_offsets라는 내부 토픽에 각 Consumer Group의 Offset 상태가 기록된다.
  4. Commit하지 않으면 같은 메시지가 다시 전달된다 : 실패하거나 누락된 커밋이 있다면, Kafka는 해당 Offset부터 메시지를 다시 전송한다.

 

 


자동 커밋과 수동 커밋

 

Kafka에서 메시지를 읽고 난 뒤 처리 완료를 Kafka에 알리는 방법에는 자동 커밋(Auto Commit)수동 커밋(Manual Commit) 두 가지 방식이 있다.

 

 

자동 커밋 : Kafka가 주기적으로 Offset을 자동 저장하는 방식으로 구현이 간단하지만 메시지가 실제로 처리되었는지와 관계없이 커밋이 이뤄질 수 있다.

  • 장점 
    • 간단한 구현: 설정만으로 자동으로 커밋되기 때문에 코드가 간단하다.
    • 빠른 처리 흐름: 별도의 커밋 로직 없이 메시지 소비와 커밋이 동시에 이뤄져 빠르다.
  • 단점
    • 유실 가능성: 메시지를 처리하기도 전에 커밋이 완료되면, 처리 도중 장애 발생 시 메시지가 유실될 수 있다.
    • 제어 불가: 커밋 타이밍이 정해져 있기 때문에 예외나 롤백 조건에 따라 동적으로 제어하기 어렵다

 

 

수동 커밋  : 메시지를 처리한 후 개발자가 명시적으로 커밋을 수행하는 방식으로 처리 완료 여부에 따라 커밋을 제어할 수 있어 정확한 제어가 가능하다. 

  • 장점 
    • 정확한 처리 제어: 메시지 처리 성공 여부에 따라 커밋 여부를 개발자가 명확히 제어할 수 있다.
    • 장애 복구 용이: 커밋되지 않은 메시지는 다시 전달되므로 실패한 작업을 재처리할 수 있다. 따라서 예외 발생(Catch)나 애플리케이션의 비정상 종료에 따른 메시지 처리 재시도가 가능하다.
  • 단점
    • 무한 루프 위험: 예외 발생 후 커밋이 누락되면 Kafka는 동일 메시지를 반복 전송하게 되며 재시도 로직이 없다면 무한 루프에 빠질 수 있다.
    • 복잡한 예외 처리 필요: 수동 커밋은 성공 여부뿐 아니라 예외 분기, 재시도 횟수, DLQ(Dead Letter Queue) 구성 등 다양한 실패 대응 전략을 함께 고려해야 한다.
  • 고려할 점
    • 재시도 횟수 제한: 메시지에 Retry Count를 기록하여 일정 횟수 이상 실패한 메시지는 별도로 분기한다.
    • Dead Letter Queue(DLQ): 처리 실패한 메시지를 별도의 큐(DLQ)에 저장하고 본 처리 로직에서는 커밋한 뒤 건너뛴다.
    • 예외 유형 분기 처리: 복구 가능한 예외인지 여부를 판단하여 커밋 여부를 동적으로 결정한다.

 

Spring Kafka에서는 다음과 같이 application.yml이나 properties 설정에서 다음과 같이 자동 커밋 활성화 여부를 조절할 수 있다.

spring:
  kafka:
    consumer:
      enable-auto-commit: false

 

 

 

 

 

 

 


References

 

  https://kafka.apache.org/documentation/

 

Apache Kafka

Apache Kafka: A Distributed Streaming Platform.

kafka.apache.org

 

 

 

반응형

BELATED ARTICLES

more