Replica Recovery

Replica에 장애가 났을 때 어떤식으로 복구를 할까? acks라는 producer parameter가 굉장히 중요하다. 바로 예시를 보자. 만약에 3개의 Replica로 구성된 하나의 Partition이 있고, Producer가 4개의 메시지(M1, M2, M3, M4)를 보냈다고 하자. 메시지M1, M2가 ISR 리스트 전체에 복제 및 Commit 되었고, Y는 M3를 복제했지만 Commit은 못한 상태, Z는 M2까지만 복제했다.

acks=all 인 경우

cks=all은 메시지가 모든 Replica까지 Commit되면 ack를 보낸다.

image

Leader X 가 죽으면 controller에 의해 새로운 leader가 선출되는데, Y가 새로운 leader가 됐다고 하면, leader epoch가 0에서 1로 증가한다. Z는 이제 Y에게서 M3를 fetch 해오고, Y는 high water mark를 진행한다. Z는 fetch를 다시 수행하고 high water mark를 수신한다.

image

여기서 이상한 점은 M3는 Commit 된 적이 없는데 왜 Y는 M3를 가지고 있을수 있을까? kafka는 수신된 데이터를 지우지 않기 때문이다. 하지만 broker X는 M3, M4에 대한 ack를 Producer에게 보내지 못했다. ack는 복제가 되었다는 것을 확인하고 보낼 수 있다. 그러면 producer는 retry로 M3, M4을 다시 Y로 보내고, 새로운 leader Y는 M3, M4를 받는다. M3도 중복으로 받게 되는데 이는 enable.idempotence 옵션이 false로 되어 있기 때문이다. Z는 그런 사실을 모르고 그냥 leader를 따라간다. Z는M3(중복), M4를 fetch하고 Z는 fetch를 다시 수행하여 High Water Mark를 받는다.

image

이제 죽었던 X가 다시 살아난다면? X는 follower가 되어서 leader Y에서 복제를 받아오기 시작한다. X가 복구되면 Zookeeper에 연결되고, X는 Controller로부터 metadata를 받고, X는 Leader Y로부터 Leader Epoch를 fetch한다. X는 Leader가 변경된 시점인 M2 이후의 데이터 M3, M4를 지워버린다.

image

그 다음부터 다시 복제를 시작한다. 복제가 한번 일어나면, ISR 리스트에 복귀한다.

image

acks=1 인 경우

acks=1은 default값으로, Leader가 메시지를 수신하면 잘 받았다고 producer에게 ack를 보낸다. 그렇기 때문에 Leader X가 장애 나기 전에 Producer는 M4에 대한 ack를 수신할 수 있다.

이때 복제가 되다가 leader X가 죽어 새로운 leader로 Y가 선출되었다고 하자. 똑같이 Leader Epoch가 0에서 1로 증가했고, Z는 M3를 fetch할 수 있다. Y는 High Water Mark를 진행하고, Z는 fetch를 다시 수행하고 High Water Mark를 받는다. 하지만 producer가 M4를 다시 보내지 않기 때문에 M4는 영원히 잃어버린다.

image


Topic parameter

ISR 리스트를 쓰는 이유는 leader가 죽었을 때 최대한 데이터의 유실을 방지하면서 ISR 리스트에 있는 replica를 새로운 leader로 선출하여 쓰기 위함이다. 만약에 ISR 리스트에 replica가 하나도 없다면 새로운 leader는 선출되지 않을 것이고, leader가 없어지면 데이터를 받거나 보내는 역할을 할 수 없게 된다. 그러면 서비스는 중단된다.

그래서 임시방편으로 ISR 리스트에 없는 replica를 leader로 선출하는 옵션이 있다. unclean.leader.election.enable=True 이라는 topic parameter이다.

또 다른 옵션으로는 최소 요구되는 ISR의 개수에 대한 옵션을 설정하는 min.insync.replicas topic parameter이다. 이 옵션의 default 값은 1로, ISR이 min.insync.replicas 보다 적은 경우 producer는 NotEnoughReplica 예외를 받는다. 일반적으로 min.insync.replicas=2로 설정하는데, Producer 파라미터인 acks=all과 함께 사용할때 더 강력한 보장을 할 수 있다. n개의 Replica가 있고, min.insync.replicas=2 인 경우 n-2개의 장애를 허용할 수 있다.

  • 데이터 유실이 없게 하려면?
    • Topic : replication.factor는 2보다 커야함 (최소3이상)
    • Producer : acks는 all 이어야함
    • Topic : min.insync.replicas는 1 보다 커야함 (최소2이상)
  • 데이터 유실이 있더라도 가용성을 높게 하려면?
    • Topic : unclean.leader.election.enable를 true로 설정