<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kafka on Jiho Kim</title><link>https://blog.wlgh7407.com/tags/kafka/</link><description>Recent content in Kafka on Jiho Kim</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Thu, 22 Oct 2026 15:53:46 +0900</lastBuildDate><atom:link href="https://blog.wlgh7407.com/tags/kafka/index.xml" rel="self" type="application/rss+xml"/><item><title>Kafka-01 Kafka는 무엇이고 언제 사용할까?</title><link>https://blog.wlgh7407.com/posts/dev/261022_dev_kafka-01-kafka%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4%EA%B3%A0-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C/</link><pubDate>Thu, 22 Oct 2026 15:53:46 +0900</pubDate><guid>https://blog.wlgh7407.com/posts/dev/261022_dev_kafka-01-kafka%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4%EA%B3%A0-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C/</guid><description>&lt;p&gt;&lt;img
 src="https://blog.wlgh7407.com/images/Pasted%20image%2020261022160739.png"
 alt="Image Description"loading="lazy"&gt;&lt;/p&gt;
&lt;h2 id="-상세-정리"&gt;&lt;a href="#-%ec%83%81%ec%84%b8-%ec%a0%95%eb%a6%ac" class="header-anchor"&gt;&lt;/a&gt;📝 상세 정리
&lt;/h2&gt;&lt;h3 id="1-kafka는-왜-필요할까"&gt;&lt;a href="#1-kafka%eb%8a%94-%ec%99%9c-%ed%95%84%ec%9a%94%ed%95%a0%ea%b9%8c" class="header-anchor"&gt;&lt;/a&gt;1. Kafka는 왜 필요할까?
&lt;/h3&gt;&lt;p&gt;일단 이와 같은 서비스를 운영하고 있다고 생각해보자.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;거래 발생 -&amp;gt; DB 저장 -&amp;gt; 이메일 서비스 호출 -&amp;gt; 이상거래 탐지 서비스 호출 -&amp;gt; 통계 서비스 호출
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이런식으로 한 트랜잭션에 대해, 그 결과를 필요로 하는 시스템이 덕지덕지 붙어있다고 생각해보자.
여기서 다음과 같은 이슈들이 발생하면 어떻게 될까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이메일 서비스가 조금 느리다면?&lt;/li&gt;
&lt;li&gt;이상거래 탐지 서비스가 30초동안 죽어있는다면?&lt;/li&gt;
&lt;li&gt;통계 서비스에서 버그가 발견되어서 어제 발생한 모든 거래를 다시 처리하고싶다면?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;첫번째 질문에 대해선 당연히 병렬화를 기대할 수 있겠다. 저렇게 직렬적으로 꽂는게 아니라, 거래가 DB저장을 성공적으로 수행한다면, 나머지 서비스 시스템들을 다 비동기로 실행하면 더 좋겠다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;그런데 거래 API가 호출한 직후 죽거나, 한 서비스가 오랫동안 응답하지 않는다면?&lt;/li&gt;
&lt;li&gt;누가 어떤 작업까지 성공적으로 수행했는지를 어떻게 확인하지?&lt;/li&gt;
&lt;li&gt;또한, 어떤 서비스 하나가 실패했다고 해서 DB 저장까지 전부 롤백해야할까?
&lt;ul&gt;
&lt;li&gt;서비스들이 너무 강하게 연결된 것 아닐까? (coupling 문제)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만 &lt;a class="link" href="https://blog.wlgh7407.com/posts/dev/260823_dev_the-google-file-system-2003/" &gt;GFS&lt;/a&gt;라던가 DDIA등을 읽어본 우리들은 로깅을 통해 이런 상황을 해결할 수 있다는 것을 본 적이 있다. 어떤 다른 저장소에 트랜잭션같은 정보를 저장해두고, 이를 각 서비스가 필요할 때 읽도록 하면 되지 않을까?
또한 그렇다면 과거 정보/이벤트를 다시 읽어서 처리하는것 또한 가능해질 것이다.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;이를 재처리(Replay)라고 한다.&lt;/p&gt;

 &lt;/blockquote&gt;

