Broker에 장애가 발생하면 어떻게 될까? 장애가 발생한 Broker의 Partition들은 모두 사용할 수 없게 되는 문제가 발생할 것이다.

계속 하기 전에 다시 한번 복습해보자면,

- Producer가 Write하는 LOG-END-OFFSET과 Consumer Group의 Consumer가 Read하고 처리한 후에 Commit한 CURRENT-OFFSET과의 차이(Consumer Lag)가 발생할 수 있다고 했다.
- 이 상태에서 장애가 나면?
다른 Broker에서 Partition을 새로 만들 수 있으면 장애는 해결될까? 다음과 같이 말이다.

- 고장난 Broker에 있는 파티션들을 다른 멀쩡한 Broker에 새로 만들었다. 해결될 것 같지만 이러한 고민거리가 남는다.
- 기존 메시지는 버릴 것인가? 기존 Offset 정보들을 버릴 것인가?
Replication
위와 같은 문제를 해결하기 위해, Partition을 복제(Replication)하여 다른 Broker상에서 복제물(Replicas)을 만들어서 장애를 미리 대비한다.
Replicas - Leader Partition, Follower Partition

- 위 그림처럼, Leader 1개, Follower 2개로 총 Replicas는 3개가 있다.
- Producer는 Leader에만 Write하고, Consumer는 Leader로부터만 Read한다.
- Follower는 Broker 장애시 안정성을 제공하기 위해서만 존재한다.
- Follower는 Leader의 Commit Log에서 데이터를 가져오기 요청(Fetch Request)으로 복제한다.

- 물론, 2.4부터 Follower에도 Consumer가 Read할 수 있는 기능이 추가됐지만 기본적으로는 Leader에서만 Read한다.
Leader에 장애가 발생하면?
Kafka 클러스터는 Follower 중에서 새로운 Leader를 선출한다. Clients(Producer/Consumer)는 자동으로 새 Leader로 전환하여 Write/Read를 한다.

Partition Leader에 대한 자동 분산
하나의 Broker에만 Partition의 Leader들이 몰려 있다면? 여러가지 문제가 발생한다.
- 특정 Broker에만 Clients(Producer/Consumer)로 인해 부하 집중
- 해당 Broker가 고장나면 모든 Partition에 대해서 Leader를 다 재선출

- 이러한 문제가 있기 때문에 기본적으로 Leader를 골고루 분산하는 옵션이 켜져있다.
- auto.leader.rebalance.enable (기본값 enable)
- leader.imbalance.check.interval.seconds (기본값 300 sec)
- leader.imbalance.per.broker.percentage (기본값 10)

- 그래서 이와 같은 골고루 Leader를 분산하여 Broker에 저장된다.
Rack Awareness
- 동일한 Rack 혹은 Available Zone 상의 Broker들에 동일한 "rack name" 지정
- 복제본 (Replica-Leader/Follower)은 최대한 Rack 간에 균형을 유지하여 Rack 장애 대비
- Topic 생성 시 또는 Auto Data Balancer/Self Balancing Cluster 동작 때만 실행

In-Sync Replicas (ISR)
Leader 장애시 Leader를 선출하는데 사용된다. In-Sync Replicas(ISR)는 High Water Mark라고 하는 지점까지 동일한 Replicas(Leader와 Follower 모두)의 목록이다. Leader에 장애가 발생하면 ISR중에서 새 Leader를 선출한다.

- 보면, replica.lag.max.messages=4 라는 옵션으로 설정되면 4개 이상으로 메시지(데이터)가 차이가 나는 Replica는 OSR(Out-of-Sync Follower)이라고 간주한다.
- 그리고, 그 범위 안에 들어오는 Replica는 ISR이라고 간주한다. 보면 Broker102에 있는 Follower는 2개밖에 차이가 나지 않기 때문에 ISR로 간주된다.
- 저 High Water Mark는 무엇이냐? Leader에 Producer가 데이터를 생산을 쭉 해나가면, Follower들은 Fetch Request를 통해 Leader의 데이터를 계속 복제하려 할 것이다. 이때, 모든 Follower들(ISR에 속한)이 전부 다 복제한 지점까지를 High Water Mark라고 한다.
그런데 이 replica.lag.max.messages로 ISR을 판단할 때 어떤 문제가 있을 수 있냐면,
- 메시지가 항상 일정한 비율로 Kafka로 들어올 때는 지연되는 경우가 없을것이므로 ISR들이 정상적으로 동작한다.
- 그런데 갑자기 메시지 유입량이 늘어난다면 예를 들어, 원래는 초당 3개의 메시지만 들어왔는데 갑자기 초당 20개의 메시지가 들어오면 20개의 차이가 갑자기 나니까 replica.lag.max.messages를 4로 설정하면 지연으로 판단하고 OSR로 상태를 변경시킨다.
- 그런데 실제 Follower들은 정상적으로 동작하고 단지 잠깐 지연만 발생했을 뿐인데 OSR로 판단하게 되는 문제가 발생한다. 이로 인해 운영중에 불필요한 에러 발생 및 그로 인해 불필요한 Retry를 유발하므로써 좋지 않은 상태가 된다)
그래서, replica.lag.time.max.ms로 판단해야 한다.
- Follower가 Leader로 Fetch 요청을 보내는 Interval을 체크
- 예) replica.lag.time.max.ms = 10000 이라면 Follower가 Leader로 Fetch 요청을 10000ms 내에만 요청하면 정상으로 판단
ISR은 Leader가 관리한다.
- Follower가 너무 느리면, Leader는 ISR에서 Follower를 제거하고, 변경 사항에 대한 메타데이터를 Controller가 받아 처리한다.
- 여기서 Controller란?
- Kafka Cluster 내의 Broker 중에 하나가 Controller가 된다.
- Controller는 Leader와 Replica 정보를 Cluster내의 다른 Broker들에게 전달한다.
- Controller가 Leader 장애 시 Leader Election을 수행
- Controller가 장애가 나면 다른 Active Broker들 중에서 재선출
Consumer 관련 Position들

