나의 개발 일상 기록
[Kafka] Kafka란? 본문
Kafka

위키백과에서 Kafak는 실시간 데이터 피드를 관리하기 위해 통일된, 높은 처리량, 낮은 지연시간을 지닌 플랫폼을 제공하는 것이 목표이며 분산 트랜잭션 로그로 구성된 상당히 확장 가능한 pub/sub 메시지 큐로 정의한다고 나와있습니다.
데이터 전송하는 Source 애플리케이션과 데이터를 받는 Target 애플리케이션이 있었습니다. Source & Target 애플리케이션들이 많아지면서 데이터를 전송하는 라인이 매우 복잡해졌습니다. 데이터 전송 라인이 많아지면 배포와 장애에 대응하기가 힘들어지니다. 그래서 Apache Kafka는 이러한 복잡함을 해결하기 위해 개발되었습니다.

Topic은 일종을 큐 라고 생각을 하시면 됩니다. Producer의 역할은 Topic에 데이터를 삽입을 하며 Consumer의 역할은 Topic에 데이터를 조회 하는 역할을 합니다. Kafka는 아주 유연한 큐 역할을 한다고 보시면 됩니다. 이런 데이터 흐름에 있어서 Kafka는 고가용성으로서 서버가 이슈가 생기거나 갑작스럽게 랙(전원이) 내려간다던가 하는 상황에서도 데이터를 손실없이 복구할 수 있습니다. 또한, Kafka는 낮은 지연과 높은 처리량을 통해서 아주 효과적으로 데이터를 아주 많이 처리할 수 있습니다.
1. Kafka Topic
Kafka에는 다양한 데이터가 들어갈 수 있는데 데이터가 들어가는 공간을 Topic이라고 합니다. Kafka에서는 Topic을 여러개 생성할 수 있습니다. Topic은 데이터베이스의 테이블이나 파일시스템의 폴더와 유사한 성질을 가지고 있습니다. 이 Topic에 Producer가 데이터를 넣게되고 Consumer는 데이터를 가져가게 됩니다. Topic은 이름을 가질수 있는데 목적에 따라 클릭로그, send sms, location log 등과 같이 무슨 데이터를 담는지 명확하기 명시하면 추후 유지보수 시 편리하게 관리 할 수 있습니다.
- Partition이 하나인 경우

하나의 Topic은 여러개의 Partition으로 구성될 수 있으며 첫번째 Partition 번호는 0번부터 시작합니다. 하나의 Partition은 큐와같이 내부에 데이터가 Partition 끝에서부터 차곡차곡 쌓이게 됩니다. 클릭로그 Topic에 Kafka Consumer가 붙게되면 데이터를 가장 오래된 순서대로 가져가게 됩니다. 더이상 데이터가 들어오지 않으면 Consumer는 또 다른 데이터가 들어올때까지 기다립니다. Consumer가 Topic 내부의 Partition에서 데이터를 가져가더라도 데이터는 삭제되지 않고 Partition에 그대로 남게됩니다.
만약 Partition #0번의 남은 데이터를 재사용을 하기위해서는 새로운 Consumer가 붙었을때 다시 0번 부터 사용할 수 있습니다. 이를 위해서 몇가지 제약 조건이 있습니다. 첫번째로 Consumer그룹이 달라야하고 auto.offset.reset=earliest 이여야 합니다. 이처럼 사용할 경우 동일 데이터에 대해서 두번 처리할 수 있는데 이는 Kafka를 사용하는 아주 중요한 이유이기도 합니다.
- Partition이 두개 이상인 경우

