반응형

stream-processing 9

11편. Kafka를 도입했는데 장애가 더 늘어난 이유

Kafka 시리즈의 마지막이다. 지금까지 우리는 Kafka의 설계 의도부터 Consumer Group, Offset, Exactly-once, 스토리지, OS, 관측, Kubernetes까지 한 바퀴를 돌았다.그럼에도 현장에서 가장 많이 듣는 말은 이것이다.“Kafka를 도입했는데, 오히려 장애가 더 늘어났다.”이 문장의 핵심은 Kafka가 아니다. 기대와 현실의 불일치다.이유 1. Kafka를 메시지 큐로 기대했다Kafka는 메시지를 전달하는 시스템이 아니라 이벤트를 기록하는 로그다.그럼에도 많은 설계는 다음을 전제로 한다.한 번만 처리될 것이다처리되면 사라질 것이다브로커가 상태를 관리해줄 것이다이 기대는 Kafka의 로그 모델과 충돌한다. 결과는 중복 처리, 오프셋 혼란, 리밸런스 폭증이다.이유 2...

10편. Kubernetes 위의 Kafka는 왜 더 위험할까

9편에서 Kafka의 관측이 어려운 이유와 Consumer Lag이 왜 자주 오해되는지를 살펴봤다. 이제 많은 팀이 실제로 부딪히는 환경으로 들어가 보자.“Kafka를 Kubernetes에 올렸더니, 예전보다 장애가 더 잦아졌다.”이 문제는 Kafka나 Kubernetes 중 하나가 나빠서가 아니다. 상태를 가진 시스템(stateful system)을 무상태 플랫폼(stateless-first)에 올렸기 때문이다.Kubernetes는 본질적으로 무상태를 전제로 한다Kubernetes의 설계 전제는 명확하다.Pod는 언제든지 죽을 수 있다다시 뜨면 새 인스턴스다상태는 외부에 있어야 한다이 전제는 웹 서버나 API 서버에는 매우 잘 맞는다. 하지만 Kafka는 다르다.Kafka는 디스크에 상태를 가진 시스템..

8편. Kafka 성능 문제는 JVM이 아니라 OS 문제일 때가 많다

7편에서 Kafka가 디스크를 빠르게 쓰는 이유를 스토리지 구조와 Page Cache 관점에서 살펴봤다. 이제 실무에서 가장 흔한 착각으로 넘어가 보자.“Kafka가 느린데, JVM 옵션을 더 만져야 하나?”많은 경우 이 질문은 방향이 틀려 있다. Kafka 성능 병목의 상당수는 JVM이 아니라 OS와 운영 환경에서 발생한다.왜 JVM부터 의심하게 될까Kafka는 JVM 위에서 동작한다. GC 로그도 있고, 힙도 있다. 그래서 문제가 생기면 자연스럽게 GC-힙-옵션부터 보게 된다.하지만 Kafka의 데이터 경로를 다시 떠올려보자.데이터는 파일로 append된다읽기-쓰기는 Page Cache를 통과한다네트워크 전송은 zero-copy를 활용한다즉, Kafka의 핫패스는 OS 커널 영역에 더 가깝다.CPU가..

7편. Kafka는 디스크를 어떻게 이렇게 빠르게 쓸 수 있을까

6편에서 Exactly-once가 성립하는 조건과 한계를 살펴봤다. 이제 Kafka의 또 다른 오해로 넘어가 보자.“Kafka는 디스크에 쓰는데, 왜 이렇게 빠르지?”이 질문에 대한 답은 Kafka의 스토리지 구조가 아니라 운영체제와 IO를 바라보는 관점에 있다.Kafka는 디스크를 느리다고 가정하지 않는다많은 시스템은 디스크를 “느리고 비싼 자원”으로 취급한다. 그래서 캐시-락-복잡한 메모리 구조를 앞에 둔다.Kafka는 반대로 생각한다.디스크는 순차 쓰기라면 충분히 빠르다.이 전제가 Kafka의 모든 스토리지 설계를 결정한다.Append-only Log의 힘Kafka의 Partition은 append-only log다.항상 파일의 끝에만 쓴다중간 수정이 없다삭제는 즉시 하지 않는다이 구조 덕분에 랜덤..

6편. Exactly-once는 언제 성립하고 언제 깨질까

