- kafka broker와 zookeeper가 존재하고 최대 3대 이상의 서버로 클러스터를 구성
- zookeeper는 broker와 같은 서버에 구축해도 되고 별도의 서버에 구축해도 됨
- broker 중 한 대는 controller/coordinator 역할을 담당함
- 데이터는 파일시스템에 저장
- pull 방식
- consumer가 broker로부터 당겨오는 방식
- 실체화된 event stream
- 연관된 이벤트를 함께 묶어준 단위
- DB에 비유하자면 테이블에, 파일시스템에 비유하자면 파일에 해당함
- topic을 더 잘게 쪼갠 단위
- 여러 서버에 분산되어 저장됨(복제)
- 장애 시 partition 단위로 failover가 수행됨
- 병렬 처리됨
- 메시지의 생산 주체
- producer는 지정된 키를 해시하여 대상 partition을 결정하고 거기에 메시지를 저장함
- 메시지의 소비 주체
- consumer는 자신에게 할당된 partition에서 메시지를 읽어 옴
- 객체 형태의 메시지를 전달하기 위해 Kafka 내부에서 직렬화해둔 형태
- 각 파티션에서 메시지를 저장할 때마다 부여되는 유니크한 순차 ID
- 파티션마다 고유한 offset을 가지지만
producer마다 달라지진 않음
- consumer 입장에서도 offset을 활용할 여지가 있음
- 위에서 언급된 offset과 다른 개념이지만 offset값을 이용함
- "offset"이라고 하면 원칙적으로는 producer의 offset이지만 애플리케이션 입장에서는 consumer의 (last committed) offset에 관심의 초점이 맞춰져 있음
consumer마다 파티션별로 다른 offset을 가짐
- 다른 consumer가 block되더라도 나머지 consumer에게는 영향이 없음
- pull 방식이므로 consumer가 offset을 커서처럼 사용함
- 어디까지 소비되었는지를 추적하는 용도
- consumer는 메시지를 읽고 다음 offset을 가리키는 커서를 전진시킴 (Kafka는 아무 것도 하지 않음)
- 같은 topic을 바라보는 consumer 그룹
- partition 내부의 레코드를 파일로 보관할 때는 단일 파일에 저장하는 것이 아니라 각각의 log segment 단위로 나눠서 저장함
- log segment는 크기 제한이나 시간 제한에 따라 분할됨
- 사용 중에는 segment 파일을 열어두고 있다가
- 일정 크기나 시간을 초과하면 파일을 닫고
- 다시 일정 크기나 시간을 초과하면 압축하거나 삭제함
- leader partition에 저장된 레코드를 follower partition들에 복제하여 분산 저장하는 메커니즘
- 레코드 복제 과정
- 0번 partition의 소유자인 producer가 0번 partition에 저장. 1번과 2번에 복제됨
- 1번 partition의 소유자인 producer가 1번 partition에 저장. 0번과 2번에 복제됨
- shared message queue 모델에서는 queue 내부의 데이터를 모든 producer와 consumer들이 서로
공유
함
- 큐에 저장된 메시지는 한 번만 읽을 수 있고
단 하나의 consumer만
읽을 수 있음
- 성공적으로 읽히면 메시지를 제거함
- consumer가 많이 연결되는 경우에는 consumer 중 누가 처리해도 상관없는 응용에서만 사용이 가능함
- pub-sub system 모델에서는 여러 publisher가 발행하고
여러 subscriber가
구독할 수 있는 방식
- 파티션이 많아지면 subscriber가 여러 서버에 접근해야 하므로 클러스터가 커지면 부담이 커짐
- 그림에서 S1, S2, S3가 topic 1의 각각의 파티션 0, 1, 2에 연결을 맺고 있음
- subscriber간 sync를 맞추는 게 어려움. 파티션 내에서는 메시지 순서가 보장되지만 토픽 차원에서는 메시지 순서가 보장되지 않음
- Kafka는 기본적으로 pub-sub 시스템이지만 custom group 방식을 더했음
- broker들에 의한 메시지 유지 (consumer가 읽어가도 당장 삭제되지는 않음)
- consumer가 consumer group에 참여하고 topic을 구독할 때 단 하나의 consumer(partition owner)만 실제적으로 그 topic으로부터 메시지를 소비하게 되고 메시지는 broker에 의해 유지됨
- 여러 consumer group들은 동일한 topic 집합에서 읽을 수 있고 다른 시간에 다른 논리적 응용 도메인을 처리할 수 있음
- 그림에서 topic B의 partition 0은 두 group A와 B에 의해 각각 사용됨
- consumer group에 속한 consumer들은 동일한 group id를 공유함
- 그룹 내의 consumer들은 파티션을 공평하게 나눠서 사용함
- 그림에서 Group A의 각 consumer들이 topic A의 파티션 1,2,3을 하나씩 나눠서 맡고 있음(중복은 없음)이 이에 해당함
- 모든 consumer가 동일한 그룹에 속해있으면 shared message queue처럼 동작함
- 여러 consumer group이 존재하면 pub-sub model처럼 동작함
- partition 수와 consumer 수는 동일한 게 좋음
- consumer가 더 많아지면? 유휴 상태로 대기하는 consumer가 존재하게 됨
- partition이 더 많아지면? 일부 consumer가 여러 partition에서 읽어오게 됨. consumer가 처리할 수 있는 성능 이상으로 메시지가 적재되면 종단 간 대기 시간이 길어질 수 있음
- 권장값 계산
- p: producer를 위한 단일 파티션에서 얻을 수 있는 처리속도
- c: consumer를 위한 단일 파티션에서 얻을 수 있는 처리속도
- t: 목표 처리속도
- # of partitions = max(t/p, t/c)
- partition이 많아진다는 건 병렬성과 가용성이 높아진다는 의미임
- 그러나 partition 수가 커질수록 브로커에서 파일 디스크립터나 메모리 등의 리소스 사용이 증가하고 클러스터 내에서 복제가 많이 늘어나기 때문에 종단 간 대기시간이 길어질 수 있음
- Confluent의 권장 값: 브로커당 파티션은 2~4천개 이하로 제한, 클러스터의 총 파티션은 수만 개 이하로 제한
- 주의사항: 메시지 순서를 보장받기 위해 키를 부여하기도 하는데, 키를 가진 메시지는 해시 기반으로 파티션에 매핑되므로 파티션 수가 변경되면 영향을 받게 됨. 이를 회피하려면 비트를 잘게 쪼개서 파티션의 수를 늘려놓는 방법이 있음
- 다양한 이유로 consumer group의 규모에 변화가 생길 수 있음
- broker나 consumer의 장애
- topic 또는 partition 추가
- consumer를 추가하거나 삭제하는 것도 안전함
broker가 consumer로부터 등록 요청을 받으면 응답으로 consumer가 소유해야 하는 partition 목록을 반환함
- consumer가 heartbeat를 일정 시간 내에 coordinator 역할을 하는 broker에게 보내지 못하면(장애), coordinator는 해당 consumer를 죽은 것으로 간주하고 rebalancing을 진행함
같은 그룹의 다른 consumer들이 잠시 소비를 멈추고 죽은 consumer가 소유하던 partition까지 포함해서 partition들을 재분배받는다.
- 다른 그룹은 영향받지 않음
- rebalancing 과정에 대한 자세한 설명은 다음 자료를 참고할 것