SW/클라우드 서비스 아키텍처

Kafka란? LinkedIn·Netflix·Uber가 선택한 이유와 핵심 개념 완벽 정리

얇은생각 2025. 12. 22. 07:30
반응형

왜 LinkedIn, Netflix, Uber는 Kafka로 하루 수십억 개의 메시지를 버틸까?

우리가 쓰는 서비스는 겉으로 볼 때 참 매끄럽습니다. 버튼을 한 번 누르면 바로 영상이 재생되고, 택시가 잡히고, 결제가 끝나죠. 하지만 그 뒤에서는 엄청난 양의 event가 쉴 새 없이 쏟아지고 있습니다.

유저 클릭, 결제 내역, driver 위치, video stream 상태, log, alert… 이 모든 것들이 초 단위도 아니고 밀리초 단위로 쏟아집니다.

이 미친 트래픽을 LinkedIn, Netflix, Uber 같은 회사들은 어떻게 감당할까요? 많은 곳이 선택한 답이 바로 Kafka입니다.

Kafka를 쓰는 이유는 단순히 "scale 잘 된다"가 아닙니다. Kafka의 distributed log 구조가 주는 독특한 장점 때문입니다.

  • 과거 event를 replay 할 수 있고,
  • 서로 다른 service를 느슨하게 이어주는 decoupling이 가능하고,
  • 갑작스러운 traffic spike를 흡수해서 backend를 보호할 수 있습니다.

이 글에서는 Kafka가 이런 걸 어떻게 해내는지, 그리고 Kafka를 도입할 때 우리가 어떤 trade-off를 받아들여야 하는지 깊게 살펴보겠습니다.

 

Kafka가 사랑받는 핵심 이유: Decoupling

 


Kafka가 사랑받는 핵심 이유: Decoupling

많은 회사가 Kafka를 도입하는 가장 큰 이유는 사실 단순합니다. 바로 system decoupling입니다.

전통적인 구조를 생각해보면, service끼리 직접 호출합니다.

  • payment service가 notification service에 직접 요청을 보내고,
  • order service가 inventory service를 직접 두드리고,
  • 하나가 느려지거나 죽으면 연쇄적으로 문제가 터집니다.

 

Kafka를 넣으면 그림이 완전히 달라집니다.

  • 각 service는 producer가 되어 Kafka topic에 메시지를 쓰고,
  • 다른 service는 consumer로서 그 topic을 읽기만 합니다.

 

서로를 직접 알 필요가 없습니다. 누구랑 통신하는지 몰라도, Kafka만 알고 있으면 됩니다. 이게 바로 decoupling입니다.

이 구조가 주는 이점은 생각보다 큽니다.

  1. 서비스를 독립적으로 진화시킬 수 있음
    어떤 service를 Go에서 Rust로 갈아엎든, monolith를 microservice로 쪼개든, 다른 service는 Kafka topic만 유지되면 영향이 거의 없습니다.
  2. Traffic spike를 Kafka가 대신 맞아줌
    특정 이벤트로 인해 갑자기 트래픽이 폭증해도, producer는 일단 Kafka에 메시지를 쌓습니다. consumer는 자기 처리 속도에 맞춰 차분히 읽어가면 됩니다.
  3. Replay와 복구가 가능함
    Kafka는 그냥 큐가 아니라 log입니다. retention 기간 동안은 예전 메시지도 그대로 남아 있기 때문에, 필요하면 일정 시점부터 다시 읽으면서 시스템을 복구하거나, bug를 분석할 수 있습니다.

대신 이제 Kafka 자체가 핵심 인프라가 됩니다. 운영과 관리가 필수고, 잘못 운영하면 전체 system이 동시에 흔들릴 수 있습니다.

 

 


Distributed log로서 Kafka는 어떻게 동작할까?

Kafka의 기본 아이디어는 놀라울 정도로 단순합니다.

여러 서버에 분산된 append-only log

producer가 Kafka로 메시지를 보내면, 그 메시지는 특정 partition에 기록됩니다. 이 partition은 말 그대로 끝에만 계속 append 되는 log 파일이라고 보면 됩니다. 중간 수정은 없습니다.

