데이터가 들어가는 공간을 토픽이라고 한다.
kafka에서는 토픽을 여러개 생성할 수 있고 DB의 테이블이나 파일시스템의 폴더와 유사한 성질을 갖고 있기 때문에 그런 개념과 비슷하다고 생각하면 된다.
이러한 토픽들은 이름을 가질 수 있다.
ex) click_log, send_sms, location_log등등...무슨 데이터를 담는지 명확하게 명시하면 유지보수에 도움이 된다.
하나의 토픽은 여러 파티션으로 구성될 수 있으며 첫 번째 파티션 번호는 0번부터 시작하고 하나의 파티션은 큐와 같이 내부에 데이터가 파티션 끝에서부터 차곡차곡 쌓이게 된다.
데이터는 가장 오래된 0번부터 컨슈머가 가져가게 되는 것이다.
데이터를 가져간다고 해도 큐에서 삭제되지 않는 다면 그건 누가 가져가나?
새로운 컨슈머가 붙었을 시 가져갈 수 있다.
단, 컨슈머 그룹이 달라야 하고 auto.offset.reset이라는 옵션이 earliest로 설정되어 있어야 한다.
위의 그림과 같이 다른 컨슈머 그룹일 경우, 새로운 컨슈머가 추가로 붙을 수 있고 데이터를 Elastic Search, Hadoop에 각각 저장할 수도 있다.
그렇다면 위의 그림과 같은 상황에서 click_log 토픽에 파티션이 2개 있다고 할 경우 7번째 데이터를 넣어야 하는데 어떤 파티션으로 들어가야 할까?
프로듀서가 데이터를 보낼 때 키를 지정할 수 있다.
키를 따로 설정하지 않았다고 하면 파티션 1번으로 들어가게 되고 Round robin으로 다음에 들어오는 데이터들은 차례대로 아래 사진처럼 파티션 0, 1번에 저장된다.
그리고 파티션을 하나 더 만들어준다고 할 때, 유의사항이 있다.
파티션은 늘리는 것만 가능하고 줄이는 것은 불가능하다!
파티션을 늘리는 이유?
컨슈머의 개수를 늘려서 데이터 처리를 분산시킬 수 있기 때문이다.
데이터가 늘어나면 파티션의 데이터(record)는 그럼 언제 삭제될까?
삭제되는 타이밍은 옵션에 따라 다르다.
replication(복제)은 kafka 아키텍처의 핵심
클러스터에서 서버에 장애가 생겼을 때, 가용성을 보장하는 가장 좋은 방법이 복제이기 때문이다.
브로커는 카프카가 설치되어 있는 서버 단위를 말한다
보통 3개 이상의 브로커로 구성하여 사용하는 것을 권장
만약 파티션이 1개, replication이 1인 토픽이 존재하고 브로커가 3대라면?
브로커 3대 중 1대에 해당 토픽 정보가 저장된다.
만약 replication이 2라고 하면?
원본 1개 다른 브로커의 파티션에 복제본1개가 생기는 것이다.
마찬가지로 replication이 3이면 원본 1개와 각각 다른 브로커의 파티션에 복제본 2개가 생기게 된다. (아래 사진 참고)
원본 파티션은 leader, 복제본은 follower 파티션이라고 부르고 이 구조를 일컬어 ISR이라고 부른다.
replication이 브로커의 개수를 넘을 수는 없다.
고가용성을 위해 replication이 된다고 했다, 그렇다면 leader 파티션이 다운됐다고 하면?
복제본은 그대로 살아있게 되고 leader 파티션 역할을 승계한다.
프로듀서가 토픽의 파티션에 데이터를 전달한다고 했다.
그때 전달받는 주체가 바로 leader 파티션.
프로듀서에는 ack라는 옵션이 있다.
ack를 통해 고가용성을 유지할 수 있는데, 이는 파티션의 replication과 관련이 있따.
ack는 0,1,all 옵션 중 하나를 골라서 사용할 수 있다
0
leader 파티션에 데이터를 전송하고 응답값은 받지 않는다.
이 때문에 leader 파티션에 데이터가 잘 전송되었는지 알 수가 없다.
이는 속도는 매우 빠르지만 데이터 유실 가능성이 있다.
1
응답값을 받는다. 하지만 여기서도 알 수 없는 것이 있다.
바로 나머지 파티션에 복제 되었는지 여부이다.
만약 leader 파티션이 데이터를 받는 즉시 브로커가 장애가 난다면?
이전에 0 옵션처럼 데이터 유실 가능성이 있다.
ALL
leader 파티션에 데이터를 보내고 leader는 물론 follower 파티션에 대한 정보도 응답 받을 수 있기 때문에 데이터 유실은 없다고 보면 된다.
하지만 0,1에 비해 확인하는 부분이 많기 때문에 속도가 현저히 낮다..
replication의 개수가 많으면 좋은걸까?
이는 브로커의 리소스 사용량도 늘어나게 된다. 따라서 kafka에 들어오는 데이터 양과 저장시간을 잘 생각해서 replication을 저하는 것이 좋다.
3개 이상의 브로커를 사용할 때, replication은 3으로 설정하는 것이 권장된다.
프로듀서가 데이터를 보내면 무조건 파티셔너를 통해서 브로커로 데이터가 전송된다.
파티셔너는 데이터를 토픽에 어떤 파티션에 넣을지 결정하는 역할을 한다.
레코드에 포함된 메시지 키 또는 메시지 값에 따라서 파티션의 위치가 결정되게 된다.
프로듀서를 사용할 때 파티셔너를 설정하지 않는다면 UniformStickyPartitioner로 설정이 된다.
이 파티셔너는 메시지 키가 있을 때, 없을 때 다르게 동작한다.
메시지 키가 있는 경우
토픽에 파티션이 2개 있는 경우
파티셔너의 해쉬로직에 의해서 아래 사진의 예시처럼 서울은 파티션 0, 부산은 파티션 1, 울산은 파티션 0번으로 들어가게 할 수 있다.
동일한 메시지 키를 가진 레코드는 동일한 해쉬값을 만들어내기 때문에 항상 동일한 파티션에 들어가는 것을 보장한다.
ex) 서울에 온도를 기록하는 레코드를 파티션에 집어넣는다?
메시지 키에 서울이라는 string값을 넣고 레코드를 지속적으로 보낸다면 동일한 파티션에 데이터가 순서대로 들어간다.
컨슈머는 순서를 지켜서 데이터를 처리할 수 있게 되는 것이다.
메시지 키가 없는 경우
round robin으로 들어가게 된다.
UniformStickyPartitioner는 프로듀서에서 배치로 모을 수 있는 최대한의 레코드들을 모아서 파티션으로 데이터를 보내게 된다.
배치단위로 데이터를 보낼 때 round robin방식으로 데이터를 넣게 된다.
그냥 메시지 키가 없는 레코드들은 파티션에 적절히 분배된다고 생각하면 된다.
커스텀 파티셔너
커스텀 파티셔너를 만들 수도 있다.
Partitioner Interface를 통해 메시지 키, 값, 또는 토픽이름에 따라서 어느 파티션에 데이터를 보낼 것인지도 설정할 수 있다.
커스텀 파티셔너를 사용하는 경우?
ex) VIP고객을 위해서 데이터 처리를 빠르게 하는 로직을 개발하는 경우
파티셔너를 통해 처리량을 늘릴 수도 있다.
10개의 파티션이 있다고 할 때, 커스텀 파티셔너를 만들어서 8개 파티션에는 vip고객의 데이터, 나머지 2개엔 일반 고객의 데이터를 넣는 것과 같은 파티셔너를 만들 수 있다.
Kafka lag은 kafka를 운영함에 있어서 아주 중요한 모니터링 지표 중 하나
파티션에 데이터를 하나하나씩 넣게 되면 각 데이터에는 오프셋이라고 하는 숫자가 붙게 된다.
파티션이 1개인 토픽에 프로듀서가 데이터를 넣을 경우
이와 같은 구조일 것이다.
만약 프로듀서가 데이터를 넣어주는 속도가 컨슈머가 가져가는 속도보다 빠르다면?
프로듀서가 넣은 데이터의 오프셋, 컨슈머가 가져간 데이터의 오프셋 간의 차이가 발생한다. 이것이 바로 컨슈머 lag
lag은 적을수도 있고 많을 수도 있다.
lag의 숫자를 통해 현재 해당 토픽에 대한 파이프라인으로 연계되어 있는 프로듀서와 컨슈머의 상태에 대해 예측이 가능하다.
주로 컨슈머의 상태를 볼 때 사용
프로듀서가 넣은 데이터의 오프셋 - 컨슈머가 가져가는 오프셋
컨슈머 lag은 위의 식을 기반으로 한다.
때문에 토픽에 여러 파티션이 존재할 경우 lag은 여러개가 존재할 수 있다.
이렇게 한 개의 토픽과 한 개의 컨슈머 그룹에 대한 lag이 여러개 존재할 수 있을 때, 그중 높은 숫자의 lag을 records-lag-max라고 부른다.
lag을 실시간으로 모니터링하고 싶다면 Grafana와 같은 모니터링 툴을 통해 모니터링할 수 있다.
컨슈머 단위에서 lag을 모니터링하는 것은 아주 위험하고 운영요소가 많이 들어간다. 컨슈머 로직단에서 lag을 수집하는 것은 컨슈머 상태에 디펜던시가 걸리기 때문.
컨슈머가 비정상적으로 종료되게 되면 컨슈머는 lag정보를 보낼 수 없기 때문에 lag을 측정할 수 없게 된다.
추가적으로 컨슈머가 개발될때마다 해당 컨슈머에 lag 정보를 특정 저장소에 저장할 수 있도록 개발해야 한다. 컨슈머 lag을 수집할 수 없는 컨슈머면 lag을 모니터링할 수 없으므로 운영이 매우 까다로워지게 되기 때문.
때문에 링크드인에서 컨슈머 lag 모니터링을 할 수 있는 독립적인 애플리케이션을 개발했는데 이것이 바로 Burrow. (오픈소스로 Golang으로 작성되어 있다.)
Burrow
멀티 kafka 클러스터 지원
기업에선 대부분이 2개 이상의 kafka 클러스터를 사용할 것이다.
Sliding Window를 통한 컨슈머의 status 확인
Window를 통해 컨슈머의 status를 'ERROR', 'WARNING', 'OK'로 표현할 수 있다.
데이터량이 일시적으로 많아지면서 컨슈머 오프셋이 증가되고 있으면 WARNING
데이터량이 많아지고 잇는데 컨슈머가 데이터를 가져가지 않으면 ERROR
HTTP API 제공
http api를 통해 위와 같은 것들을 조회할 수 있다.
메시징 플랫폼이라고 부르는 것들은 두 개의 종류로 나뉘어진다.
메시지 브로커와 이벤트 브로커이다.
메시지 브로커는 이벤트 브로커로 역할을 할 수 없지만, 이벤트 브로커는 메시지 브로커로 역할을 할 수 있다.
메시지 브로커
메시지 브로커는 많은 기업들의 대규모 메시지 기반 미들웨어 아키텍처에서 사용되어 왔다.
미들웨어라는 것은 서비스하는 애플리케이션들을 보다 효율적으로 아키텍처들을 연결하는 요소들로 작동하는 소프트웨어
(메시징 플랫폼, 인증 플랫폼, DB -> 미들웨어)
메시지 브로커에 있는 큐에 데이터를 보내고 받는 프로듀서와 컨슈머를 통해 메시지를 통신하고 네트워크를 맺는 용도로 사용해왔다.
메시지 브로커의 특징
메시지를 받아서 적절히 처리하고 나면 즉시 삭제 되는 구조.
이벤트 브로커
메시지 브로커의 특징과 조금 다른 구조
이벤트 브로커의 특징
이벤트 또는 메시지라고도 불리는 이 레코드(장부)를 하나만 보관하고 인덱스를 통해 개별 액세스를 관리한다.
업무상 필요한 시간동안 이벤트를 보존할 수 있다.
메시지 브로커는 데이터를 보내고 처리하고 삭제한다
이벤트 브로커는 왜 삭제하지 않을까?
'이벤트' 라는 단어에 단서가 잇다.
서비스에서 나오는 이벤트를 마치 DB에 저장하듯이 이벤트 브로커의 큐에 저장한다.
이런 저장방식의 이점
메시지 브로커 : redis queue나 rabbitMQ
이벤트 브로커 : kafka, AWS Kinesis