&lt;p&gt;결국 하고싶은건, &lt;strong&gt;거래가 발생했다는 사실을 독립적으로 보관하고, 필요한 서비스들이 각자의 속도로 읽게 하는 것&lt;/strong&gt;
Kafka는 이런 이벤트 흐름을 다루기 위해 만들어진 &lt;strong&gt;분산 이벤트 스트리밍 플랫폼&lt;/strong&gt; 이다.&lt;/p&gt;
&lt;h3 id="2-kafka-기본-용어"&gt;&lt;a href="#2-kafka-%ea%b8%b0%eb%b3%b8-%ec%9a%a9%ec%96%b4" class="header-anchor"&gt;&lt;/a&gt;2. Kafka 기본 용어
&lt;/h3&gt;&lt;p&gt;이제 카프카를 언제 쓰는지 어렴풋이 알았으니, 위 예시에 맞춰 구체적인 용어들을 알아보자.
거래 발생을 예시로 들거고, 각 필드의 뜻은 아래와 같다.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;필드&lt;/th&gt;
 &lt;th&gt;의미&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;event_id&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;거래 이벤트의 고유 식별자&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;account_id&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;거래가 발생한 계좌 ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h5 id="record--레코드"&gt;&lt;a href="#record--%eb%a0%88%ec%bd%94%eb%93%9c" class="header-anchor"&gt;&lt;/a&gt;Record / 레코드
&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;Kafka가 다루는 가장 작은 데이터 단위&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;예를 들면 다음과 같겠다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e-001&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;account_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;acct-001&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;그냥 뭐.. 1번 계좌가 1번 이벤트 발생시킨 간단한 상황만 신경써보자.&lt;/p&gt;
&lt;h5 id="topic--토픽"&gt;&lt;a href="#topic--%ed%86%a0%ed%94%bd" class="header-anchor"&gt;&lt;/a&gt;Topic / 토픽
&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;데이터가 모이는 논리적 공간&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;우리가 저장할 데이터는 하나만 있지 않다. 예를들어, 거래 발생이벤트인 &lt;code&gt;trades.raw&lt;/code&gt;, 사용자 가입 이벤트인 &lt;code&gt;user.registered&lt;/code&gt; 등이 있을 수 있다. 이 각각을 &lt;strong&gt;Topic&lt;/strong&gt;이라 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DB의 테이블이랑 비슷한 느낌이라고 생각하면 좋을듯&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="partition--파티션"&gt;&lt;a href="#partition--%ed%8c%8c%ed%8b%b0%ec%85%98" class="header-anchor"&gt;&lt;/a&gt;Partition / 파티션
&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;하나의 Topic을 나누는 단위&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;초당 수십만건의 이벤트가 발생한다고 하면, 모든 이벤트를 순서대로 처리하는 방식은 병목이 될 수 있다.
대신 이를 Partition으로 나누어서 데이터를 &lt;strong&gt;분산 저장&lt;/strong&gt;하고 여러 &lt;strong&gt;consumer&lt;/strong&gt;이 병렬로 처리하도록 할 수 있다.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Kafka는 Topic 전체의 메세지 순서는 보장하지 않지만, 각 Partition 내부에서의 순서는 보장한다.&lt;/p&gt;

 &lt;/blockquote&gt;