- Last Committed Offset(Current Offset): Consumer가 최종 Commit한 Offset
- Current Position: Consumer가 읽어간 위치(처리 중, Commit 전). 그러니까, 마지막으로 커밋한 지점은 2인데 Consumer가 데이터를 지금 현재 읽는중이고 2부터 6까지 읽고 있는 중이라고 생각하면 된다.
- High Water Mark(Committed): ISR간에 복제된 Offset.
- Log End Offset: Producer가 메시지를 보내서 저장된 로그의 맨 끝 Offset
High Water Mark(Committed)의 의미
- ISR 목록의 모든 Replicas가 메시지를 성공적으로 가져오면 Committed.
- Consumer는 Committed 메시지만 읽을 수 있다. (위 그림에서는 0 ~ 11번 메시지까지)
- Leader는 메시지를 Commit할 시기를 결정한다.
- Committed 메시지는 모든 Follower에서 동일한 Offset을 갖도록 보장한다. (모든 Replicas들이 0번 메시지는 0번 메시지를 가르키고, 10번 메시지는 10번 메시지를 가르키고, 11번 메시지는 11번 메시지를 가르킨다는 의미)
- 즉, 어떤 Replica가 Leader인지에 관계없이 모든 Consumer는 해당 Offset에서 같은 데이터를 볼 수 있다. (Leader, Follower 상관없이 0번 메시지는 모두 다 동일한 0번 메시지라는 것을 말함)
- Broker가 다시 시작할 때 Committed 메시지 목록을 유지하도록 하기 위해, Broker의 모든 Partition에 대한 마지막 Committed Offset은 replication-offset-checkpoint라는 파일에 기록됨
Message Commit 과정

- Offset 5까지 복제가 완료된 상태에서, Producer가 메시지를 보내면 Leader가 offset 6에 새 메시지를 추가
- Fetcher Thread는 모든 브로커에 존재하고, 각 브로커에 모든 Follwer들이 본인의 Leader에 메시지를 가져오기 요청을 보낼 때 사용

- 각 Follower들의 Fetcher Thread가 독립적으로 fetch를 수행하고, 가져온 메시지를 offset 6에 메시지를 write

- 이 상태에서 각 Follwer들의 Fetcher Thread가 또 독립적으로 fetch를 수행하고 null을 받는데, null을 Leader가 준다는 것은 Leader가 모든 Follwer들에게 현재 내가 가진 모든 데이터를 다 정상적으로 줬음을 의미하므로, High Water Mark를 이동시킨다.

- 각 Follower들의 Fetcher Thread가 독립적으로 또 다시 fetch를 수행하고, High Water Mark를 받는다. 받은 High Water Mark로 이동한다.
정리하자면
- Partition을 복제(Replication)하여 다른 Broker 상에서 복제물(Replicas)을 만들어서 장애를 미리 대비함
- Replicas - Leader Partition, Follower Partition
- Producer는 Leader에만 Write하고, Consumer는 Leader로부터만 Read한다.
- Follower는 Leader의 Commit Log에서 데이터를 가져오기 요청(Fetch Request)으로 복제
- 복제본(Replicas-Leader/Follower)은 최대한 Rack 간에 균형을 유지하여 Rack 장애 대비하는 Rack Awareness 기능이 있다.
- In-Sync Replicas(ISR)는 High Water Mark 라고 하는 지점까지 동일한 Replicas(Leader, Follower)의 목록
- High Water Mark(Committed)는 ISR(Leader-Follower)간에 복제된 Offset
- Consumer는 Committed 메시지만 읽을 수 있다.
- Kafka Cluster 내의 Broker 중 하나가 Controller가 된다.
'Apache Kafka' 카테고리의 다른 글
p8. Replica Failure (0) | 2025.03.15 |
---|---|
p7. Acks, Batch, Page Cache, Flush (0) | 2025.03.15 |
p5. Consumer (0) | 2025.03.15 |
p4. Producer (0) | 2025.03.15 |
p3. Broker (0) | 2025.03.15 |