Kafka 기본 구성
- message ⊂ partition ⊂ topic ⊂ cluster
topic
- 특정 message(데이터)들을 저장
- sequence of messages 를 data stream이라고 부름
- 어떤 message format이든지 저장할 수 있다.
- 데이터 검증이 없기때문에
- JSON, Avro, text, binary...
- name으로 topic을 식별
- Kafka Producer가 특정 topic에 데이터를 보내고 Kafka consumer는 특정 topic의 데이터를 읽는다.
- topic에 쿼리는 불가능
- 데이터를 일단 기록하면 임의로 해당 데이터를 삭제/변경 불가능
- 데이터의 수명을 정할 수 있으며 default 1week
partition
- topic은 여러 partition으로 나눠져 있으며 하나의 topic이 몇개의 partition으로 나눠질지 지정가능
- message는 특정 partition에 쌓이며 id 값을 가짐
- id는 0부터 시작하며 새로운 message가 들어오면 해당 partition에 직전에 들어온 id보다 1 큰 값을 가짐
- 이러한 id를
offset
이라고 부름
offset
은 재사용할 수 없다.
- 예를들어 이전의 메시지가 삭제되도 이전의 offset을 다시 사용하지 않는다.
- 그래서 메시지의 순서를 보장해줌
- 키가 없는 경우에 message는 임의의 partition에 할당된다.
Producer
- producer는 data를 message의 형태로 topic에게 보낸다.
- porducer는 data가 어떤 Kafka partition에 들어갈지 결정한다.
- Kafka broker에 고장이 발생하면, Producer는 자동으로 recovery함
- Producer는 message의 key를 보고 어떤 producer에게 보낼지 결정한다.
- 만약 key=null 이면 round robine 방식(0 → 1 → 2..)
- 만약 key!=null 이면 key에 hash함수를 적용하여 어떤 partition에 보낼지 결정한다. (default로 murmur2 algorithm을 씀)
Kafka Message 구조
- Key-binary : Key Object에 Serializer를 적용해 생성한 binary 값
- Value-binary : Value Object에 Serializer를 적용해 생성한 binary 값
- Serializer의 종류 : String(Json 포함), Int, Float, Avro, Protobuf ..
- Compression Type
- Headers(optional) : 추가적인 key-value 쌍
- Partition+Offset
- Timestamp
Consumer
- Consumer는 데이터를 topic으로 부터 읽어온다.
- Kafka 브로커가 데이터를 push하는 것이 아니라 pull model이다.
- Consumer는 어떤 Kafka 브로커에게서 데이터를 읽어야하는 안다.
- broker가 고장나게되면 consumer는 어떻게 recover해야하는지 안다.
- consumer는 partition의 데이터를 offset이 낮은 것부터 순차적으로 읽는다.
Deserializer
- Consumer는 message의 key,value를 원래의 object로 복원해야한다. 이러한 작업을
Deserializer
로 하게된다.
- Consumer는 key,value가 원래 어떤 형식이였는지 알아야한다.
- Deserializer 종류
- String(incl.JSON)
- Int, Float
- Avro
- Protobuf ...
- 한번 topic이 생성되면 Producer/Consumer의 Serializer/Deserializer type이 바뀌면 안된다.
- 바꾸기를 원한다면 새로운 topic을 생성해야함
- 왜냐하면 Cosumer가 예상하고 있는 데이터의 타입이 있는데 Producer가 Serializer type를 무작위로 사용하게 되면 원래의 object로 복원하지 못한다.
Cosumer group
- Kafka는 topic의 처리량을 높이기 위해 Consumer group을 사용한다.
- Consumer group은 하나 이상의 Consumer로 구성되어 있고 같은 consumer group에 속한 consumer들은 같은 topic을 subscribe한다.
- 같은 Consumer group에 속한 consumer들은 topic에 속한 partition을 exclusive하게 나눠가진다.
- 만약 Consumer group에 속한 consumer의 수보다 topic의 partition의 수가 작으면 partition을 할당받지 못한 consumer가 존재할 수 있으며 이러한 consumer는 standby consumer가 된다.
- 같은 topic에 대해서 여러 consumer group이 subscribe 할 수 있다.
Consumer Offsets
- consumer는 자신이 어디까지의 내용을 읽었는지 topic에
__consumer_offsets
이라는 파라미터에 기록한다.
- consumer가 죽어도 topic에 저장된
__consumer_offsets
을 통해 어디서 부터 읽어야하는지 알아낼 수 있다.
__consumer_offsets
을 기록하는 시점에 따라 3가지로 나뉜다.
- at least once
- message가 처리되고 commit
- default, 보통 선호됨
- message가 처리되던 도중에 cosumer가 죽으면 message의 일부가 반복적으로 처리될 수 있다. 반복적인 처리가 되더라도 시스템에 영향을 주지 않도록 해야한다. (idempotent(멱등성))
- at most once
- message를 받자마자 commit
- message가 처리되던 도중에 cosumer가 죽으면 message의 일부를 잃을 수 있다.
- exactly once
- Kafka => Kafka workflow : Transactional API(Kafka streams API)
- Kafka => external workflow : idenmpotent consumer
Broker
- Kafka cluster 는 Kafka broker(server)들로 구성됨
- 각 broker들은 ID(integer)로 식별됨
- 각 broker들은 특정 topic의 partition들을 담고있다.
- 아무 Kafka broker(bootstrap broker)에 연결해도 Kafka cluster 전체에 연결할 수 있다.
- 각각의 broker들은 Kafka cluster 내의 모든 broker, topic, partition에 대한 메타데이터를 가지고 있다.
- client가 broker에 연결 하게되면 해당 broker는 kafka cluster 전체의 broker 목록을 반환해준다.
- Kafka broker의 개수를 설정할 수 있고 3개가 보통 시작하기에 좋다. 큰 cluster는 100개 이상의 broker를 가질수도 있다.
Broker & Topic
- topic은 partition 단위로 Kafka cluster 내의 broker들에 분산되어 저장된다.
- replication factor를 통해 topic의 backup도 Kafka cluster 내의 broker들에 분산되어 저장할 수 있다.
- 보통 replication factor 2~3의 값을 사용한다.
- replication factor를 N이라고 할때 N-1개의 broker가 고장나도 데이터를 온전 보존할 수 있다.
- 각 partition에는 leader broker가 있으며 producer는 partition을 가지는 모든 broker에게 데이터를 보내느 것이 아니라 leader broker에게만 보낸다.
- partition을 저장하는 다른 broker는 leader broker가 받아온 데이터를 복제하여 저장한다.
- 각 partition은 하나의 leader broker와 다수의 ISR(in-sync replica)를 가진다.
- 예전에는 consumer 또한 leader broker를 통해서만 partitino을 읽을 수 있었는데 Kafka 2.4이후에는 consumer로 부터 가장 가까운 broker로 부터 partition을 읽을 수 있게 되었다.
Producer Acknowledgements (acks)
- producer는 데이터가 성공적으로 작성되는 기준을 acks로 설정할 수 있다.
- acks=0 : producer는 어떠한 Acknowledgement도 기다리지 않는다.(possible data loss)
- acks=1 : producer는 leader의 Acknowledgement를 받으면 데이터가 성공적으로 작성되었다고 간주한다.(limited data loss)
- acks=all : leader+replicas Acknowledgement를 모두 받아야 데이터가 성공적으로 작성되었다고 간주한다.(no data loss)
Zookeeper
- zookeeper는 Kafka broker를 감시하는 도구
- leader broker가 죽으면 새로운 leader 를 뽑는데 도움을 줌
- 변화가 생기면 Kafka에게 알림을 발송(eg. new topic, brocker dies, brocker comes up, delete topic...)
- Kafka 3.0 부터 zookeeper없이 동작 가능, zookeeper대신 Kraft(Kafka Raft)를 쓸 수 있음(KIP-500)
- Kafka 4.x 부터는 zookeeper 를 사용하지 않음
- zookeeper는 홀수개의 server를 가짐(1,3,5,7)
- zookeeper는 하나의 leader를 가지며 나머지는 follower(read)
- cosumer offset은 zookeeper가 아니라 topic에 저장함
- production 환경에서는 아직 zookeeper를 사용해야함 (< Kafka 4.0)
- 예전에는 Kafka client, CLI가 zookeeper에 연결했었는데 지금은 brocker를 연결 엔드포인트로 활용
- Kafka 2.2 부터 kafka-topic.sh CLI 커맨드도 zookeeper가 아닌 Kafka broker를 참조하도록 바뀜
- Zookeeper를 더이상 사용하지 않으려고 하는 것은 zookeeper 보다 Kafka가 더 안정적이기 때문이다.
Kafka KRaft
- 2020부터 Apache Kafka project는 zookeeper에 의존성을 없애기 시작함(KIP-500)
- zookeeper에는 Kafka cluster가 100,000개를 넘어가는 partition을 가지게 되면 scaling issue가 존재
- zookeeper를 제거함으로서 얻게되는것
- 100,000개 이상의 partition을 가질 수 있게됨
- 안정성이 높아지고 monitor,support,administer가 쉬워짐
- 전체 시스템에 대한 단일 보안 모델을 가짐(zookeeper 보안 모델 없어도 되)
- 단일 process를 실행으로 Kafka 시작 가능
- controller shutdow and recovery 시간이 빨라짐
- Kafka 3.0부터 Raft protocol(KRaft) 도입, 3.3.1 부터 production ready(KIP-833)
- Kafka 4.0 부터 KRaft만 지원 (zookeeper 더이상 지원안함)