복제와 ISR
복제와 ISR
카프카는 각 토픽의 파티션 로그(log)를 여러 서버에 복제(replicate) 해서, 어떤 서버가 죽어도 메시지가 계속 유지되도록 해요. 복제 반복 팩터(replication factor)는 토픽마다 설정할 수 있고, 이 복제 덕분에 클러스터의 서버 하나가 실패해도 나머지 복제본으로 자동 페일오버(failover) 가 일어나요. 복제의 단위는 바로 토픽-파티션 이에요.
본문
정상적인 상황에서 각 파티션에는 하나의 리더(leader) 와 0개 이상의 팔로워(follower) 가 있어요. 리더를 포함한 복제본의 총 개수가 곧 복제 팩터가 되고요. 프로듀서가 쓰는 데이터는 리더에게 전달되고, 팔로워들은 리더의 로그를 따라잡으며 복제해요.
카프카가 복제본을 고르는 방식은 다수결(majority vote)이 아니에요. 대신 in-sync replicas(ISR) 라고 부르는, 리더를 따라잡은 복제본들의 집합을 동적으로 유지해요. 이 ISR 의 멤버만 리더 후보가 될 수 있고, 이 ISR 집합이 바뀔 때마다 클러스터 메타데이터에 영속적으로 기록돼요. 그래서 ISR 안의 어떤 복제본이든 리더로 선출될 수 있어요.
카프카 파티션에 대한 쓰기(write)는 모든 ISR 이 그 쓰기를 받기 전까지는 커밋(commit) 되지 않은 것으로 간주돼요. 프로듀서가 acks=all(=-1)로 요청하면 메시지가 전체 ISR 에 적용된 뒤에만 승인 응답을 받아요. 반대로 acks=0 이면 비동기적으로, acks=1 이면 리더에만 동기적으로 커밋하고요. 메시지가 커밋된 뒤에는, 그 파티션을 복제하는 브로커가 하나라도 살아있는 한 메시지가 유실되지 않아요.
복제 팩터가 f+1 개인 ISR 모델에서는, 카프카가 파티션 수가 많고 리더십 밸런스가 중요한 사용 모델에서 유리한 성질을 가져요. ISR 에 속한 복제본으로 f 개의 장애를 견딜 수 있기 때문이에요. 커밋된 메시지는 적어도 ISR 하나가 살아있는 한 잃지 않는다는 보장이 항상 성립해요.
복제본이 리더를 따라잡지 못할 때는 ISR 에서 빠져요. 그리고 ISR 이 최소 ISR 수(min.insync.replicas) 보다 적어지면, 데이터는 유실되지 않지만 그 파티션은 쓰기(write)가 불가능해져 가용성(availability)이 떨어져요. ISR 이 전부 죽어 버리는 상황에선 리더 선출을 어떻게 할지 선택해야 하는데, 카프카 기본값은 일관성(consistency)을 우선해 일관된 복제본을 기다리는 쪽을 택해요. unclean.leader.election.enable 설정으로 가용성(uptime)을 우선하는 비정상(unclean) 리더 선출을 허용할 수도 있어요.
이 많은 복제를 실제로 조율하는 역할이 컨트롤러(controller) 예요. 컨트롤러는 브로커의 등록과 관리를 담당하고, 브로커 하나가 실패했다고 감지하면 ISR 의 남은 멤버 중 하나를 새 리더로 선출해요. 그리고 로그 압축(log compaction)이나 브로커 관리 등도 함께 다루며, 수백·수천 개의 파티션이 있는 클러스터를 꾸준히 운영할 수 있게 해줘요.
더 알아보기
- 메시지가 "커밋"된다는 것의 정확한 의미는 [메시지 전달 의미론] 문서를 보면 돼요.
- 파티션이 여러 브로커에 나눠지는 원리는 [토픽과 파티션] 문서에서 확인해요.
- 복제 관련 토픽 설정값과
min.insync.replicas는topic-config문서를 참고해요.