리더가 죽었는데 리더를 이어받을 인-싱크 레플리카가 없을 때, 뒤처진 레플리카를 리더로 삼을 것인가. 가용성과 일관성 중 무엇을 택할지 정면으로 묻는 설정이다. unclean.leader.election.enable, 기본값은 false다.
클린 선출과 언클린 선출
클린 리더 선출은 인-싱크 레플리카 중 하나가 새 리더가 되는 경우다. 커밋된 데이터에 유실이 없음이 보장되는데, 커밋의 정의가 “모든 ISR에 존재하는 것”이라서 자동으로 따라 나온다.
언클린 리더 선출은 작동 불능한 리더 외에 인-싱크 레플리카가 없는 경우다. 선택지가 둘뿐이다. 아웃-오브-싱크 레플리카를 리더로 선출하면 유실을 감수하는 것이고, 원래 리더가 복구될 때까지 기다리면 그동안 파티션이 오프라인이 된다.
언클린 상황이 만들어지는 두 갈래
이런 상황은 두 갈래로 만들어진다.
팔로워가 먼저 죽는 경우다. 레플리카 3개 중 팔로워 2개가 크래시로 죽어도 프로듀서는 리더에 계속 쓴다. 리더가 유일한 ISR이므로 모든 메시지가 커밋되고 성공 응답이 간다. 이후 리더도 죽으면, 아웃-오브-싱크 레플리카 중 하나가 먼저 시작되는 순간 그것이 그 파티션에서 유일하게 사용 가능한 레플리카가 된다.
팔로워가 뒤처지는 경우도 결과가 같다. 네트워크 문제로 복제가 밀리면 복제 작업 자체는 계속되지만 인-싱크 상태는 아니다. 리더가 죽으면 리더가 될 수 있는 것은 아웃-오브-싱크 레플리카밖에 없다.
선호 리더 선출
이름이 비슷한 선호 리더 선출은 다른 이야기다. 각 파티션은 선호 리더로 불리는 레플리카를 하나씩 가지는데, 모든 파티션이 선호 리더를 리더로 삼으면 브로커마다 할당되는 리더 수의 균형이 맞는다. 카프카는 5분마다 선호 리더가 실제로 리더를 맡고 있는지 확인하고, 맡을 수 있는데도 맡고 있지 않으면 그것을 리더로 삼는다.
auto.leader.rebalance.enable이 이 동작을 켜고 끈다. 꺼져 있거나 즉시 실행하고 싶으면 AdminClient의 electLeaders()를 쓴다. 같은 메서드로 언클린 리더 선출도 할 수 있다.
같은 오프셋에 다른 메시지
true로 두면 유실만 생기는 것이 아니라 컨슈머가 보는 데이터가 어긋난다.
레플리카 1(리더), 2, 3이 있고 2와 3이 작동 불능이라고 하자. 1이 오프셋 100200에 해당하는 메시지를 쓴다. 2와 3에는 099까지만 있다. 1이 죽고 2가 새 리더가 되면 2는 오프셋 100~200에 새로운 메시지를 쓴다. 같은 오프셋에 다른 메시지가 들어간 것이다.
오프셋이라는 좌표 자체를 믿을 수 없게 된다. 이미 100~150을 읽은 컨슈머와 이제 읽기 시작하는 컨슈머가 전혀 다른 데이터를 본다. 가용성보다 데이터 정합성이 중요하면 false로 두는 이유이고, 기본값이 false인 이유이기도 하다.
멱등적 프로듀서를 쓸 때 시퀀스 넘버 간격이 크고 지속적으로 벌어진다면 이 설정이 true로 켜져 있는지 가장 먼저 의심해야 한다.