Partition이 2개 이상인 경우 새로운 데이터가 유입 되었을 때 어떤 Partition으로 보내는 경우는 Producer가 키를 지정 할 수 있습니다. 키가 null 즉, 키를 지정하지 않고 기본 파티셔너 사용한다면 round-robin으로 Partition이 지정됩니다. 반대로 키가 있고 기본 파티셔너를 사용할 경우에는 키의 해시값을 구하고 특정 Partition에 항상 할당되게 됩니다.
Partition을 늘리는 것에는 주의해야 할 점이 있습니다. Partition은 늘리는 것은 가능하지만 다시 줄일 수는 없기 때문입니다. Partition을 늘리는 이유는 Partition을 늘리면 Consumer의 개수를 늘려서 데이터 처리를 분산시킬 수 있습니다. 지속적으로 Partition의 데이터가 늘어나면 옵션에 따라 일정 기간 또는 용량 동안 데이터를 저장할 수 있게 되고 적절하게 데이터가 삭제될 수 있도록 설정할 수 있습니다.
- log.retention.ms : 최대 record 보존 시간
- log.retention.byte : 최대 record 보존 크기
2. Kafka broker, replication, ISR
2.1 Kafka broker
Kafka borker는 Kafka가 설치되어 있는 서버 단위를 말합니다. 보통 3개 이상의 borker로 구성하여 사용하는 것을 권장합니다. 만약 Partition이 1개이고 replication이 1인 topic이 존재하고 borker가 3대라면 borker 3대중 1대에 해당 topic의 정보(데이터)가 저장됩니다.
2.2 Kafka replication
replication은 Partition의 복제를 뜻합니다. 만약 replication이 1이라면 Partition은 1개만 존재한다는 것이고 replication이 2라면 Partition은 원본 1개와 복제본 1개로 총 2개가 존재합니다. replication이 3이라면 Partition은 원본 1개와 복제본 2개로 총 3개가 존재하게 됩니다. 다만 borker 개수에 따라서 replication개수가 제한됩니다. borker개수가 3이면 replication은 4가 될수 없습니다. 원본 1개 Partition은 Leader Partition이라고 부릅니다. 그리고 나머지 복제본 Partition은 Follower Partition이라고 부릅니다.
- replication을 사용하는 이유
replication은 Partition의 고가용성을 위해 사용됩니다. 만약 borker가 3개인 Kafka에서 replication이 1이고 Partition이 1인 Topic이 존재한다고 가정한다면 borker가 어떠한 이유로 사용불가하게 된다면 더이상 해당 Partition은 복구할 수 없습니다. 만약 replication이 2라면 borker 1개가 죽더라도 Follower Partition이 존재하므로 복제본은 복구가 가능합니다. 나머지 1개가 남은 Follower Partition이 Leader Partition역할을 승계하게 되는 것입니다.
* ack
Producer가 Topic의 Partition에 데이터를 전달할때 전달받는 주체가 Leader Partition입니다. Producer에는 ack라는 상세 옵션이 있습니다. ack를 통해 고가용성을 유지할 수 있는데 이 옵션은 Partition의 replication과 관련이 있습니다. ack는 0, 1, all 옵션 3개중 1개를 골라서 설정할 수 있습니다.
- ack Option 0
- Producer는 Leader Partition에 데이터를 전송하고 응답값을 받지않습니다. 그렇기에 Leader Partition에 데이터가 정상적으로 전송됏는지 그리고 나머지 Partition에 정상적으로 복제되엇는지 알 수 없고 보잘할 수 없기에 속도는 빠르지만 데이터 유실 가능성이 있습니다.
- ack Option 1
- Leader Partition에 데이터를 전송하고 Leader Partition이 데이터를 정상적으로 받앗는지 응답값을 받습니다. 다만 나머지 Partition에 복제되엇는지는 알 수 없습니다. 만약 Leader Partition이 데이터를 받는 즉시 broker가 장애가 발생한다면 나머지 Partition에 데이터가 전송되지 못한 상태이므로 데이터의 유실 가능성이 있습니다.
- ack Option all
- 1옵션에 추가로 Follower Partition에 복제가 잘 이루어졌는지 응답값을 받습니다. Leader Partition에 데이터를 보낸 후 나머지 Follower Partition에도 데이터가 저장되는 것을 확인하는 절차를 거칩니다. 때문에 속도가 현저히 느리다는 단점이 있습니다.
replication개수가 많아지면 그만큼 broker의 리소스 사용량도 늘어나게 됩니다. 따라서 Kafka에 들어오는 데이터량과 retention data 즉, 저장시간을 잘 생각하여 replication 개수를 정하는 것이 좋습니다. 3개 이상의 브로커를 사용할때
replication은 3으로 설정하는 것을 권장합니다.
2.3 Kafka ISR
위의 2.2에서 설명한 Leader, Follower Partition을 합쳐서 ISR 즉, In Sync Replica라고 볼 수 있습니다.
3. Kafka Partitioner
Partitioner는 Kafka Producer의 중요한 개념 중 하나입니다. Producer가 데이터를 보내면 무조건 Partitioner를 통해서 broker로 데이터가 전송됩니다. Partitioner는 데이터를 Topic에 어떤 Partitioner에 넣을지 결정하는 역할을 합니다.
레코드에 포함된 메시지 키 또는 메시지 값에 따라서 Partitioner의 위치가 결정되게 됩니다. Producer를 사용하실 때 Partitioner를 따로 설정하지 않으면 UniformStickyPartitioner로 설정이 됩니다. 이 Partitioner는 메시지 키가 있을 때와 없을 때 다르게 동작하게 됩니다.
- 메시지 키가 있는 경우
메시지 키를 가진 레코드는 Partitioner에 의해서 특정한 해쉬값이 생성됩니다. 이 해쉬값을 기준으로 어느 Partitioner으로 들어갈지 정해지게 됩니다. 동일한 메시지 키를 가진 레코드는 동일한 해쉬값을 만들기 때문에 항상 동일한 Partition에 들어가는 것을 보장합니다. 예를 들어 서울의 온도를 기록하는 레코드를 Partition에 집어넣는다고 가정해볼 수 있습니다. 메세지 키에 "서울"이라는 String 값을 넣고 레코드를 지속적으로 보낸다면 항상 동일한 Partition에 데이터가 순서대로 들어가기 때문에 Consumer는 서울이라는 레코드를 순서를 지켜서 데이터를 처리할 수 있게 되는 것입니다. Partition 한개 내부에서는 큐처럼 동작하기 때문에 순서를 지킬 수 있는것입니다.
- 메시지 키가 없는 경우
메시지 키가 없는 레코드는 라운드 로빈으로 Partition에 들어가게 됩니다. UniformStickyPartitioner는 Producer에서 배치로 모을 수 있는 최대한의 레코드들을 모아서 Partition으로 데이터를 보내게 됩니다. 이렇게 배치단위로 데이터를 보낼 때 Partition에 round-robin 방식으로 들어가면서 데이터를 넣게 됩니다. 쉽게 말해서 메시지 키가 없는 레코드들은 Partition에 적절히 분배된다고 생각하시면 될 것 같습니다.
4. Kafka Consumer Lag
Kafka lag은 Kafka를 운영함에 있어서 중요한 모니터링 지표 중 하나입니다.
Kafka Producer는 Topic의 Partition에 데이터를 차곡차곡 넣게됩니다. 이 Partition에 데이터가 하나 하나씩 들어가게되면 각 데이터는 오프셋이라고하는 숫자가 붙게됩니다. 만약 Partition이 1개가 존재한다면 Partition이 1개인 Topic에 Producer가 데이터를 넣을 경우 0부터 차례대로 숫자가 매겨지게 됩니다. Producer는 계속해서 데이터를 넣게되고 Consumer는 계속해서 데이터를 가져가게 됩니다. 만약 Producer가 데이터를 넣어주는 속도가 Consumer가 가져가는 속도보다 빠르게 되면 Producer가 넣은 데이터의 오프셋, Consumer가 가져간 데이터의 오프셋 이 두개의 오프셋 간에 차이가 발생합니다. 이게 바로 Consumer Lag입니다. Lag은 적을수도 있고 많을 수도 있습니다. 이 Lag의 숫자를 통해 현재 해당 Topic에 대해 파이프라인으로 연계되어 있는 Producer와 Consumer의 상태에 대해 유추가 가능합니다. Consumer Lag은 주로 Consumer의 상태에 대해 볼때 사용합니다.
Lag은 각 Partition의 오프셋기준으로 Producer가 넣은 데이터의 오프셋과 Consumer가 가져가는 데이터의 오프셋의 차이를 기반으로 합니다. 그렇기 때문에 Topic에 여러 Partition이 존재할 경우 Lag은 여러개가 존재할 수 잇습니다. 만약 Consumer 그룹이 1개이고 Partition이 2개인 Topic에서 데이터를 가져간다면 Lag은 2개가 측정될 수 있습니다. 이렇게 한개의 Topic과 Consumer 그룹에 대해 Lag이 여러개 존재할 수 있을때 그 중 높은 숫자의 Lag를 records-lag-max라고 부릅니다.
'Spring' 카테고리의 다른 글
| [FCM] FireBase를 활용한 Web Push Alarm (0) | 2022.02.26 |
|---|---|
| [Spring] TDD(Test-Driven-Development) (0) | 2022.02.22 |
| [Kafka] Kafka Producer&Consumer Application (0) | 2021.10.05 |
| [Spring] 스프링 AOP(Aspect Oriented Programming) (0) | 2021.05.06 |
| [Error] java.lang.NoClassDefFoundError : sun.awt.x11GraphicsEnvironment (0) | 2021.04.19 |