partition들은 broker라고 부르는 server 위에 올라갑니다. 여러 broker가 모이면 하나의 Kafka cluster가 됩니다.

Kafka는 데이터를 topic이라는 단위로 묶습니다.

  • payments topic에는 결제 이벤트가,
  • user-clicks topic에는 유저 클릭 로그가,
  • video-uploads topic에는 영상 업로드 이벤트가 쌓입니다.

 

producer는 이 topic에 메시지를 쓰고, consumer는 관심 있는 topic을 구독해서 읽습니다.

각 메시지는 보통 다음 정보를 가집니다.

  • key
  • value (실제 payload)
  • timestamp
  • 필요하다면 header로 metadata 추가

 

이 중에서 특히 중요한 것이 key입니다. key가 바로 이 메시지가 어떤 partition으로 갈지 결정합니다.

  • 같은 key로 보낸 메시지는 항상 동일한 partition에 저장됩니다.
  • 그래서 해당 key 기준으로는 순서가 보장됩니다.

 

반대로 key를 지정하지 않으면, Kafka가 알아서 round-robin 비슷한 방식으로 partition에 골고루 분산시켜 load balancing을 해줍니다.

요즘 스펙 괜찮은 hardware라면, broker 하나가 초당 수십만 메시지를 처리하는 것도 충분히 가능합니다.
실제로는 CPU나 disk보다 network bandwidth가 먼저 한계에 부딪히는 경우가 많습니다.

 

 


잠깐, 개발자 생산성도 중요하다: Warp와 AI agent

Kafka 이야기를 계속하기 전에, 실제로 이런 분산 시스템을 다루는 개발자 입장도 한 번 짚고 넘어가 보겠습니다.

요즘은 terminal에 AI agent를 붙여서 code 작성과 debugging을 돕는 workflow가 많이 쓰입니다. 원본 script에서는 Warp라는 modern terminal이 언급됩니다.

많은 AI agent가 코드를 거의 맞게 만들어 주지만, 막상 돌려보면 자잘한 bug를 잡느라 시간을 다 쓰는 경험, 한 번쯤 해보셨을 겁니다.

Warp의 AI agent는 이런 문제를 줄이려고, 개발자가 지금 어떤 context에서 무엇을 하고 있는지 더 잘 이해하려고 합니다. 그리고 한 곳에서:

  • prompt를 던지고,
  • 나온 코드를 review하고,
  • 다시 refine하는 과정을

 

계속 terminal 안에서 진행할 수 있게 해줍니다. 굳이 editor, browser, terminal을 왔다 갔다 할 필요가 줄어듭니다.

Warp는 여러 benchmark에서 상위권 성능을 보여준다고 광고하고, 실제 사용자들이 하루 평균 한 시간 이상을 절약한다고 주장합니다.

물론 이런 tool이 Kafka의 architecture를 바꾸지는 않습니다. 다만, 복잡한 distributed system과 Kafka cluster를 운영하고 debug할 때, 이런 도구들이 실수를 줄이고 속도를 높여준다는 점은 꽤 의미가 있습니다.

 

 


Topic, Partition, Key: Kafka 설계의 심장

Kafka 기반 system을 성공적으로 운영하고 싶다면, 반드시 이해해야 할 것이 있습니다. 바로 partitioning strategy입니다.

어떤 기준으로 partition을 나누느냐에 따라, system이 우아하게 scale 할 수도 있고, 또는 traffic 앞에서 허무하게 무너질 수도 있습니다.

나쁜 partition key를 고르면, 특정 partition 하나만 과도한 traffic을 받게 되는 hot partition 문제가 생깁니다. 그러면 그 partition이 올라가 있는 broker만 터지고, 나머지 broker는 한가해지는 기괴한 상황이 벌어집니다.

 

Streaming 서비스 예시: Hot partition이 터지는 순간

예를 들어 우리가 영화 streaming 서비스를 만든다고 해 봅시다. 설계를 단순하게 하려고, video-stream-events topic의 partition key를 movieId로 정했습니다.

