티스토리 뷰
이전글:2025.05.02 - [기술노트/Apach Kafka] - Kafka 기초2 - 프로듀서 & 메세지
이전 글에서는 카프카로 데이터를 보내는 프로듀서에 대해 알아보았다.
이번 글에서는 프로듀서가 보낸 데이터를 실제로 읽어와 처리하는 카프카 컨슈머(Consumer) 에 대해 다뤄보겠다.
컨슈머(Consumer)란?
카프카에서 컨슈머란 카프카 토픽(Topic)에 저장된 데이터를 읽어오는 컴포넌트이다.
프로듀서가 데이터를 생산하는 주체라면, 컨슈머는 해당 데이터를 소비하는 역할을 한다.
컨슈머는 풀(Pull) 방식으로 동작한다.
풀 방식이란 컨슈머가 능동적으로 카프카 브로커에 데이터를 요청하여 가져오는 구조다.
이는 브로커가 일방적으로 데이터를 컨슈머에게 밀어 넣는 푸시(Push) 방식과는 대조되는 방식이며,
컨슈머가 자신의 처리 능력에 맞게 데이터 흐름을 조절할 수 있다는 장점이 있다.
백프레셔(Backpressure)
백프레셔(Backpressure)는 생산자(Producer)와 소비자(Consumer) 사이에서 소비자가 처리할 수 있는 속도보다 데이터가 더 빠르게 유입될 경우, 데이터 흐름을 제어하여 시스템의 안정성을 유지하는 메커니즘이다
컨슈머의 데이터 읽기
카프카의 토픽은 하나 이상의 파티션으로 구성되며,
컨슈머는 이런한 파티션으로부터 데이터를 읽어온다.
하나의 컨슈머는 하나 이상의 파티션에서 데이터를 읽어올 수 있고 각 파티션 내에서는 메세지가 저장된 순서,
즉 오프셋(Offset) 순서대로 데이터를 읽는다.
예를 들어, 특정 파티션에서 오프셋 0번 메세지를 읽은 후에는 1번, 그 다음에는 2번 메세지를 순차적으로 읽게 된다. 이는 같은 파티션 단위에서 데이터 처리 순서를 보장한다.
(다른 파티션 간의 데이터 읽기 순서는 보장되지 않는다.)
컨슈머는 데이터를 읽는 과정에서 오프셋을 커밋하는데,
이는 컨슈머가 각 파티션 별로 어떤 오프셋까지 읽었는지를 확인하기 위한 작업이다.
커밋된 오프셋은 __consumer_offsets 이라는 내부 토픽에 저장된다.
커밋은 주기적으로 저장하는 자동 커밋과 명시적으로 커밋을 호출하는 수동 커밋이 있다.
역직렬화기 (Deserializer)의 역할
카프카에서 메세지를 주고받을 때 기본적으로 바이너리(byte 배열) 형태로 데이터를 전송한다.
프로듀서가 특정 객체(예: 문자열, 숫자, 사용자 정의 객체)를 바이트 배열로 변환하여 카프카에 전송했다면,
컨슈머는 이 바이트 배열을 다시 원래의 객체 형태로 복원해야 한다.
이러한 변환 과정을 역직렬화(Deserialization)라고 하며,
이 역할을 수행하는 컴포넌트가 바로 역직렬화기(Deserializer)이다.
컨슈머는 수신한 메시지의 키(Key)와 값(Value)에 대해 각각 적절한 역직렬화기를 설정해야 한다.
예를 들어, 프로듀서가 메시지 키를 정수(Integer)로, 값을 문자열(String)로 직렬화하여 전송했다면, 컨슈머는 다음과 같이 역직렬화기를 설정해야 한다.
- 키(Key) 역직렬화기: IntegerDeserializer
- 값(Value) 역직렬화기: StringDeserializer
컨슈머는 어떻게 데이터 타입을 알까?
결론부터 말하면 컨슈머는 메세지 타입을 미리 알고 있지 않으면 알 수가 없다.
카프카에서 프로듀서가 보내는 메시지에는 데이터 타입이 포함되어 있지 않으며, 컨슈머는 이를 자동으로 인식할 방법이 없다. 컨슈머가 역직렬화기를 구성하기 위해서는 사전에 정의된 규칙이나 프로듀서가 직접 알려주는 방법밖에 없다.
프로듀서에서 보낸 메시지가 직렬화되어 컨슈머에 도착했을 때는 아래와 같은 형태의 이진 데이터일 뿐이다.
Key: [01000011 01000001]
Value: [01101000 01100101 01101100 01101100 01101111]
컨슈머는 이러한 직렬화된 데이터를 보고 어떻게 역직렬화해야 할지 스스로 판단할 수 없다.
이 바이너리가 정수인지, 문자열인지, 혹은 복잡한 객체인지 알 수 없기 때문이다.
카프카는 다양한 언어와 시스템에서 범용적으로 사용될 수 있어야 한다. 그래서 카프카는 메시지를 해석하는 책임을 컨슈머 쪽으로 위임한다. 이는 유연성을 확보하는 대신, 명확한 데이터 계약(Contract) 이나 스키마 관리가 필수적이라는 의미이기도 하다.
카프카는 메시지 타입을 자동으로 알려주지 않기 때문에, 실무에서는 다음과 같은 방법들이 활용된다:
방법 | 설명 |
---|---|
명시적 계약 | 토픽마다 key/value의 데이터 타입을 문서화하여 모든 시스템이 공유 |
스키마 레지스트리 | Avro, Protobuf, JSON Schema 등의 스키마를 중앙에서 관리하고 메시지에 스키마 ID를 포함시켜 전송 |
토픽 네이밍 규칙 | order-created-json , user-updated-avro 처럼 형식을 이름에 포함 |
Kafka 헤더 사용 | 메시지 header에 "key-type": "int" , "value-type": "json" 등의 정보 포함 |
Custom Serializer/Deserializer | 타입 정보까지 포함하는 사용자 정의 직렬화 포맷 사용 |
지원되는 역직렬화 형식
카프카는 다양한 기본 데이터 타입 및 표준 직렬화 형식을 위해 다음과 같은 형식을 제공한다.
- StringDeserializer
- IntegerDeserializer, LongDeserializer
- FloatDeserializer, DoubleDeserializer
- BytesDeserializer
또한, 스키마 레지스트리(Schema Registry)와 함께 사용되는
AvroDeserializer, ProtobufDeserializer, JsonSchemaDeserializer 등도 널리 사용된다.
필요에 따라서는 특정 비즈니스 로직에 맞는 사용자 정의 역직렬화기를 구현하여 사용할 수도 있다.
맺음말
지금까지 카프카에서 데이터를 소비하는 핵심 주체인 컨슈머에 대해 자세히 알아보았다.
컨슈머가 어떻게 토픽의 파티션으로부터 데이터를 순서대로 읽어오는지, 그리고 이 과정에서 역직렬화기가 바이트 형태의 메시지를 실제 애플리케이션에서 사용할 수 있는 객체로 변환하는 중요한 역할을 수행함을 이해하는 것은 안정적인 데이터 파이프라인 구축에 있어 필수적이다. 또한, 데이터 타입의 일관성 유지가 왜 중요한지에 대해서도 인지해야 한다.
다음 글에서는 여러 컨슈머가 협력하여 데이터를 병렬적으로 처리하는 강력한 기능인 컨슈머 그룹(Consumer Group) 에 대해 심도 있게 다뤄보겠다.
참고 및 출처
'기술노트 > Apach Kafka' 카테고리의 다른 글
Kafka 기초5 - 브로커(Broker) (0) | 2025.05.19 |
---|---|
Kafka 기초4 - 컨슈머 그룹 (0) | 2025.05.16 |
Kafka 기초2 - 프로듀서 & 메세지 (0) | 2025.05.02 |
Kafka 기초1 - 토픽, 파티션, 오프셋 (0) | 2025.05.02 |
Kafka 기초0 - Apache Kafka란 (0) | 2025.05.02 |
- Total
- Today
- Yesterday
- apach kafka
- 디커플링
- Apache kafka
- 클러스터
- sticky partitioner
- Consumer
- 브로커
- Kafka
- 파티션
- 백프레셔
- 라운드로빈
- 프로듀서
- 소비자
- 아파치카프카
- kafak
- Serializer
- 컨슈머그룹
- 카프카
- 역직렬화
- 컨슈머
- 키 기반 파티셔닝
- 메세지
- 토픽
- broker
- 오프셋
- 분산서비스
- Cluster
- 직렬화
- 파티셔닝
- Producer
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |