카프카 파티션/컨슈머그룹/오프셋, 스몰 파일 터지고 나서야 이해했어요
처음 카프카를 공부할 때 파티션, 컨슈머 그룹, 오프셋이라는 개념을 봤을 때 솔직히 이런 생각이 들었어요.
“아, 그냥 메시지 큐 아닌가? 데이터 넣고 빼면 되는 거 아니야?”
근데 막상 파이썬으로 컨슈머 코드를 짜고, 실제로 데이터를 흘려봤더니 스몰 파일 문제가 터지더라고요. 파티션 하나에 소비자를 하나만 붙여놨는데, 파일이 수천 개 쪼개져서 저장되는 거예요. 그때서야 “아, 이게 그냥 큐가 아니구나”라는 걸 몸으로 배웠어요.
오늘은 그 경험을 바탕으로 카프카의 핵심 구조인 파티션, 컨슈머 그룹, 오프셋을 왜 이렇게 설계했는지 같이 이해해 봐요.
카프카가 뭔지 30초만 짚고 갈게요
카프카는 한마디로 “대용량 데이터를 실시간으로 안전하게 전달해주는 파이프” 예요.
생산자(Producer)가 데이터를 보내면, 카프카가 중간에서 받아서 보관하고, 소비자(Consumer)가 꺼내가는 구조예요. 이메일로 비유하면 카프카는 메일 서버고, 생산자는 메일 보내는 사람, 소비자는 메일 읽는 사람이라고 보면 돼요.
근데 이 “보관”하는 방식이 핵심이에요. 바로 여기서 파티션이 등장해요.
파티션: 데이터를 나눠 담는 서랍장
파티션은 쉽게 말해 토픽(Topic)을 쪼개 담는 서랍 이에요.
카프카에서 토픽은 데이터를 분류하는 단위예요. 예를 들어 “주문 데이터”라는 토픽이 있다면, 그 안에 파티션이 여러 개 있는 거예요. 파티션 0번 서랍, 1번 서랍, 2번 서랍 이런 식으로요.
데이터는 파티션 안에 순서대로 쌓여요. 이걸 로그(Log) 구조라고 해요. 한번 들어간 데이터는 수정되지 않고, 뒤에 계속 추가되기만 해요. 이 구조 덕분에 쓰기 속도가 엄청 빠른 거예요.
파티션이 여러 개 있으면 뭐가 좋냐고요? 바로 병렬 처리가 가능해져요. 서랍이 3개 있으면 3명이 동시에 꺼낼 수 있잖아요. 파티션 수 = 동시에 처리할 수 있는 최대 소비자 수라고 이해하면 딱 맞아요.
한 줄 정리: 파티션은 데이터를 병렬로 처리하기 위해 토픽을 물리적으로 쪼갠 단위예요.
오프셋: 내가 어디까지 읽었는지 기억하는 북마크
오프셋(Offset)은 각 파티션 안에서 데이터의 위치 번호 예요.
파티션에 데이터가 들어올 때마다 0, 1, 2, 3… 이렇게 번호가 붙어요. 소비자는 이 번호를 보고 “나는 5번까지 읽었어”라는 걸 기억해요. 다음에 다시 연결되면 6번부터 이어서 읽는 거예요.
이게 왜 중요하냐면, 카프카는 메시지를 꺼내도 지우지 않거든요. 일반적인 큐는 꺼내면 사라지는데, 카프카는 설정한 보존 기간 동안 그대로 남아요. 그래서 오프셋만 조정하면 과거 데이터를 다시 읽을 수도 있어요.
오프셋 커밋(Commit)이라는 개념도 중요해요. 소비자가 데이터를 읽은 후 “나 여기까지 읽었어”라고 카프카에 보고하는 게 오프셋 커밋이에요. 이걸 안 하면 서버가 재시작됐을 때 처음부터 다시 읽는 문제가 생겨요.
한 줄 정리: 오프셋은 소비자가 어디까지 읽었는지 추적하는 북마크이고, 커밋을 통해 위치를 저장해요.
컨슈머 그룹: 팀으로 나눠 읽는 구조
컨슈머 그룹(Consumer Group)은 같은 토픽을 함께 소비하는 소비자들의 팀 이에요.
핵심 규칙이 하나 있어요. 하나의 파티션은 같은 그룹 안에서 딱 한 명만 읽을 수 있어요. 이게 카프카 파티션 할당 메커니즘의 핵심이에요.
예를 들어볼게요. 파티션이 3개 있고, 컨슈머가 3개라면 각자 파티션 하나씩 맡아요. 근데 컨슈머가 2개라면 한 명이 파티션 2개를 맡아요. 반대로 컨슈머가 4개라면 파티션이 3개뿐이라 한 명은 놀게 돼요. 그래서 컨슈머 수를 파티션 수보다 많이 늘려도 의미가 없어요.
그룹이 다르면 얘기가 달라요. 그룹 A와 그룹 B가 같은 토픽을 읽는다면, 두 그룹 모두 처음부터 독립적으로 읽어요. 오프셋도 그룹마다 따로 관리되거든요. 같은 데이터를 분석팀은 분석 목적으로, 알람팀은 알람 목적으로 동시에 쓸 수 있는 이유가 여기 있어요.
한 줄 정리: 컨슈머 그룹은 파티션을 나눠 읽는 팀이고, 같은 팀 안에서 하나의 파티션은 한 명만 담당해요.
스몰 파일 문제로 배운 파티션 설계의 중요성
이제 제가 겪은 삽질 얘기를 해볼게요.
파이썬으로 카프카 컨슈머를 짜면서 처음엔 대충 이렇게 했어요. 파티션 1개짜리 토픽 만들고, 컨슈머 하나 붙여서 데이터 받는 족족 파일로 저장했어요. 처음엔 잘 됐어요. 근데 데이터 양이 늘어나면서 파일이 수천 개, 수만 개로 쪼개지기 시작했어요. 이게 스몰 파일 문제예요.
왜 이런 일이 생겼냐면, 컨슈머가 메시지를 받을 때마다 파일을 하나씩 열고 닫았거든요. 파티션이 하나라 병렬 처리도 안 되고, 버퍼링도 없다 보니 작은 파일이 미친 듯이 쌓인 거예요.
이걸 해결하면서 파티션 구조를 다시 공부했어요. 파티션을 늘리고, 컨슈머 그룹을 제대로 설정하고, 오프셋 커밋 타이밍을 조절하는 방식으로 바꿨더니 파일 크기가 일정하게 유지되기 시작했어요.
그때 깨달은 건데, 카프카의 파티션/컨슈머 그룹/오프셋 구조는 그냥 기능이 아니라 처리량과 안정성을 동시에 잡기 위한 설계 철학 이더라고요. 개념을 외우는 게 아니라 왜 이렇게 만들었는지를 이해해야 실제로 쓸 수 있어요.
한 줄 정리: 파티션 설계를 잘못하면 스몰 파일 같은 실제 운영 문제로 이어져요.
리밸런싱: 소비자가 바뀌면 파티션을 다시 나눠요
마지막으로 리밸런싱(Rebalancing)도 짚고 갈게요. 이것도 파티션 할당 메커니즘의 중요한 부분이에요.
컨슈머 그룹에서 소비자가 하나 추가되거나 빠지면, 카프카가 파티션 배분을 다시 해요. 이게 리밸런싱이에요. 예를 들어 컨슈머 3개가 파티션 3개를 각각 맡고 있었는데, 한 명이 갑자기 죽으면 카프카가 남은 2명한테 파티션을 다시 나눠줘요.
리밸런싱 중에는 잠깐 데이터 처리가 멈춰요. 이걸 Stop-the-world라고 해요. 그래서 카프카 버전이 올라가면서 리밸런싱을 최소화하는 방향으로 계속 개선되고 있어요. 최근엔 Incremental Cooperative Rebalancing이라는 방식으로 처리 중단 없이 리밸런싱하는 것도 가능해요.
한 줄 정리: 리밸런싱은 소비자 변화에 따라 파티션을 재배분하는 과정이고, 잠깐의 처리 중단이 발생할 수 있어요.
정리: 세 개념이 하나로 맞물려요
카프카의 파티션, 컨슈머 그룹, 오프셋은 따로 외우면 헷갈려요. 근데 이렇게 이해하면 한 번에 정리돼요.
- 파티션: 데이터를 병렬 처리하기 위해 쪼갠 단위
- 컨슈머 그룹: 파티션을 나눠 읽는 팀, 같은 팀 안에서 파티션 하나는 한 명만
- 오프셋: 각 소비자(팀)가 어디까지 읽었는지 기록하는 위치 정보
저처럼 직접 코드 짜고 문제 터진 다음에 이해하는 것도 방법이긴 한데, 미리 이 구조를 알고 들어가면 설계할 때 훨씬 수월해요.
이 글과 함께 보면 좋아요
Kafka와 Firehose: 실시간 데이터 파이프라인은 왜 이렇게 설계됐나 →
파티션 구조를 이해했으면, Firehose를 컨슈머로 붙였을 때 스몰 파일 문제가 어떻게 해결되는지 바로 이어서 읽어보세요.