초반에는 꽤 괜찮아 보입니다.

  • 영화마다 traffic도 다르고
  • 여러 movieId가 여러 partition에 적당히 나뉘니
  • 모니터링 그래프도 평온해 보입니다.

 

그런데 금요일 밤, 대형 블록버스터가 공개되는 순간 상황이 달라집니다.

수백만 유저가 같은 영화를 동시에 보기 시작합니다.

movieId 기준 partitioning을 했기 때문에, 그 영화와 관련된 event가 한 partition에 몰리기 시작합니다.

  • 해당 partition이 있는 broker만 CPU, disk I/O, network가 폭증하고
  • 해당 partition을 읽는 consumer는 backlog에 깔리며
  • 실시간 analytics나 recommendation pipeline이 밀리기 시작합니다.

 

이게 바로 대표적인 hot partition 시나리오입니다.

 

Compound key로 균형 잡기

이 문제를 푸는 전형적인 방식이 compound key입니다.

movieId만 key로 쓰는 대신, 여기에 userId 기반 hash를 섞습니다. 예를 들면:

key = movieId + ":" + hash(userId)

 

이렇게 하면:

  • 동일한 movie에 대한 event도 여러 partition에 분산되고,
  • 같은 user의 session event들은 여전히 같은 key를 사용하기 때문에 user 단위 ordering은 유지됩니다.

 

결과적으로,

  • 대형 영화가 터져도 여러 partition으로 traffic이 나뉘고,
  • broker 간 load도 더 고르게 퍼지고,
  • 전체 system이 peak traffic을 훨씬 안정적으로 처리할 수 있습니다.

 

Time-based partitioning과 그 한계

또 다른 방식으로는 time-based partitioning이 있습니다. 예를 들어 1시간 단위, 1일 단위로 partition을 쪼개는 패턴입니다.

이 방식은 특히 log data에 잘 맞습니다.

  • retention 기간이 끝난 오래된 partition만 통째로 drop하면 되니,
  • retention policy 관리가 매우 단순해집니다.

 

하지만 real-time aggregation이 필요할 때에는 이야기가 복잡해집니다.

  • 여러 시간 구간을 한꺼번에 분석해야 하면,
  • 여러 partition을 동시에 읽고 조합해야 하는 상황이 많아집니다.

 

partitioning strategy를 정할 때는 항상 다음 질문을 던져야 합니다.

  • 어떤 기준으로 순서(ordering) 가 중요할까?
  • traffic이 몰릴 때 어디에 집중적으로 쏠릴까?
  • 데이터 보관(retention)삭제를 어떻게 할 계획인가?

 

 


Consumer는 어떻게 진행 상황을 기억할까? Offset과 Commit

Kafka에서 consumer는 "내가 어디까지 읽었지?"를 기억해야 합니다.

이를 위해 Kafka는 각 partition 안의 메시지마다 offset이라는 번호를 붙입니다. 마치 log 파일의 줄 번호 같은 개념입니다.

consumer는 partition에서 메시지를 읽어 처리하고, 마지막으로 처리한 메시지의 offset을 기억했다가, 일정 주기마다 이 offset을 다시 Kafka에 저장합니다. 보통 내부용 topic에 이 정보가 남습니다.

 

이 구조 덕분에,

  • consumer가 crash 나도,
  • 재시작 후 Kafka에서 마지막으로 commit된 offset을 읽고,
  • 그 다음 offset부터 다시 메시지를 처리할 수 있습니다.

 

하지만 여기에도 중요한 고민거리가 하나 있습니다. 바로 언제 offset을 commit 할 것인가입니다.

 

너무 빨리 commit 하면 생기는 문제

다음과 같은 흐름을 생각해 봅시다.

  1. consumer가 메시지 batch를 받는다.
  2. 아직 business logic 처리가 끝나기 전에, offset을 먼저 commit 한다.
  3. 그 직후에 consumer가 crash 난다.

 

재시작 후에는 Kafka 기준으로는 해당 offset까지 이미 처리된 걸로 보이기 때문에, 그 구간 메시지는 다시 읽히지 않습니다.

즉, 실제로는 처리되지 않았는데, 시스템은 처리된 줄 알고 데이터 손실이 발생합니다. 이게 at-most-once 상황입니다.

 

 

너무 늦게 commit 하면 생기는 문제

이번에는 반대 상황입니다.

  1. consumer가 메시지를 받고, business logic까지 모두 잘 처리했다.
  2. 그런데 아직 offset commit을 안 한 상태에서 crash가 난다.

재시작 후에는 이전에 처리했던 메시지를 다시 읽어서 한 번 더 처리하게 됩니다. 데이터는 잃지 않지만, 중복 처리가 일어나죠.

이게 바로 at-least-once 상황입니다.

이 두 extreme 사이에서, 우리가 어떤 delivery semantics를 선택할지 정해야 합니다.

 

 


Consumer group으로 scale-out 하기

Kafka에서 consumer group은 message processing을 확장하는 핵심 개념입니다.

하나의 consumer group은 여러 개의 consumer instance로 이루어지고, Kafka는 topic의 각 partition을 group 안의 딱 한 consumer에게만 할당합니다.

즉, 같은 group 안에서는 각 메시지가 정확히 한 번만 처리되도록 보장하려고 합니다. (물론 crash와 commit 타이밍에 따라 중복은 여전히 날 수 있습니다.)

consumer를 더 추가하면 어떻게 될까요?

  • Kafka가 rebalance를 수행하면서 partition을 새 consumer에게 재배치합니다.
  • 어떤 consumer가 죽으면, 그 consumer가 담당하던 partition이 다른 consumer에게 자동으로 넘어갑니다.

 

이 덕분에 우리는:

  • consumer instance 수를 늘리면서 자연스럽게 처리량을 scale-out 할 수 있고,
  • 상당수의 장애 상황을 별도 수작업 없이 흡수할 수 있습니다.

이렇게 partition assignment를 재조정하는 과정이 바로 rebalance입니다. 내부적으로는 꽤 복잡하지만, 사용자 입장에서는 "consumer 늘리고 줄이면 Kafka가 알아서 분배해준다" 정도로 이해해도 큰 무리는 없습니다.

 

 


Delivery guarantee: At-most-once, At-least-once, Exactly-once

Kafka는 세 가지 대표적인 delivery guarantee 모델을 지원합니다.

  1. at-most-once
  2. at-least-once
  3. exactly-once

각각은 성능, 복잡도, 데이터 정확성 측면에서 서로 다른 trade-off를 가집니다.

 

1) At-most-once

at-most-once는 말 그대로, 메시지가 0번 혹은 1번 처리되지만, 절대 두 번 이상은 처리되지 않는 모델입니다.

보통은 offset을 비교적 빨리 commit하는 방식으로 구현합니다.

  • 처리 전에 commit을 해버리면,
  • crash 시 메시지를 다시 읽지 않으므로,
  • 손실은 생길 수 있지만 중복은 없습니다.

장점은 간단하고 빠르다는 것. 반면, 약간의 데이터 손실을 허용해야 합니다.

 

2) At-least-once

at-least-once는 각 메시지가 최소 한 번은 처리되도록 하는 모델입니다. 그 대신, 두 번 이상 처리될 가능성은 존재합니다.

  • 메시지를 처리한 뒤에 offset을 commit하는 식으로 설계하면,
  • crash 시 다시 읽어서 중복 처리가 발생할 수 있습니다.

그래서 이 모델에서는 consumer 쪽 로직을 idempotent하게 만드는 것이 사실상 필수입니다.

  • 같은 메시지가 두 번 들어와도 결과가 달라지지 않도록 설계해야 합니다.

대부분의 production system은 at-least-once + idempotent consumer 조합을 기본값으로 선택합니다. trade-off 대비 효율이 좋기 때문입니다.

 

3) Exactly-once

exactly-once는 말 그대로, 각 메시지를 정확히 한 번만 처리하는 것을 목표로 합니다. crash든 retry든 어떤 상황에서도 중복도, 손실도 없이 한 번.