&lt;h5 id="key--키"&gt;&lt;a href="#key--%ed%82%a4" class="header-anchor"&gt;&lt;/a&gt;Key / 키
&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;Partition 혹은 Record를 구분할 때 사용하는 값&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kafka Record는 Key-Value를 넣을 수 있다.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;key = acct-001
value = {&amp;#34;event_id&amp;#34;:&amp;#34;e-001&amp;#34;,&amp;#34;account_id&amp;#34;:&amp;#34;acct-001&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;어떤 Record를 각 Partition으로 보낼 때, 기본적으로는 GFS에서 했던것과 같이 key를 해싱한값을 기반으로 한다. 따라서 &lt;strong&gt;순서를 보장하고 싶은 데이터가 있다면 해당 데이터들은 같은 파티션 안에 들어갈 수 있도록 해야한다.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;파이썬의 dict나 cpp의 set같은 느낌이 아니다!&lt;/li&gt;
&lt;li&gt;같은 key의 데이터가 여러개 있어도 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예를 들어 위와 같은 상황에 key값을 &lt;code&gt;event_id&lt;/code&gt;로 한 상황과 &lt;code&gt;account_id&lt;/code&gt;로 한 상황 두가지를 생각해보자.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;만약 &lt;code&gt;account_id&lt;/code&gt;로 했다면 같은 계좌는 같은 key를 가지므로 같은 Partition 안에 들어가게 되고, 각 계좌에 대한 이벤트는 기록된 순서가 보장된다.&lt;/li&gt;
&lt;li&gt;하지만 &lt;code&gt;event_id&lt;/code&gt;를 key로 했다면 같은 계좌가 다른 Partition에 들어가는 일이 생기고, Topic 단위에서는 순서를 보장하지 않기에 순서가 깨질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="offset--오프셋"&gt;&lt;a href="#offset--%ec%98%a4%ed%94%84%ec%85%8b" class="header-anchor"&gt;&lt;/a&gt;Offset / 오프셋
&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;Partition 내부에서 Record를 가리키는 위치&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;별건 아니고 Partition에 데이터가 들어오면 그게 offset 0, 1, 2&amp;hellip; 하고 저장될 뿐이다
이는 위에서 각 consumer / 서비스별로 어디까지 읽었는지를 저장해야하니까.
Consumer은 이를 기준으로 어느 위치부터 읽을지를 결정하며, Consumer Group별로 다음에 읽을 위치를 Committed Offset으로 기록할 수 있다.&lt;/p&gt;
&lt;h5 id="producer--broker--consumer"&gt;&lt;a href="#producer--broker--consumer" class="header-anchor"&gt;&lt;/a&gt;Producer / Broker / Consumer
&lt;/h5&gt;&lt;p&gt;&lt;img
 src="https://blog.wlgh7407.com/images/Drawing%202026-10-22%2016.23.17.excalidraw.png"
 alt="Image Description"loading="lazy"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Producer: 이벤트를 Kafka에 전송하는 프로그램&lt;/li&gt;
&lt;li&gt;Broker: Kafka 서버 / 이벤트 저장과 클라이언트의 읽기, 쓰기 요청 처리&lt;/li&gt;
&lt;li&gt;Consumer: Kafka에 저장된 이벤트를 읽어 처리하는 프로그램&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="03-실습"&gt;&lt;a href="#03-%ec%8b%a4%ec%8a%b5" class="header-anchor"&gt;&lt;/a&gt;03. 실습
&lt;/h3&gt;&lt;h4 id="카프카-키기"&gt;&lt;a href="#%ec%b9%b4%ed%94%84%ec%b9%b4-%ed%82%a4%ea%b8%b0" class="header-anchor"&gt;&lt;/a&gt;카프카 키기
&lt;/h4&gt;&lt;p&gt;도커는 깔려있다고 믿겠다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name de-w01-kafka &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -p 127.0.0.1:9092:9092 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; apache/kafka:4.3.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="topic-생성"&gt;&lt;a href="#topic-%ec%83%9d%ec%84%b1" class="header-anchor"&gt;&lt;/a&gt;Topic 생성
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; de-w01-kafka &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /opt/kafka/bin/kafka-topics.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bootstrap-server localhost:9092 &lt;span class="k"&gt;$(&lt;/span&gt;: 접속할 Kafka Broker 주소&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --create &lt;span class="k"&gt;$(&lt;/span&gt;: 토픽을 만들건데&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --topic trades.raw &lt;span class="k"&gt;$(&lt;/span&gt;: 토픽의 이름은 trades.raw고&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --partitions &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;: Partition은 3개로 할건데&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --replication-factor &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;: 각 Partition의 복제는 1개로 유지하겠다&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;참고로 현재 Broker이 한개라서 replication factor은 1밖에 못한다.&lt;/p&gt;
&lt;h4 id="topic-조회"&gt;&lt;a href="#topic-%ec%a1%b0%ed%9a%8c" class="header-anchor"&gt;&lt;/a&gt;Topic 조회
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; de-w01-kafka /opt/kafka/bin/kafka-topics.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bootstrap-server localhost:9092 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --describe &lt;span class="k"&gt;$(&lt;/span&gt;: Topic의 구성 정보 조회&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --topic trades.raw
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;아마 대충 이런식으로 나올 것이다.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Topic: trades.raw PartitionCount: 3 ReplicationFactor: 1

Partition: 0 Leader: 1 Replicas: 1 Isr: 1
Partition: 1 Leader: 1 Replicas: 1 Isr: 1
Partition: 2 Leader: 1 Replicas: 1 Isr: 1
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;Leader: 해당 Partition의 읽기-쓰기 요청을 주로 담당하는 Broker&lt;/li&gt;
&lt;li&gt;Replicas: 해당 Partition의 복제본이 배치된 Broker 목록&lt;/li&gt;
&lt;li&gt;Isr: 복제본 중 Leader와 충분히 동기화된 것으로 인정되는 집합 (In-Sync Replicas)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="consumer--producer-실행"&gt;&lt;a href="#consumer--producer-%ec%8b%a4%ed%96%89" class="header-anchor"&gt;&lt;/a&gt;Consumer / Producer 실행
&lt;/h4&gt;&lt;p&gt;이제 Broker이 잘 만들어져있으니, Consumer과 Produser을 연결하자.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it de-w01-kafka &lt;span class="k"&gt;$(&lt;/span&gt;: -i : stdin 열어두기 / -t : 가상터미널 할당&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bootstrap-server localhost:9092 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --topic trades.raw &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --from-beginning &lt;span class="k"&gt;$(&lt;/span&gt;: 유효한 committed offset이 없으면 가장 오래된 Record 읽기&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --group w01-cli &lt;span class="k"&gt;$(&lt;/span&gt;: Consumer Group ID 지정&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.partition&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.offset&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;아래 세개는 각각 Record의 Key / Partition 번호 / Offset을 출력하라는 뜻이다.
이렇게 Consumer를 켜두고, 다른 터미널에서 다음을 실행하자.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it de-w01-kafka &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /opt/kafka/bin/kafka-console-producer.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bootstrap-server localhost:9092 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --topic trades.raw &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --property parse.key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;: 입력 문자열에서 key를 분리할건데&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --property key.separator&lt;span class="o"&gt;=&lt;/span&gt;: &lt;span class="k"&gt;$(&lt;/span&gt;: 그 separator는 &lt;span class="s2"&gt;&amp;#34;:&amp;#34;&lt;/span&gt;이다&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;위를 예를 들자면 &lt;code&gt;acct-001:{&amp;quot;event_id&amp;quot;:&amp;quot;e-001&amp;quot;}&lt;/code&gt;는&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Key = acct-001
Value = {&amp;#34;event_id&amp;#34;:&amp;#34;e-001&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;로 해석된다는 뜻이다.&lt;/p&gt;
&lt;p&gt;아무튼 Producer창에 아래 내용을 붙여넣어보자.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;acct-001:{&amp;#34;event_id&amp;#34;:&amp;#34;e-001&amp;#34;,&amp;#34;account_id&amp;#34;:&amp;#34;acct-001&amp;#34;}
acct-002:{&amp;#34;event_id&amp;#34;:&amp;#34;e-002&amp;#34;,&amp;#34;account_id&amp;#34;:&amp;#34;acct-002&amp;#34;}
acct-001:{&amp;#34;event_id&amp;#34;:&amp;#34;e-003&amp;#34;,&amp;#34;account_id&amp;#34;:&amp;#34;acct-001&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Consumer을 보면 데이터가 잘 들어온것을 볼 수 있다.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Partition:0	Offset:0	acct-002	{&amp;#34;event_id&amp;#34;:&amp;#34;e-002&amp;#34;,&amp;#34;account_id&amp;#34;:&amp;#34;acct-002&amp;#34;}
Partition:1	Offset:0	acct-001	{&amp;#34;event_id&amp;#34;:&amp;#34;e-001&amp;#34;,&amp;#34;account_id&amp;#34;:&amp;#34;acct-001&amp;#34;}
Partition:1	Offset:1	acct-001	{&amp;#34;event_id&amp;#34;:&amp;#34;e-003&amp;#34;,&amp;#34;account_id&amp;#34;:&amp;#34;acct-001&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;같은 key는 같은 Partition에 할당된것도 잘 보인다!&lt;/p&gt;
&lt;h4 id="consumer-group과-재실행"&gt;&lt;a href="#consumer-group%ea%b3%bc-%ec%9e%ac%ec%8b%a4%ed%96%89" class="header-anchor"&gt;&lt;/a&gt;Consumer Group과 재실행
&lt;/h4&gt;&lt;p&gt;다음 두 명령어를 실행해보자.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it de-w01-kafka &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bootstrap-server localhost:9092 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --topic trades.raw &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --from-beginning &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --group w01-cli &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --timeout-ms &lt;span class="m"&gt;5000&lt;/span&gt; &lt;span class="c1"&gt;# 5초동안 새 메세지를 못받으면 Consumer 종료&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it de-w01-kafka &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bootstrap-server localhost:9092 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --topic trades.raw &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --from-beginning &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --group w01-replay &lt;span class="k"&gt;$(&lt;/span&gt;: 아까랑 다른 group이다! &lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --timeout-ms &lt;span class="m"&gt;10000&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.partition&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.offset&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;위에서는 아까랑 같은 group이고, 아래에서는 아까랑 다른 group이다
그래서 위 명령어에서는 아까 읽은게 저장되어서 committed offset에 저장되어있을테니, 새로운걸 안읽고
아래 명령어에서는 committed offset이 없으니 아까 데이터를 다시 받는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;그리고 이걸 볼 때, committed offset은 &lt;strong&gt;Broker이 저장한다는 것&lt;/strong&gt;을 알아낼 수 있다.&lt;/p&gt;
&lt;h4 id="broker-재시작"&gt;&lt;a href="#broker-%ec%9e%ac%ec%8b%9c%ec%9e%91" class="header-anchor"&gt;&lt;/a&gt;Broker 재시작
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker stop de-w01-kafka
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker start de-w01-kafka
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it de-w01-kafka &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bootstrap-server localhost:9092 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --topic trades.raw &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --from-beginning &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --group w01-after-restart &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --timeout-ms &lt;span class="m"&gt;10000&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.partition&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --formatter-property print.offset&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Kafka는 기본적으로 Record를 &lt;strong&gt;디스크의 로그&lt;/strong&gt;에 저장하기때문에, 프로세스를 정상 종료해도 보존기간 내의 데이터는 유지됨을 알 수 있다.&lt;/p&gt;
&lt;h3 id="04-정리"&gt;&lt;a href="#04-%ec%a0%95%eb%a6%ac" class="header-anchor"&gt;&lt;/a&gt;04. 정리
&lt;/h3&gt;&lt;p&gt;간단하게 Kafka의 탄생 배경을 알아보고 가벼운 실습까지 진행했다. 뒷 글에서 조금 더 괴롭혀보자.&lt;/p&gt;</description></item></channel></rss>