Kafka ‐ Kafka 기본 개념 - dnwls16071/Backend_Study_TIL GitHub Wiki
📚 Kafka - Kafka 시스템 구조도
📚 Kafka
- 하나의 Topic은 여러 개의 Partition으로 나뉠 수 있다.
- Partition은 Kafka에서 데이터를 물리적으로 저장하는 단위
- Partition마다 독립적으로 메시지를 저장하고 처리할 수 있어서 병렬 처리가 가능하다.
📚 주요 파티셔닝 전략
- Round-Robin : 키가 없으면 기본적으로 순서대로 파티션에 분배(단순 로깅, 순서 무관)
- Key-based : key 값을 해시해서 특정 파티션으로 보낸다.(사용자별, 주문별 등 특정 기준으로 순서 보장)
📚 메시지 전송 특징
- At-most-once : 메시지 손실 가능성 있고 중복은 없다.
- At-least-once : 메시지 중복 가능성 있고 손실은 없다.
- Exactly-once : 중복도 없고 손실도 없다. 가장 이상적이지만 구현이 복잡하다.
📚 데이터를 쪼개야 하는 이유
- 단일 디스크의 I/O 한계 → 분산 저장 필요성 인지
- 같은 키는 항상 같은 파티션에 속한다.(순서 보장)
파티션 = hash(메시지 키) % 파티션 수
- hash : 해시 값을 생성한다.
📚 트러블 슈팅 시나리오
- Consumer가 Producer의 생산 속도를 따라가지 못해 Lag가 발생한다.
- Lag : Producer는 막 열심히 메시지를 보내고 있는데, Consumer가 처리 속도가 느려서 따라오지 못하는 상황
- 만약 데이터 유실 문제가 발생한다면 어떻게 해결을 해야할까?
- 파티션의 수를 늘린다.
- 데이터 유실 방지를 위한 프로듀서 설정을 추가한다.
📚 카프카 프로듀서 선택 옵션
acks
- 프로듀서가 전송한 데이터가 브로커들에 정상적으로 저장되었는가에 대한 전송 성공 여부를 확인하는 데에 사용하는 옵션이다.
- 0, 1, -1 중 하나로 설정할 수 있다. 설정값에 따라 데이터의 유실 가능성이 달라진다.
- 1(default) : 리더 파티션에 데이터가 저장되면 전송 성공으로 판단한다.
- 0 : 프로듀서가 전송한 즉시 브로커에 데이터 저장 여부와 상관없이 성공으로 판단한다.
- -1 : 토픽의 min.insync.replicas 개수에 해당하는 리더 파티션과 팔로워 파티션에 데이터가 저장되면 성공하는 것으로 판단한다.
buffer.memory
- 브로커로 전송할 데이터를 배치로 모으기 위해 설정할 버퍼 메모리양을 지정한다. 기본값은 32MB이다.
retries
- 프로듀서가 브로커로부터 에러를 받고 난 뒤 재전송을 시도하는 횟수를 지정한다.
- 재시도 횟수 기본값은 2,147,483,647이다.
batch.size
- 배치로 전송할 레코드 최대 용량을 지정한다.
- 너무 작게 설정하면 프로듀서가 브로커로 자주 보내기 때문에 네트워크 부담이 있고 너무 크게 설정하면 메모리를 많이 사용하게 된다.
- 기본값은 16,384이다.
linger.ms
- 배치를 전송하기 전까지 기다리는 최소 시간이다.
- 기본값은 0이다.
partitioner.class
- 레코드를 파티션에 전송할 때 적용하는 파티셔너 클래스로 지정한다.
- 기본 클래스는
org.apache.kafka.clients.producer.internals.DefaultPartitioner
이다.
enable.idempotence
- 멱등성(여러 번 호출한 것과 한 번 호출한 것이 같다는 의미, 수학적으로는
f(f(x)) = f(x)
이다.) - 기본값은 false이다.
transactional.id
- 프로듀서가 레코드를 전송할 때 레코드를 트랜잭션 단위로 묶을 것인지 설정한다.
- 프로듀서의 고유한 트랜잭션 아이디를 설정할 수 있다.
- 이 값을 설정해주면 트랜잭션 프로듀서로 동작한다.
📚 Zookeeper와 Kraft 모드 동작 차이점 정리
- Zookeeper 모드의 경우 민감한 정보를 Zookeeper에 저장할 때, 패스워드 인코더를 정의해 특정 알고리즘으로 인코딩할 수 있다.
- 허나 Kraft 모드의 경우 민감한 정보를 저장할 때 암호화되지 않은 채로 저장될 수 있다.
- Zookeeper가 더 좋고.. Kraft가 더 좋고.. 이런 개념이 아니라 "주어진 상황에 맞는" Kafka를 사용하면 된다.
📚 Kafka Topic(토픽)
- 하나의 토픽은 여러 파티션으로 구성되며 파티션은 0번부터 시작한다.
- 컨슈머가 토픽 내부의 파티션에서 데이터를 가져가더라도 데이터는 삭제되지 않는다.
- 카프카 파티션을 늘리는 것은 가능하지만 그에 따라 컨슈머 역시도 늘려야 한다.(무조건적으로 늘리는 것이 정답은 아니다.)
📚 Kafka Broker(브로커)
- 카프카 브로커는 카프카가 설치되어 있는 서버 단위를 말한다.
- 보통 3개 이상의 브로커로 구성하여 사용하는 것을 권장한다.
- 만약 partition이 1이고, replication이 2라면 원본 1개, 복제본 1개를 말하는 것이다.
- 다만 브로커 개수에 따라서 replication 개수가 제한된다.
- 여기서 원본 파티션은 리더 파티션이라고 부르고 나머지 복제 파티션은 팔로워 파티션이라고 부른다.
- 프로듀서가 토픽의 파티션에 데이터를 전달할 때 바로 리더 파티션에 전달된다.
- 프로듀서에는 ack라는 상세 옵션이 존재한다.
- 이 ack를 통해 고가용성을 유지할 수 있는데 이 옵션은 partition의 replication과 관련이 있다.
- 프로듀서가 전송한 데이터가 브로커들에 정상적으로 저장되었는가에 대한 전송 성공 여부를 확인하는 데에 사용하는 옵션이다.
- 0, 1, -1 중 하나로 설정할 수 있다. 설정값에 따라 데이터의 유실 가능성이 달라진다.
- 1(default) : 리더 파티션에 데이터가 저장되면 전송 성공으로 판단한다.
- 0 : 프로듀서가 전송한 즉시 브로커에 데이터 저장 여부와 상관없이 성공으로 판단한다.
- -1 : 토픽의 min.insync.replicas 개수에 해당하는 리더 파티션과 팔로워 파티션에 데이터가 저장되면 성공하는 것으로 판단한다.
❓적정 Replication 개수 : 많으면 많을수록 좋은 것이 아니라는 점
- Replication 개수가 많아지면 브로커의 리소스 사용량도 늘어나게 된다.
- 카프카에 들어오는 데이터의 양과 저장 시간을 잘 고려해 Replication 개수를 정하는 것이 좋다.
- 추천 Replication 개수 : 3
📚 파티셔너
- 파티셔너는 데이터를 토픽에 있는 파티션 중 어떤 파티션에 넣을 것인지를 결정하는 역할을 합니다.
- 레코드에 포함된 메시지 키 또는 메시지 값에 따라서 파티션의 위치가 결정된다.
- 프로듀서를 사용할 때 파티셔너를 따로 설정하지 않으면 UniformStickyPartitioner로 동작한다.
- 해당 파티셔너는 메시지 키가 있을 때와 없을 때가 다르게 동작한다.
- 메시지 키가 있는 경우는 다음과 같이 hash를 통해 해시 값을 찾아 어느 파티션으로 들어갈지를 결정한다.
- 메시지 키가 없는 경우는 파티션에 적절히 분배가 된다.
- 커스텀으로도 파티셔너를 구성할 수 있다.
📚 컨슈머 렉(Lag)
- 컨슈머가 아직 읽지 못한 메시지의 수
- 컨슈머의 처리 속도가 느리거나 프로듀서가 메시지를 너무 많이 전송할 경우 따라가지 못해서 Lag가 발생한다.