Kafka는 idempotent producertransaction 기능을 통해 exactly-once processing을 지원할 수 있습니다. 하지만 이건 설정도 복잡하고, 운영도 험난합니다.

  • producer와 consumer 모두에서 option을 잘 맞춰야 하고,
  • transaction을 걸고 commit/abort 흐름을 제대로 관리해야 합니다.

 

대신, 금융 거래 같은 critical pipeline에서는 이 복잡성이 충분히 가치가 있을 수 있습니다.

system 설계 시에는 이 세 가지 중 하나를 명시적으로 선택해야 합니다. "기본값 따라가면 되겠지"보다는, "우리 비즈니스는 어느 정도의 손실/중복을 감당할 수 있는가"를 먼저 질문하는 것이 좋습니다.

 

 


Durability와 고가용성: Replication, Leader, Follower

Kafka의 durability고가용성replication에서 나옵니다.

각 partition은 하나의 leader replica와 여러 개의 follower replica로 구성됩니다.

  • leader는 읽기/쓰기 요청을 모두 처리하고,
  • follower는 leader의 log를 계속 따라가며 데이터를 복제합니다.

 

leader에 문제가 생기면, Kafka는 in-sync replica(ISR) 중 하나를 새 leader로 승격시킵니다.

많은 production 환경에서는 replication factor를 3으로 설정합니다.

  • 각 partition이 세 개의 replica를 가지게 되고,
  • broker 하나를 잃어도 여전히 최소 두 개의 copy가 남습니다.

 

또한 producer 입장에서 "몇 개의 replica가 ack을 보내야 write를 성공으로 볼 것인가"도 설정할 수 있습니다.

  • 모든 in-sync replica의 ack를 기다리면 안전성은 극대화되지만,
  • 그만큼 latencythroughput에서 손해를 봅니다.

 

일반적으로 replication factor 3에 적절한 ack 설정을 하면, broker 하나 정도의 장애는 크게 데이터 손실 없이 버틸 수 있습니다.

이 구조 덕분에 많은 회사들이 Kafka를 핵심 데이터 파이프라인의 중추로 신뢰하고 사용합니다.

 

 


실제 사례들: Uber, Event sourcing, 그리고 Kafka의 활용 패턴

Kafka의 구조는 꽤 다양한 패턴을 가능하게 만듭니다.

Uber: 실시간 Surge Pricing

예를 들어 Uber를 떠올려 봅시다.

전 세계 수많은 driver의 위치 update가 실시간으로 쏟아집니다. 이런 event들은 Kafka를 통해 흘러가면서:

  • 특정 지역의 demand/supply를 계산하고,
  • surge pricing을 적용하고,
  • rider와 driver를 매칭하고,
  • ETA를 추정하는 system으로 전달됩니다.

 

이때 일반적인 전략은 지리적 기준 partitioning입니다.

  • region이나 city를 기준으로 topic이나 partition을 나누고,
  • 각 지역이 서로 독립적으로 scale 할 수 있도록 설계합니다.

 

이렇게 하면 한 도시에서 traffic이 폭발해도, 다른 도시의 pipeline까지 같이 끌려가지 않습니다.

 

 

Kafka를 source of truth로 쓰는 Event sourcing

일부 회사는 아예 Kafka를 source of truth로 사용하는 방식을 선택하기도 합니다.

전통적으로는 database row를 직접 update하면서 상태를 관리합니다. 하지만 event sourcing 패턴에서는 이렇게 하지 않습니다.

  • 상태 변화 하나하나를 모두 event로 만들어
  • Kafka topic에 append 합니다.

 

어떤 entity의 현재 상태가 궁금하면,

  • 해당 entity 관련 event들을 순서대로 replay 해서
  • 최종 state를 fold 해내는 방식입니다.

 

이 방식의 장점은 분명합니다.

  • 모든 변경이 event로 남기 때문에 완전한 audit trail을 얻을 수 있고,
  • 특정 시점의 상태를 다시 복원할 수도 있고,
  • 같은 event stream을 analytics, search, cache 등 여러 system이 재사용할 수 있습니다.

 

물론 event sourcing은 만능이 아닙니다.

  • schema evolution,
  • 대량 replay 성능,
  • state rebuild 전략

 

