Kafka의 구성
System 구성은 다음과 같이 직관적이다.
Producer -> Kafka -> Consumer
- Message를 생산하는 Producer
- Message를 보관하는 Kafka
- Message를 사용하는 Consumer
Kafka 저장소 형태
Topic > Partition > Leader(원본) & Follower(복제본) 순으로 깊게 들어간다.
- Kafka에서는 데이터를 메시지라는 용어로 사용한다.
- 메시지는 논리적 저장 공간인 Topic에 저장된다.
- Topic에 저장되는 메시지들은 다수의 서버에 분산되어 있는 Partition에 저장된다.(Partition 개수 설정 가능)
- 메시지는 다수의 Partition에 저장되는데 이들은 Replication Factor를 통해 복제본을 만들어 저장된다.
- 하나의 Partition은 Leader와 Follower로 나뉘게 된다.
- Replication factor 만큼 복제를 해야 하니 누군가는 첫번째 원본을 저장하고 있어야 하고(leader) 누군가는 그것의 복제본을 저장하고 있어야 한다.(follower)
- Replication factor가 3이라면 1개의 원본, 2개의 복제본을 만든다.
- Leader가 원본을 저장하기에 Producer와 Consumer는 Leader하고만 통신하면 된다.
- 그럼 특정 노드만 부하가 올라가냐? 하나의 Partition에 Leader가 존재하고, 서로 다른 Partition의 Leader는 여러 서버에 분산되어 존재한다. 그래서 서버가 충분히 많다면 걱정할 필요는 없다. 그러나 여기서 짐작하듯이 서버수와 Partition 수가 상관관계가 있을 수 밖에 없구나... 라고 느끼게 된다.
- Leader와 Follower는 High Availability에 연관되어 장애시 failover 정책에 따라 역할이 정해진다.
Leader & Follower
Leader 선출
보통 Leader 선출한다고 하면 드는 생각이 '아! zookeeper에 ephemeral node를 선점하는 녀석이 이기겠구나! 라던지 lock node를 선점하는 녀석이 이기는 거겠지?' 라고 생각할 수 있으나 kafka는 좀 다르다.;;;
Kafka는 Leader를 선정할 때 여러 노드에 분산하여 선정한다. 그래야 특정 서버에 부하가 몰리지 않겠지. 장애 등으로 인해 leader가 죽으면 follower 중 하나를 leader로 세우겠지. 다음과 같은 정책이 있다.
- prefered replica leader: kafka가 보기에 '이 partition의 leader는 니(노드)가 하는 게 좋겠어' 라고 지정한 것
- auto.leader.rebalance.enable=true: 장애등으로 인해 특정 leader가 죽었다면 follower중 하나가 leader가 되어야 하는데 kafka가 공들여서 만들어 놓은 leader 분배 밸런스가 깨지겠지? 그럼 다시 밸런스를 맞춰야 겠지. 이 옵션을 켜면 그렇게 해 준다. (kafka-preferred-replica-election.sh으로 수동으로 할 수도 있음)
ISR(In-Sync Replicas)
"In-Sync" 라는 말은 '동기화 되어 있다.' 정도로 해석할 수 있지 않을까? 즉, follower가 나의 leader와 동기화 되어 있다!라고 생각해야 제대로 된 replica라고 할 수 있지 않겠나.
"ISR"은 하나의 partition에서 동기화 되어 있다고 판단되는 replica set을 이야기 한다. 즉, leader와 follower의 집합이다.
그럼 동기화 주기는 어떻게 되는가? replica.lag.time.max.ms 시간 내 동기화 되었다고 느끼면 된거다.(default 500ms)
그런데 조금 이상하다. Follower 입장에서 동기화라고 하면 '내가 얼마 주기로 동기화 해야 하지?' 라던지 '계속 폴링 해야지?' 라던지... 'replica.lag.time.max.ms'라는 옵션을 해석해 보자. '동기화에 걸리는 최대 지연시간'. 뭔가 굉장히 강압적인 이 느낌. 그렇다. follower는 저 시간내 동기화 되지 못하면 짤린다. 즉, ISR에서 퇴출된다.
Follower가 ISR 멤버임을 유지할 수 있는 조건은 다음과 같다. 실제로는 replica.lag.time.max.ms 만 설정해도 된다.
- replica.lag.time.max.ms: leader와 최소 이 시간 마다 동기화 해야 함
- replica.lag.max.messages: leader와 동기화된 메시지의 최대 차이를 이 수 내에서 유지해야 함 (있다는 것만 알아도 된다.)
동기화가 되어 있지 않은 follower에는 어떤 유형이 있을까?
- Slow replica: I/O 등의 이슈로 동기화가 느린 유형
- Stuck replica: GC 발생 또는 서버 장애 등의 이유로 전혀 동작하지 않는 유형
- Boostrapping replica: ISR 수를 조정하여 새로운 follower로 등록된 경우 leader가 가진 모든 메시지를 복사하는 유형
아무튼 Follower가 이렇게 기구한 운명을 타고난 이유를 살펴보기 위해서는 메시지가 저장되는 과정의 일부를 살펴볼 필요가 있다.
Acknowledgement
publisher, 즉 메시지를 생산하는 입장에서 중요한 것은 역시 내가 보낸 메시지가 안전하게 저장되었는 지 확인하는 것이다. 중요한 것은 안전한 전송이 아니라 안전한 저장 이다. 즉, 메시지가 안전하게 전송된 후 역시 안전하게 저장되어야 ACK를 받는다는 것을 기저에 두고 있다.
- acks=0: publisher는 leader에게 메시지를 전송하지만 저장여부에 관심이 없다. 그냥 계속 보내기만 한다.
- acks=1: publisher는 leader에게 메시지를 전송하고 ACK를 기다린다. leader는 자기만 저장하면 ACK를 전송한다.
- acks=all: publisher는 leader에게 메시지를 전송하고 ACK를 기다린다. leader는 자기와 follower들이 모두 메시지를 저장한 다음 ACK를 보낸다. 즉, ISR이 모두 메시지를 디스크에 저장하면 leader가 ACK를 보낸다.
다시 ISR 이야기로 돌아가 보자. 결국 acks=all의 경우 producer에게는 견뎌야 하는 지연이 발생한다. 이 지연 시간을 최소화 하기 위해서는 follower들이 leader가 수신한 메시지를 최대한 빠르게 복제해야 한다. 결과적으로 뭔가 문제가 있어 replica.lag.time.max.ms시간 내에 복사를 제대로 못하는 follower는 publisher, kafka에 이르는 전체 시스템에 영향을 미치기에 짤린다.
그런데 무작정 짜르기만 한다면 언제까지 자를 것인가? min.insync.replicas 이 설정이 바로 최소의 ISR내 replica 요건이 된다. 만약 이런 저런 이유로 follower 들이 줄어들다가 이 수 보다 작아지는 경우, leader는 publisher의 메시지 송신 응답으로 "Not engough replicas"라는 에러 응답을 하게 된다.
Availability 보다 Consistency가 더 중요하다는 이야기다.
중요한 옵션이 하나 더 있는데 unclean.leader.election.enable 이다. 이 옵션은 ISR이 무너진 경우 ISR에서 쫒겨났지만 살아 있는 노드에게 leader 역할을 넘기는 것을 허용할 지 여부를 결정한다. 그러나 ISR에서 쫒겨난 경우 이미 leader와 메시지 동기화 수준이 많이 떨어져 있기 때문에 상당한 메시지 손실을 볼 수 있다.
애초에 replica를 위한 서버 구성을 하는 것이 필요하겠다. 모든 것은 돈이 문제라...
중요한 설정
- replica.lag.time.max.ms: follower가 이 시간 내에는 반드시 메시지 동기화를 수행해야 함
- unclean.leader.election.enable: ISR 내에 더 이상 leader 역할을 할 수 없을 때 ISR 밖에서 leader를 선임할 수 있는 지 여부를 설정 - consistency는 포기하더라고 availability가 중요한 경우...라도 정말 좋지 않은 상황인듯?
- min.insync.replicas: ISR내 최소 이 수의 leader+follower 수는 확보되어야 함을 의미
댓글 없음:
댓글 쓰기