Skip to content

카프카 인프라 공부 ​

복제와 isr (in-sync replicas) ​

파티션 복제 (Replication Factor) 카프카는 토픽의 파티션을 여러 대의 브로커(서버)에 복제하여 저장합니다. 이때 복제본들은 Leader(리더)와 Follower(팔로워)라는 역할 ​

  • Leader: 모든 읽기와 쓰기 작업을 전담 처리합니다.
  • Follower: 리더의 데이터를 실시간으로 복제(Fetch)해 가며, 리더가 죽었을 때 왕위를 계승할 준비를 합니다.

ISR (In-Sync Replicas)의 관리 ​

  • 이슈(네트워크 지연, 장애) 등으로 따라오지못하는 팔로워 발생시 리더의 데이터와 거의 동일하게 동기화되어 있는 유효한 복제본 그룹을 ISR(In-Sync Replicas)이라는 가두리 양식장처럼 관리
  • 리더가 급작스럽게 죽으면, 오직 ISR 그룹에 속한 팔로워만 새로운 리더가 될 자격이 있음

유실을 막는 핵심 운영 옵션 (Producer & Broker) ​

  • 완벽한 유실 방지(Ack-all) 체인을 완성하는 핵심 옵션 3가지

프로듀서 옵션: acks=all (acks=-1) ​

  • acks=0: 보낸 즉시 성공으로 간주 (유실 위험)
  • acks=1: 리더 브로커가 자기 디스크에 기록만 하면 성공으로 간주 (리더가 복제해주기 전에 죽으면 유실)
  • acks=all: 리더뿐만 아니라 현재 ISR 그룹에 속한 모든 팔로워까지 데이터를 안전하게 복제 완료했을 때 비로소 프로듀서에게 성공 응답을 보냅니다

브로커 옵션: min.insync.replicas ​

  • acks=all과 반드시 세트로 움직여야 하는 브로커 측 옵션입니다. "최소 몇 개의 ISR 복제본이 데이터 복제를 성공해야 프로듀서의 요청을 최종 성공으로 인정할 것인가"를 정의합니다.
  • 권장 설정 (Replication Factor가 3일 때): min.insync.replicas=2
  • 동작 방식: 리더를 포함해 최소 2대 이상의 브로커에 데이터가 저장되어야 성공으로 인정합니다. 만약 브로커 2대가 동시에 죽어서 ISR에 리더 1대만 남는다면, 카프카는 프로듀서의 쓰기 요청을 거부(NotEnoughReplicasException)하여 불완전한 저장을 원천 차단합니다.

브로커 옵션: unclean.leader.election.enable=false ​

  • 만약 리더 브로커가 죽었는데, ISR 그룹(최신 데이터를 가진 팔로워들)에 남은 브로커가 하나도 없는 극단적인 상황이 발생했을 때의 대처법입니다.
  • true로 둘 경우: 최신 데이터가 없는(동기화가 뒤처진) 일반 팔로워를 리더로 승인합니다. 서비스는 계속 굴러가지만, 과거 복제하지 못한 데이터는 통째로 유실됩니다.
  • false로 둘 경우: 데이터가 유실되는 위험을 감수하느니, 기존 리더가 살아날 때까지 해당 파티션의 서비스(읽기/쓰기)를 중단시킵니다. 데이터의 정합성과 무결성을 최우선으로 할 때 필수적인 설정입니다.

카프카 운영시 메모리 ​

  • 보통 자바 프로그램들은 데이터를 메모리에 올려두려고 JVM 힙(Heap) 메모리를 크게 잡지만, 카프카 브로커는 의외로 힙 메모리를 4GB~6GB 수준으로 매우 작게잡는 대신 나머지 OS 메모리 공간을 OS의 페이지 캐시 영역으로 비워둠
  • 페이지 캐시란? 리눅스 같은 OS는 디스크 읽기/쓰기 성능을 높이기 위해, 남는 RAM 공간을 디스크 데이터의 복사본을 저장하는 캐시로 활용