같은 부분에서 꽤 깊은 고민이 필요합니다.

 

 


언제 Kafka가 좋은 선택이 아닐까?

Kafka는 강력하지만, 모든 문제에 대한 정답은 아닙니다.

Kafka는 기본적으로 throughput 최적화에 초점을 둔 system입니다. 덕분에 대량의 data를 굉장히 효율적으로 다루지만, 대신 latency 면에서는 극단적으로 빠른 편은 아닙니다.

producer와 broker, consumer 모두가 batchingbuffering을 활용합니다.

  • 메시지를 모아서 한 번에 보내고,
  • log에 순차적으로 쓰고,
  • consumer도 한 덩어리씩 읽습니다.

 

이 과정에서 약간의 지연이 생기는데, 대부분의 streaming이나 analytics pipeline에서는 이 정도 delay는 전혀 문제 되지 않습니다.

하지만 아주 짧은 request-response 패턴, 예를 들어 몇 ms 안에 반응해야 하는 API 호출 경로에 Kafka를 그대로 끼워 넣는 건 대체로 적절하지 않습니다.

 

 

Ordering의 한계

Kafka는 partition 단위로만 ordering을 보장합니다.

전체 topic에 대해 글로벌 ordering이 꼭 필요하다면, 결국 partition을 하나만 쓰는 구조가 됩니다.

이 경우,

  • parallelism은 거의 사라지고,
  • partition 하나가 전체 throughput의 병목이 됩니다.

 

그래서 대부분의 실제 system은 partial ordering을 받아들입니다.

  • userId, accountId, sessionId처럼 중요한 key를 하나 정하고,
  • 그 key 기준으로만 ordering을 신경 쓰는 식입니다.

 

Exactly-once의 복잡함

앞서 말했듯이 exactly-once processing은 존재하지만, 상당한 복잡성과 성능 비용을 요구합니다.

많은 팀이 현실적인 선택으로 at-least-once + idempotent consumer 조합을 택합니다. 복잡한 transaction 대신 중복을 안전하게 처리하는 방향이 운영 측면에서 더 나은 경우가 많기 때문입니다.

 

 

운영 비용

Kafka를 도입하면, 그 순간부터 Kafka는 여러분 stack의 핵심 인프라가 됩니다.

  • cluster provisioning과 scaling,
  • monitoring과 alerting,
  • schema evolution과 backward/forward compatibility,
  • security, ACL, encryption,

 

이 모든 걸 책임지고 운영해야 합니다.

규모가 작거나, 요구사항이 단순한 system이라면, 이런 overhead 때문에 오히려 Kafka가 과한 선택이 될 수도 있습니다. 그럴 땐 더 단순한 message queue나 fully managed service가 나은 답일 수도 있습니다.

 

 


Kafka가 진짜로 잘하는 것: Decoupling과 완충 역할

정리해보면 Kafka의 핵심 가치는 크게 세 가지로 요약할 수 있습니다.

  • producer와 consumer를 decouple 해서, service들이 서로 얽히지 않고 진화할 수 있게 해주고,
  • 갑작스러운 traffic spike를 log가 대신 빨아들여 system을 보호하고,
  • 문제가 생겼을 때 event replay를 통해, 과거에 무슨 일이 있었는지 그대로 재현해 볼 수 있게 해줍니다.

 

그 대신 Kafka는 우리에게 몇 가지 책임을 요구합니다.

  • 잘 설계된 partitioning strategy가 필요하고,
  • 어떤 delivery semantics를 쓸 것인지 명확한 선택이 필요하며,
  • replication, monitoring, 운영 전략에 대한 성숙한 이해가 있어야 합니다.

 

Kafka를 그냥 "마법 같은 black box"로 대하면, 언젠가는 크게 발목을 잡힐 수 있습니다. 반대로 내부 모델을 제대로 이해하면, Kafka는 매우 믿을 만한 기반이 됩니다.

 

 


Kafka 설계를 위한 실전 가이드

마지막으로, Kafka 기반 architecture를 설계할 때 도움이 되는 실용적인 팁들을 정리해보겠습니다.

 

1) Event 경계를 business 관점에서 정의하기