5편에서 Offset Commit이 “처리 완료”가 아니라 “읽기 위치”일 뿐이라는 이야기를 했다. 그러면 자연스럽게 이런 기대가 등장한다.“그럼 Exactly-once를 쓰면 되는 거 아닌가?”Kafka의 Exactly-once Semantics(EOS)는 많은 오해를 낳는 개념이다. 이유는 간단하다. Exactly-once는 만능이 아니며, 매우 좁은 조건에서만 성립하기 때문이다.Kafka가 말하는 Exactly-once의 정확한 의미Kafka 공식 문서에서 말하는 Exactly-once는 흔히 기대하는 의미와 다르다.Kafka의 EOS는 다음을 의미한다.“Kafka 내부에서, 입력 레코드 하나가 출력 레코드 하나로 정확히 한 번 반영된다.”여기서 중요한 전제는 Kafka 내부다. DB, 외부 API..

5편. Offset Commit은 왜 이렇게 오해받을까

4편에서 Consumer Group과 Rebalance가 왜 운영 사고의 중심이 되는지 살펴봤다. 그 다음에 반드시 등장하는 질문이 있다.“Offset을 커밋했는데, 왜 중복 처리됐지?”이 질문은 Offset Commit을 무엇으로 이해하고 있는지를 그대로 드러낸다. Kafka에서 Offset Commit은 ‘처리 완료’의 의미가 아니다.Offset이 의미하는 것Offset은 단순히 말하면 로그에서의 위치다.Partition은 append-only log이고, Offset은 그 로그에서 “어디까지 읽었는지”를 나타낸다.Offset = 처리 결과Offset = 비즈니스 상태이 둘은 모두 틀린 해석이다.Offset은 오직 “읽기 진행 상황”만 표현한다.Commit은 무엇을 보장하고 무엇을 보장하지 않는가Of..

4편. Consumer Group과 Rebalance는 왜 항상 사고를 부를까

3편에서 Partition이 순서와 확장을 동시에 만족시키는 설계 단위라는 이야기를 했다. 이제 그 Partition 위에서 실제 처리를 담당하는 Consumer Group으로 넘어가 보자.Kafka 운영 경험이 있는 팀이라면 한 번쯤 이런 말을 해봤을 것이다.“아무 일도 안 했는데 리밸런스가 일어났다.”이 현상은 우연이 아니다. Consumer Group의 설계 자체가 리밸런스를 전제로 하고 있기 때문이다.Consumer Group은 무엇을 해결하려는 개념인가Consumer Group의 목적은 단순하다.하나의 Topic을 여러 Consumer가 나눠서 처리한다Partition은 오직 하나의 Consumer에게만 할당된다Consumer 수에 따라 처리량을 수평 확장한다이 구조 덕분에 Kafka는 병렬 처..

3편. Partition은 확장을 어떻게 가능하게 만드는가

2편에서 Kafka가 Pull 모델을 선택한 이유를 살펴봤다. 이제 Kafka를 Kafka답게 만드는 또 하나의 핵심 질문으로 넘어가자.“Kafka는 어떻게 많은 데이터를 빠르게 처리하면서도, 순서를 보장할 수 있을까?”그 답이 바로 Partition이다.Partition은 단순한 분할이 아니다Topic을 여러 개의 Partition으로 나눈다고 하면, 흔히 이렇게 이해한다.“데이터를 쪼개서 병렬로 처리하겠다는 거구나.”반은 맞고, 반은 틀리다. Partition은 단순한 성능 최적화 수단이 아니다.Kafka가 순서(ordering)와 확장성(scalability)을 동시에 만족시키기 위해 선택한 최소 단위다.Kafka에서 순서는 어디까지 보장되는가Kafka 공식 문서는 순서 보장에 대해 매우 명확하게 ..

1편. Kafka는 왜 메시지 큐가 아니라 로그일까

Kafka를 처음 접하면 흔히 이렇게 부른다. “대용량 메시지 큐”.하지만 이 표현은 Kafka를 이해하는 데 가장 빠르게 길을 잃게 만드는 출발점이다.Kafka는 메시지 큐가 아니다. Kafka 공식 문서에서 반복해서 강조하는 모델은 분산 로그(distributed commit log)다.메시지 큐의 사고방식전통적인 메시지 큐는 다음 질문에 초점을 맞춘다.메시지를 누가 가져갈 것인가한 번만 전달되었는가처리되면 삭제되었는가큐의 핵심은 중간에서 메시지를 관리하는 것이다. 브로커는 “이 메시지는 누가 가져갔는지”를 기억한다.소비자는 수동적이다. 메시지는 밀려오고(push), 소비자는 받아서 처리한다.Kafka의 사고방식은 다르다Kafka는 처음부터 이 질문을 다르게 던진다.“데이터를 어떻게 오래, 많이, 안..

반응형