카프카의 메모리 사용 : OS의 '페이지 캐시(Page Cache)' ​

  • 카프카는 OS페이지 캐시에 완전히 의존합니다. 이 때문에 카프카 서버를 모니터링해보면 항상 RAM 사용량이 꽉 차 있는 것처럼 보이게 됩

디스크 순차 쓰기와 페이지 캐시 시너지 ​

  • 쓸 때 (Write): 프로듀서가 메시지를 보내면, 카프카는 곧바로 물리 디스크로 가지 않고 OS 페이지 캐시(RAM)에 먼저 씁니다. 그리고 OS가 백그라운드에서 이 데이터를 디스크에 순차적(Sequential)으로 아주 예쁘게 정렬해서 저장합니다. (RAM에 먼저 쓰니 당연히 빠릅니다.)
  • 읽을 때 (Read): 컨슈머가 데이터를 읽으러 오면, 카프카는 디스크를 뒤지지 않고 OS 페이지 캐시(RAM)에 데이터가 있는지 먼저 봅니다. 방금 들어온 실시간 데이터라면 100% RAM에 남아있기 때문에, 디스크에는 손도 안 대고 메모리 속도로 컨슈머에게 데이터를 던져줍니다.
  • 결국 "쓸 때는 디스크 순차 쓰기 덕분에 빠르고, 읽을 때는 메모리(페이지 캐시) 덕분에 빠른" 구조

제로 카피(Zero-Copy)' 기술 ​

  • 카프카가 메모리를 효율적으로 쓰면서 성능을 극대화하는 마지막 퍼즐은 제로 카피(Zero-Copy)입니다.
  • 보통의 애플리케이션이 디스크의 데이터를 네트워크로 보내려면 아래 그림의 상단처럼 디스크 -> OS 커널 버퍼 -> JVM 애플리케이션 메모리 -> OS 소켓 버퍼 -> 네트워크라는 복잡한 복사 과정을 거치며 CPU와 메모리를 낭비합니다. -하지만 카프카는 어차피 메시지를 가공하지 않고 그대로 보내기 때문에, 리눅스의 sendfile 시스템 콜을 이용해 그림 하단처럼 OS 페이지 캐시(RAM)에 있는 데이터를 중간 과정 없이 곧바로 네트워크(NIC Buffer)로 쏴버립니다.
  • 이 과정에서 JVM 메모리로 데이터가 복사되지 않기 때문에 카프카 프로세스 자체의 메모리 오버헤드가 극도로 낮고, CPU 사용량도 획기적으로 줄어듭니다.

SSD 에서도 순차쓰기가 랜덤쓰기보다 몇백배 더 빠른 속도임 ​

  • SSD는 반도체(NAND 플래시)에 데이터를 저장합니다. 이 반도체는 데이터를 다루는 단위가 두 가지로 나뉩니다.
    • 페이지(Page): 데이터를 읽고 쓰는 단위 (보통 4KB ~ 16KB)
    • 블록(Block): 데이터를 지우는 단위 (보통 수 MB, 페이지가 수백 개 모인 크기)
  • 여기서 SSD의 치명적인 약점이 생깁니다. SSD는 이미 데이터가 써진 자리에 바로 덮어쓰기(Overwrite)를 못 합니다. 반드시 기존 자리를 지우고(Erase) 새로 써야 하는데, 지우는 건 훨씬 큰 단위인 '블록'으로만 가능합니다.
  • 블록을 빈틈없이 차례대로 꽉꽉 채워 나가기 때문에 가비지 컬렉션이 일어날 여지 자체가 없습니다. SSD 컨트롤러 입장에서는 복잡한 머리싸움 없이 초고속으로 플래시 메모리에 데이터를 때려 박을 수 있는 최적의 조건

카프카의 '통째 삭제(Segment Delete)' 전략 ​

카프카는 메시지 건건이 지우지 않습니다. 로그를 약 1GB 크기의 세그먼트(Segment) 파일 단위로 묶어서 저장하다가, 보관 주기(예: 7일)가 지나면 이 1GB짜리 파일을 통째로 OS에서 날려버립니다.