event는 되도록 비즈니스 사실을 표현하게 만드는 것이 좋습니다.

  • UserRegistered
  • PaymentCompleted

 

같은 이름은,

  • InsertUserRow
  • UpdatePaymentStatus

 

같은 database 중심 event보다 훨씬 이해하기 쉽고 유지보수도 좋습니다.

 

 

2) Partition key를 consumer의 사용 패턴에 맞추기

이 데이터를 나중에 누가, 어떤 방식으로 읽게 될지를 먼저 떠올려 보세요.

  • 대부분 user 단위로 처리한다면 userId를 key로 쓰는 게 자연스럽고,
  • 지역별 분석이 중요하다면 region 정보를 key에 포함하는 것이 좋습니다.

 

특정 productId, movieId처럼 극단적으로 쏠릴 수 있는 key는 hot partition을 만들기 쉽습니다. 이럴 땐 compound key나 hash를 섞어서 분산시키는 전략을 고민해야 합니다.

 

3) 먼저 At-least-once + Idempotent consumer를 기본 전제로 삼기

정말로 exactly-once가 필요한 상황이 아니라면,

  • at-least-once를 기본값으로 하고,
  • consumer logic을 idempotent하게 만드는 전략이 현실적인 선택입니다.

 

예를 들어,

  • operation에 고유한 ID를 붙여놓고,
  • 이미 처리한 ID인지 먼저 확인한 뒤, 중복이면 그냥 무시하는 방식 등

 

으로 설계할 수 있습니다.

 

4) Replication 설정은 중요도에 따라 다르게

replication factor 3은 많이 쓰이는 기본값입니다.

하지만 모든 topic이 똑같은 수준의 내구성을 요구하는 건 아닙니다.

  • 핵심 결제/정산 pipeline은 강한 replication과 엄격한 ack 설정이 필요할 수 있고,
  • 덜 중요한 log성 데이터는 조금 더 느슨하게 가져갈 수도 있습니다.

 

5) Monitoring과 장애 시나리오 테스트는 필수

Kafka cluster와 consumer, producer에 대한 metric과 logging을 충실하게 구성해야 합니다.

그리고 실제로 다음 같은 상황들을 테스트해 보는 게 좋습니다.

  • broker가 한 대 죽었을 때,
  • consumer가 crash 났을 때,
  • network partition 비슷한 상황이 생겼을 때,

 

시스템이 어떻게 반응하는지, 우리가 기대한 대로 failover가 이뤄지는지 꼭 확인해 봐야 합니다.

 

 


마무리: Kafka는 현대 서비스의 조용한 중추

Kafka는 이제 전 세계 많은 서비스의 기본 인프라가 되었습니다.

LinkedIn, Netflix, Uber 같은 회사들이 Kafka를 선택한 이유는 단순히 "빨라서"가 아닙니다.

  • distributed log 구조로 event를 쌓아두고,
  • producer와 consumer를 느슨하게 decoupling해주며,
  • 거대한 traffic spike도 log에 흡수해 system을 지켜주기 때문입니다.

 

물론 그 대가로,

  • 복잡한 운영과 설계,
  • 까다로운 tuning,
  • 그리고 여러 가지 architecture 상의 선택들이 따라옵니다.

 

하지만 Kafka의 개념—topic, partition, key, offset, consumer group, delivery semantics, replication, event sourcing—을 제대로 이해하고 나면, 훨씬 더 탄탄하고 확장 가능한 system을 설계할 수 있습니다.

다음번에 새로운 feature를 공개하고, 특정 video가 바이럴을 타고, 특정 도시에서 ride 요청이 폭발적으로 늘어날 때,

잘 설계된 Kafka 기반 architecture는 그 모든 event를 묵묵히 받아내면서, 서비스가 무너지는 대신 부드럽게 버티게 만들어 줄 것입니다.

Kafka는 마법이 아니라, 잘 만들어진 tool입니다. 그리고 그 tool을 제대로 이해하고 쓰는 순간, 여러분의 system 전체는 한 단계 더 안정적이고, 유연하고, 미래지향적인 기반 위에 서게 됩니다.

반응형