diff --git a/marshmallowing/Week02/chapter02.md b/marshmallowing/Week02/chapter02.md new file mode 100644 index 0000000..1f46735 --- /dev/null +++ b/marshmallowing/Week02/chapter02.md @@ -0,0 +1,342 @@ +# 4장: 분산 메시지 큐 +> 현대적 소프트웨어 아키텍처를 따르는 시스템은 잘 정의된 인터페이스를 경계로 나뉜 작고 **독립적인 블록**들로 구성된다. **메시지 큐는 이 블록 사이의 통신과 조율을 담당한다.** +> + +### 메시지 큐를 사용할 시 장점 + +- 결합도 완화: 컴포넌트 사이의 강한 결합이 사라지므로 각각을 독립적으로 갱신 가능 +- 규모 확장성 개선: 메시지 큐에 데이터를 생산하는 생산자와 큐에서 메시지를 소비하는 소비자 시스템 규모를 트래픽 규모에 맞게 독립적으로 늘릴 수 있다 +- 가용성 개선: 시스템의 특정 컴포넌트에 장애가 발생해도 다른 컴포넌트는 큐와 계속 상호작용을 이어갈 수 있다 +- 성능 개선: 비동기 통신이 쉽게 가능하다 (생산자와 소비자가 서로 기다릴 필요 없다) + +### 기능 요구사항 + +- 생산자는 메시지 큐에 메시지를 보낼 수 있어야 한다 +- 소비자는 메시지 큐를 통해 메시지를 수신할 수 있어야 한다 +- 메시지는 반복적으로 수신할 수 있어야 하고, 단 한번만 수신하도록 설정될 수도 있어야 한다 +- 오래된 이력 데이터는 삭제될 수 있다 +- 메시지 크기는 킬로바이트 수준 +- 메시지가 생산된 순서대로 소비자에게 전달할 수 있어야 한다 +- 메시지 전달 방식은 최소 한 번, 최대 한 번, 정확히 한 번 가운데 설정할 수 있어야 한다 + +### 비기능 요구사항 + +- 높은 대역폭과 낮은 전송 지연 가운데 하나를 설정으로 선택 가능하게 하는 기능 +- 규모확장성 +- 지속성과 내구성 + - 데이터는 디스크에 지속적으로 보관되어야 하며 여러 노드에 복제되어야 한다 +- **전통적인 메시지 큐와 다른 점 / 이벤트 스트리밍 플랫폼** + - 전통적인 메시지 큐(ex. RabbitMQ)는 메시지 보관 문제를 중요하게 다루지 않는다 + - 메시지가 소비자에게 전달되기 충분한 기간 동안만 메모리에 보관 + - 메시지 전달 순서를 보존하지 않음 + - 처리 용량을 넘어선 메시지는 디스크에 보관하긴 하는데 이는 이벤트 스트리밍 플랫폼이 담당하는 용량보다 아주 낮음 + + | **구분** | **메시지 큐 (MQ)** | **이벤트 스트리밍 (Kafka 등)** | + | --- | --- | --- | + | **데이터 보관** | 처리 완료 후 **삭제** | 일정 기간 동안 **저장** (재생 가능) | + | **데이터 처리** | 개별 메시지 단위 처리 | 데이터의 흐름(Stream) 단위 처리 | + | **소비자 수** | 보통 1개의 메시지는 1명의 소비자만 처리 | 1개의 이벤트를 여러 소비자가 동시 구독 가능 | + | **순서 보장** | 큐 내부 순서는 보장되나 병렬 처리 시 복잡함 | 파티션 단위로 엄격한 순서 보장 | + | **확장성** | 상대적으로 제한적 | 대규모 분산 처리에 최적화됨 | + - 메시지 큐: 생산자가 보낸 메시지를 소비자가 **안전하게 수신하고 처리**하는 것을 목적 + - 이벤트 스트리밍: 상태의 변화(이벤트)를 **연속적인 스트림으로 기록**하고, 필요할 때마다 이 데이터를 다시 읽거나 분석하는 것을 목적 + + > 이번 장에서는 데이터 장기 보관, 베시지 반복 소비 등의 부가 기능을 갖춘 **분산 메시지 큐**를 설계한다. (이러한 부가 기능은 통상적으로 이벤트 스트리밍 플랫폼에서만 이용 가능하다) +> + +--- + +## 메시지 큐의 기본 기능 + +- 생산자는 메시지를 메시지 큐에 발행 +- 소비자는 큐를 구독하고 구독한 메시지를 소비 +- 메시지 큐는 사용자와 소비자 사이의 결합을 느슨하게 하는 서비스로, 생산자와 소비자의 독립적인 운영 및 규모 확장을 가능하게 하는 역할 +- 생산자와 소비자는 모두 클라이언트/서버 모델 관점에서 보면 클라이언트고 서버 역할을 하는 것은 메시지 큐이며 이 클라이언트와 서버는 네트워크를 통해 통신 + +## 메시지 모델 + +- 일대일 모델(point-to-point) + - 큐에 전송된 메시지는 오직 한 소비자만 가져갈 수 있다 + - 어떤 소비자가 메시지를 가져갔다는 사실을 큐에 알리면 해당 메시지는 큐에서 삭제됨 + - 데이터 보관을 지원하지 않음 +- 발행-구독 모델 + - 메시지를 보내고 받을 때는 토픽에 보내고 받게 됨 + - 토픽에 전달된 메시지는 해당 토픽을 구독하는 모든 소비자에 전달된다 + + + +## 토픽, 파티션, 브로커 + +> 메시지는 토픽에 보관한다. 토픽에 보관되는 데이터의 양이 커져서 서버 한 대로 감당하기 힘든 문제를 해결하기 위해 **파티션**, 즉 **샤딩** 기법을 활용한다. +> +- **토픽을 여러 파티션으로 분할**한 다음, 메시지를 모든 파티션에 균등하게 나눠 보낸다 +- 파티션은 메시지 큐 클러스터 내의 서버에 고르게 분산 배치한다 +- 파티션을 유지하는 서버는 보통 브로커라고 부른다 + - 파티션을 브로커에 분산해야 높은 규모 확장성 달성 할 수 있음 + - 토픽의 용량을 확장하고 싶으면 파티션 개수를 늘리면 된다 +- 각 토픽 파티션은 FIFO 큐처럼 동작 + - 같은 파티션 안에서는 메시지 순서가 유지됨 + - 파티션 내에서의 메시지 위치는 offset으로 표시 +- 메시지에는 키를 붙일 수 있는데, 같은 키를 가진 모든 메시지는 같은 파티션으로 보내진다 + - 키가 없을 경우 무작위 파티션 +- 토픽을 구독하는 소비자는 하나 이상의 파티션에서 데이터를 가져오게 된다 + - 토픽을 구독하는 소비자가 여러명일 경우, 해당 토픽의 소비자 그룹이라 부른다 + - **소비자 그룹** + - 하나의 소비자 그룹은 여러 토픽을 구독할 수 있고 오프셋을 별도로 관리한다 + - 같은 그룹 내의 소비자는 메시지를 병렬로 소비할 수 있다 + + > 데이터를 병렬로 읽으면 대역폭 측면에서는 좋지만 파티션 안에 있는 메시지를 순서의 소비를 보장할 수 없게 된다. 이 경우 한 그룹 안에서는 오직 한 소비자만 읽을 수 있다는 제약을 추가하면 일대일 모델에 수렴하게 되면서 순서가 보장된다. 또한 미리 충분한 파티션을 할당해 두면 파티션의 수를 동적으로 늘리는 일은 피할 수 있다. +> + + +## 개략적 설계안 + +- 클라이언트 + - 생산자: 메시지를 특정 토픽으로 보낸다 + - 소비자 그룹: 토픽을 구독하고 메시지를 보낸다 +- 핵심 서비스 및 저장소 + - 브로커: 파티션들을 유지한다. 하나의 파티션은 특정 토픽에 대한 메시지의 부분 집합을 유지한다 + - 저장소 + - 데이터 저장소: 메시지는 파티션 내 데이터 저장소에 보관된다 + - 상태 저장소: 소비자 상태는 이 저장소에 유지된다 + - 메타데이터 저장소: 토픽 설정, 토픽 속성 등은 이 저장소에 유지된다 + - 조정 서비스 + - 서비스 탐색: 어떤 브로커가 살아있는지 알려준다 + - 리더 선출: 브로커 가운데 하나는 컨트롤러 역할을 담당해야 하며, 한 클러스터에는 반드시 하나의 활성 상태 컨트롤러가 하나 있어야 한다. (컨트롤러가 파티션 배치를 책임짐) + - 아파치 주키퍼나 etcd가 보통 컨트롤러 선출을 담당하는 컴포넌트로 널리 이용됨 + +--- + +## 데이터 저장소 + +- 메시지 큐의 트래픽 패턴 + - 읽기와 쓰기가 빈번하고, 갱신/삭제 연산은 발생하지 않는다 +1. 데이터베이스 + + 읽기와 쓰기 연산이 동시에 대규모로 빈번하게 발생하는데 이를 처리하기 어렵다 + +2. 쓰기 우선 로그(WAL) + + 새로운 항목이 추가되기만 하는 일반 파일 + + - MySQL의 복구 로그(redo log), 아파치 주키퍼도 해당 기술 활용 + - WAL에 대한 접근 패턴은 읽기/쓰기 모두 순차적 + - 새로운 메시지는 파티션 꼬리 부분에 추가되며, 오프셋은 그 결과를 점진적으로 증가 + - 파일의 크기가 커질 수 있으니, 세그먼트 단위로 나누는 것도 좋음 + - 세그먼트를 사용할 경우 새 메시지는 활성 상태의 세그먼트 파일에만 추가된다 + - 해당 세그먼트 크기가 한계에 도달 시, 새 활동 세그먼트 파일이 만들어져 새 메시지를 수용하고, 다른 세그먼트 파일이 비활성 상태로 바뀜(읽기 요청만 처리) + +## 메시지 자료 구조 + +> 메시지 구조는 높은 대역폭 달성에 중요하다. 메시지가 큐를 거쳐 소비자에게 전달되는 과정에서 **불필요한 복사가 일어나지 않도록** 함으로써 높은 대역폭을 달성해야 한다. +> +- 메시지 키 + - 파티션을 정할 때 사용 + - 보통 `hash(key)%numPartitions` 공식에 따라 결정 +- 메시지 값 + - 메시지의 내용(페이로드) + + + +## 일괄 처리 + +- 생산자, 소비자, 메시지 큐는 메시지를 가급적 일괄 처리한다 + - 시스템 성능에 매우 중요 +- 운영체제로 하여금 여러 메시지를 한 번의 네트워크 요청으로 전송할 수 있도록 하기 때문에 네트워크 왕복 비용 제거 가능 +- 브로커가 여러 메시지를 한 번에 로그에 기록하면 큰 규모의 순차 쓰기 연산이 발생하고 운영체제가 관리하는 디스크 캐시에서 **더 큰 규모의 연속된 공간을 점유**하게 된다. + - 더 높은 디스크 접근 대역폭 달성 가능 + +> 높은 대역폭과 낮은 응답 지연은 동시에 달성하기 어렵다. 낮은 응답 지연이 중요한 전통적 메시지 큐에서는 일괄 처리 메시지 양을 낮추고, 디스크 성능은 낮아지게 된다. 처리량을 높여야 한다면 토픽당 파티션 수를 늘린다. +> + +### 생산자 측 작업 흐름 + +1. 생산자는 메시지를 라우팅 계층으로 보낸다 + + -라우팅 계층은 적절한 브로커에 베시지를 보내주는 역할 + +2. 라우팅 계층은 메타데이터 저장소에 사본 분산 계획을 읽어 자기 캐시에 보관 + + -메시지가 도착하면 라우팅 계층은 파티션-1의 리더 사본에 보낸다 + +3. 리더 사본이 우선 메시지를 받고 해당 리더를 따르는 다른 사본은 해당 리더로부터 데이터를 받는다 +4. 충분한 수의 사본이 동기화되면 리더는 데이터를 디스크에 기록한다. + + -데이터가 소비 가능 상태가 되는 것이 바로 이 시점이다 + + -기록이 끝나고 나면 생산자에게 회신을 보낸다 + + +- 리더와 사본이 필요한 이유 + - 장애 감내가 가능한 시스템을 만들기 위해 +- 위 흐름의 문제점 + - 라우팅 계층을 도입하면 거쳐야 할 네트워크 노드가 하나 더 증가 + - 일괄 처리되지 않는 방식 + + + +### 소비자 측 작업 흐름 + +소비자는 특정 파티션의 오프셋을 주고 해당 위치에서부터 이벤트를 묶어 가져온다 + +### 푸시 VS 풀 + +> 브로커가 데이터를 소비자에게 보낼 것이냐 아니면 소비자가 브로커에서 가져갈 것이냐 +> + +**푸시 모델** + +- 장점 + - 낮은 지연: 브로커는 메시지를 받는 즉시 소비자에게 보낼 수 있음 +- 단점 + - 소비자가 메시지를 처리하는 속도가 생산자가 메시지를 만드는 속도보다 느릴 경우, 소비자에게 큰 부하 걸릴 위험 + - 셍산자가 데이터 전송 속도를 좌우하므로, 소비자는 항상 그에 맞는 처리가 가능한 컴퓨팅 자원 준비해 둬야 함 + +**풀 모델 (대부분)** + +- 장점 + - 메시지를 소비하는 속도를 소비자가 스스로 결정 + - 소비속도가 생산속도보다 느릴 시 소비자를 늘리거나 생산 속도를 따라잡을 때 까지 기다려도 됨 + - 일괄 처리에 적합 +- 단점 + - 브로커에 메시지가 없어도 소비자는 계속 데이터를 끌어가려 시도해, 소비자의 컴퓨팅 자원 낭비됨 + - 이를 극복하기 위해 많은 메시지 큐가 롱 폴링 모드를 지원해, 당장은 가져갈 메시지 없더라도 일정 시간 기다리도록 한다 + +### 소비자 재조정 + +> 어떤 소비자가 어떤 파티션을 책임지는지 다시 정하는 프로세스로 코디네이터가 중요한 역할을 한다. +> +- 코디네이터 + - 소비자 재조정을 위해 소비자들과 통신하는 브로커 노드 + - 소비자로부터 오는 박동 메시지를 살피고 각 소비자의 파티션 내 오프셋 정보를 관리 + - 같은 그룹의 모든 소비자는 같은 코디네이터 + - 코디네이터는 자신의 소비자 목록 유지, 변화 생길 시 해당 그룹의 새 리더를 코디네이터가 선출 + - 새 리더는 새 파티션 배치 계획을 만들고 코디네이터에게 전달, 코디네이터는 이를 그룹내 모든 다른소비자에게 알림 + +### 상태 저장소 + +- 소비자에 대한 파티션의 배치 관계 +- **각 소비자 그룹이 각 파티션에서 마지막으로 가져간 메시지의 오프셋** +- 읽기 쓰기 빈번, 양은 많지 않음 + - 읽기와 쓰기 연산은 무작위 패턴 +- 데이터 갱신은 빈번, 삭제는 거의 없음 +- 데이터의 일관성 중요 + +### 메타데이터 저장소 + +- 토픽 설정이나 속성 정보를 보관 + - 파티션 수, 메시지 보관 기간, 사본 배치 정보 .. +- 자주 변경되지 않으며 양이 적고 높은 일관성을 요구한다 + - 주로 주키퍼 사용 +- **주키퍼** + - 계층적 키-값 저장소 기능을 제공 + - 분산 설정 서비스, 동기화 서비스, 이름 레지스트리 등으로 이용 + + → 주키퍼를 이용해 메타데이터 저장소, 상태저장소 구현 가능 / 리더 선출 과정(조정 서비스) 도와줌 + + +## 복제 + +> 높은 가용성을 보장하기 위해 +> +1. 생산자는 메시지를 리더에게만 보냄 +2. 다른 사본은 리더에게 새 메시지를 지속적으로 가져와 동기화 +3. 메시지를 완전히 동기화한 사본의 개수가 **지정된 임계값**을 넘으면 리더는 생산자에게 메시지를 잘 받았다는 응답을 보냄 +- 사본 분산 계획 + - 사본을 어떻게 분산할지 기술 + - 조정 서비스의 도움으로 브로커 노드 가운데 하나가 리더로 선출되면 해당 리더 브로커 노드가 사본 분산계획을 만들어 메타데이터 저장소에 보관 + +### 사본 동기화 + +> 메시지는 여러 파티션에 두며, 각 파티션은 다시 여러 사본으로 복제 +> +- 동기화된 사본(ISR) + - 토픽의 설정마다 다름 + - ex) 단순 사본에 보관된 메시지 개수와 리더 사이의 차이 + - ISR은 성능과 영속성 사이의 타협점 + - 생산자에게 메시지를 잘 받았다는 응답을 보내기 전에 모든 사본을 동기화 하는 것 +- ACK=all + - 생산자는 모든 ISR이 메시지를 수신한 뒤에 ACK 응답 받음 + - 시간을 길지만 영속성 측면에서 가장 좋음 +- ACK=1 + - 셍산자는 리더가 메시지를 저장하고 나면 바로 ACK 응답을 받음 + - 동기화를 기다리지 않으니 응답 지연은 낮지만, 리더에 문제 생기면 다른 사본에 반영되지 못했으므로 복구할 수없어 소실 +- ACK=0 + - 생산자는 수신 확인 메시지를 기다리지 않고 계속 메시지를 전송하며 재시도 X + - 낮은 응답 지연위해 메시지 손실을 감수 + +## 규모 확장성 + +- 생산자 + - 새로운 생산자를 추가하거나 삭제하면서 쉽게 달성 +- 소비자 + - 소비자 그룹은 독립적이므로 쉽게 추가, 삭제 가능 + - 소비자 그룹 내 소비자가 추가/삭제될 경우 재조정 매커니즘이 맡아 처리 + - 소비자 측의 규모 확장성과 결함 내성을 보장 +- 브로커 + - 가장 간단한 방법은 브로커 노드가 추가/삭제될 때 사본을 재배치 + - 더 나은 방법으로는 브로커 컨트롤러로 하여금 **한시적으로 시스템에 설정된 사본 수보다 많은 사본을 허용**하도록 하는 것 + - 한시적으로 사본 수를 설정보다 늘려 사본을 재배치 한 후, 새 브로커가 기존 브로커 상태를 따라잡고 나면 필요없는 노드 제거 + - 브로커를 추가하는 도중 데이터 손실 피할 수 있음 + +## 파티션 + +> 생산자는 브로커와 통신할 때 파티션 수 조정을 통지 받으며, 소비자가 재조정을 시행 +> +- 토픽에 새로운 파티션이 추가될 경우 + - 지속적으로 보관된 메시지는 기존 파티션에 존재 + - 새 파티션이 추가되면 그 이후 오는 메시지는 파티션 전체에 지속적으로 보관 +- 파티션 삭제 + - 삭제될 파티션 지정되면(퇴역될 파티션), 새로운 메시지는 해당 파티션 제외 다른 파티션에 보관됨 + - 퇴역된 파티션은 일정 시간 동안 유지하다 삭제, 저장 공간 반환 + - 파티션 퇴역 후 실제 제거가 이루어지는 시점까지 생산자는 메시지를 남은 파티션으로만 보내지만 소비자는 모든 파티션에서 메시지를 읽음 + - 실제로 파티션 제거 시점이 오면 그때 생산자 그룹은 재조정 작업을 개시 + +## 메시지 전달 방식 + +- 최대 한 번(at-most-once) + + > 메시지가 소실되어도 다시 전달되는 일은 없음 + > + - 생산자는 토픽에 비동기적으로 메시지를 보내고 수신 응답을 기다리지 않음(ACK=0), 재시도X + - 소비자는 메시지를 읽고 처리하기 전에 오프셋부터 갱신 + - 오프셋이 갱신된 직후에 소비자가 장애로 죽으면 메시지는 다시 소비될 수 X + - 지표 모니터링 등 소량의 데이터 손실 감수할 수 있는 애플리케이션에 적합 +- 최소 한 번(at-least-once) + + > 메시지가 한 번 이상 전달될 수는 있으나 소실은 발생하지 않음 + > + - 생산자는 메시지를 동기/비동기적으로 보낼 수 있으며, ACK=1 또는 ACK=all의 구성을 이용 + - 브로커에게 전달되었음을 반드시 확인, 재시도 + - 소비자는 데이터를 성공적으로 처리한 뒤에만 오프셋 갱신 + - 메시지는 브로커나 소비자에게 한 번 이상 전달될 수 있음 (중복 전송 가능) +- 정확히 한 번(exactly once) + + > 사용자에게는 편리, 시스템의 성능과 구현 복잡도에는 큰 부담 + > + - 중복을 허용하지 않으며, 구현에 이용할 서비스나 제3자의 입력에 항상 같은 결과를 내 놓도록 구현되어 있지 않은 애플리케이션에 적합 + +## 고급 기능 + +- 메시지 필터링 + - 브로커에서 직접 필터링 시, 브로커의 성능 저하, 보호되어야 할 데이터를 메시지 큐에서 읽게 됨 + - 브로커에서 직접 메시지의 내용을 추출 X, 필터링에 사용될 데이터를 메타데이터 영역에 두어 브로커가 읽게끔 한다 ⇒ **태그(tag)** 사용해 필터링 가능 +- 메시지의 지연 전송 및 예약 전송 + - 토픽에 바로 저장하지 않고 브로커 내부의 임시 저장소에 넣어 두었다가 시간이 지나면 토픽으로 옮김 \ No newline at end of file diff --git a/marshmallowing/Week02/references02.md b/marshmallowing/Week02/references02.md new file mode 100644 index 0000000..fa6f13b --- /dev/null +++ b/marshmallowing/Week02/references02.md @@ -0,0 +1,125 @@ +# Apache Kafka: 이벤트 스트리밍 모델 분석 +[Introduction](https://kafka.apache.org/41/getting-started/introduction/) + +## Event Streaming이란? + +> **Event streaming**은 실시간으로 발생하는 이벤트를 캡처하고, 저장하고, 처리하는 기술이다. 단순히 데이터를 옮기는 기술이 아니라, 현대 비즈니스의 '디지털 중추 신경계' 역할이다. +> +- **실시간성:** 데이터가 발생(Database 변경, 센서 수치, 모바일 클릭 등)하는 즉시 이를 포착 +- **지속성:** 발생한 이벤트는 일회성으로 사라지지 않고, 나중에 다시 읽을 수 있도록 안전하게 보존 +- **분석 및 반응:** 과거의 데이터를 복습하거나 현재 들어오는 데이터를 실시간으로 가공하여 비즈니스 로직에 반영 +- **연결성(Routing):** 필요한 정보를 필요한 곳으로, 정확한 시간에 전달하는 통로 + + + +## Kafka의 핵심 설계 철학 + +1. **발행-구독(Pub-Sub):** 데이터의 생산자와 소비자를 완전히 분리하여, 서로의 상태와 상관없이 대규모 데이터를 막힘없이 주고받음 +2. **무한 저장소:** 데이터를 소비했다고 해서 바로 지우지 않고 사용자가 설정한 기간만큼 혹은 용량만큼 데이터를 쌓아두고 필요할 때마다 반복해서 읽을 수 있다 + + → 이벤트 스트림을 지속적으로 저장 + +3. **실시간 처리 엔진:** 단순 전달을 넘어 데이터 스트림을 변형하거나 합치는 등 복잡한 연산을 실시간으로 처리 + +> 이 모든 기능이 **확장성, 장애 내성, 분산 환경**에서도 동작한다는 게, 이벤트 스트리밍 플랫폼으로서 Kafka의 핵심이다 +> + +## 시스템 구성 요소 + +> 카프카는 고성능 TCP 프로토콜로 통신하는 **분산 시스템** +> +- **서버 계층:** + - **브로커:** 실제 데이터를 저장하고 클라이언트의 요청을 처리하는 엔진 + - 서버 한 대가 죽어도 데이터가 유실되지 않도록 클러스터 단위로 운영 + - **카프카 커넥트:** DB나 외부 시스템에서 데이터를 자동으로 가져오거나 내보내는 전용 통로 +- **클라이언트 계층:** + - **Producers:** 이벤트를 카프카에 기록 + - **Consumers:** 카프카에 기록된 이벤트를 읽어서 처리 + - **유연성:** 거의 모든 언어를 지원하며 병렬 처리가 가능 + + + +## Kafka 주요 개념 + +- **Event / Record** + - 비즈니스에서 발생하는 사실을 기록한 단위 + - **키(Key), 값(Value), 타임스탬프**로 구성 +- **토픽과 파티션** + + ![image.png](attachment:7019215e-761d-432c-8ba0-5c81de8441b6:image.png) + + - **토픽:** 이벤트들을 모아놓는 카테고리/스트림 이름 + - **파티션:** 하나의 토픽은 여러 개의 파티션으로 쪼개져 여러 브로커에 분산 저장 + - 여러 서버(Brokers)에 균등 분산 + - 같은 Topic이라도 여러 Partition에서 병렬 처리 + - Producer는 이벤트 Key를 기준으로 Partition을 정하고 Consumer는 Partition 단위로 읽음 + - **순서 보장:** 동일한 키를 가진 데이터는 항상 같은 파티션으로 들어감 + - 카프카는 파티션 내부에서의 데이터 읽기 순서를 보장하여 비즈니스 로직이 꼬이지 않게 함 + + > 토픽과 파티션 구조 덕분에 병렬 읽기/쓰기 + 순서 보장이 가능하며 이는 대규모 확장성 구조이다 +> +- **복제** + - 데이터 안정성을 위해 파티션의 복사본을 여러 브로커에 복제 + +## Consumer Group과 Offset 관리 + +![image.png](attachment:065fc829-339e-4f35-adc3-783e973e2b44:image.png) + +Kafka에서 Consumer는 단독으로 동작하지 않고, **Consumer Group** 단위로 묶여 동작한다. + +- 하나의 **Consumer Group**은 하나의 논리적 애플리케이션 +- 하나의 파티션은 **하나의 Consumer에게만** 할당된다 +- Consumer 수 ≤ Partition 수일 때 병렬 처리 가능 + +Kafka는 각 Consumer Group이 **어디까지 읽었는지(offset)** 를 내부적으로 관리한다. + +- offset: 파티션 내에서 Consumer가 마지막으로 읽은 위치 +- Consumer 장애 발생 시, 같은 그룹의 다른 Consumer가 offset부터 이어서 처리 +- 이 구조 덕분에 **Exactly-once / At-least-once 처리 전략**이 가능 + + + +## Kafka의 Pull 기반 소비 모델 + +Kafka는 Consumer가 데이터를 **Pull 방식**으로 가져간다. + +- Consumer가 처리 가능한 속도로 데이터를 요청 +- 느린 Consumer가 전체 시스템을 막지 않음 +- 백프레셔(Back-pressure)를 Consumer 쪽에서 제어 가능 + +⇒ 이는 대규모 분산 환경에서 트래픽 폭주 방지, Consumer 간 처리 속도 차이 허용, 안정적인 확장성 확보 + +## Kafka와 기존 메시지 큐의 차이 + +Kafka의 가장 큰 차이는 **데이터 삭제 방식**이다 + +- 전통 메시지 브로커 - 메시지를 읽으면 삭제 (Queue 방식) +- Kafka - 메시지를 읽어도 저장해두고 Retention 설정으로 오래 보관 가능하다 + - retention - 이벤트 보존 정책 (시간/용량 기반)으로 보관 기간 동안 언제든 재생이 가능 + - 같은 메시지를 여러 소비자가 여러 번 읽을 수 있음 + + +## 핵심 API + +> 다음 핵심 API들을 통해 카프카를 제어한다 +> +- **Admin API:** 토픽 생성/삭제, 브로커 상태 확인 등 관리용 +- **Producer API:** 데이터를 카프카로 쏘는 용도 (이벤트 발행) +- **Consumer API:** 데이터를 카프카에서 가져오는 용도 (이벤트 구독/읽기) +- **Kafka Streams API:** 데이터를 실시간으로 변환, 집계하는 고차원 기능 제공 (스트림 처리 애플리케이션) +- **Kafka Connect API:** 외부 시스템(DB 등)과 데이터를 동기화하는 커넥터 운영 \ No newline at end of file