-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c3cdcd9
commit 8b42613
Showing
1 changed file
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# 8장 “정확히 한 번” 의미 구조 | ||
|
||
태그: 카프카 핵심 가이드 | ||
주차: 4 | ||
|
||
- 7장 → “최소 한 번” 전달에 초점 | ||
- = 메세지 중복의 가능성 잔재 | ||
- → “정확히 한 번” | ||
- 두 개의 핵심 기능 | ||
- 멱등적 프로듀서 idempotent producer: 프로듀서 재시도로 인해 발생하는 중복 방지 | ||
- 트랜잭션 의미 구조: 스트림 처리 애플리케이션에서 “정확히 한 번“ 처리 보장 | ||
|
||
## 1. 멱등적 프로듀서 | ||
|
||
- 멱등적 idempotent: 동일한 작업을 여러 번 실행해도 한 번 실행한 것과 결과가 같은 서비스 | ||
|
||
### 멱등적 프로듀서의 작동 원리 | ||
|
||
- 멱등적 프로듀서 기능 사용 시, 모든 메세지는 고유한 프로듀서 ID와 시퀀스 넘버를 가지게 됨 | ||
- 대상 토픽 및 파티션과 이 두 값 합치면 → 각 메세지의 고유한 식별자 | ||
- 작동 실패 시 멱등적 프로듀서 처리 방식 | ||
- 프로듀서 재시작 | ||
- 프로듀서는 초기화 과정에서 카프카 브로커로부터 프로듀서 ID 생성 받음 | ||
- 새 프로듀서가 기존 프로듀서가 이미 전송한 메세지를 다시 전송할 경우, 메세지 중복 발생 알 수 없음 | ||
- 브로커 장애 | ||
- 컨트롤러는 장애가 난 브로커가 리더를 맡고 있었던 파티션들에 대해 새 리더 선출 | ||
- 리더가 새 메세지 쓰여질 때마다 인-메모리 프로듀서 상태에 저장된 최근 5개의 시퀀스 넘버 업데이트 | ||
- 예전 리더가 복귀하는 경우 | ||
- 재시작 후에는 인-메모리 프로듀서 상태 메모리 저장 X | ||
- 크래시 복구 작업 진행되는 동안, 프로듀서 상태는 더 오래된 스탭샷뿐만 아니라 각 파티션 최신 세그먼트의 메세지들 사용해서 복구됨 | ||
|
||
### 멱등적 프로듀서의 한계 | ||
|
||
- 카프카의 멱등적 프로듀서는 프로듀서의 내부 로직으로 인한 재시도가 발생할 경우 생기는 중복만을 방지 | ||
- 동일한 메세지를 가지고 producer.send()를 두 번 호출하면 멱등적 프로듀서 개입X 메세지 중복 발생 | ||
|
||
### 멱등적 프로듀서 사용법 | ||
|
||
- 프로듀서 설정에 enable.idempotence=true 설정 | ||
- 멱등적 프로듀서 사용시 변화하는 것들 | ||
|
||
## 2. 트랜잭션 | ||
|
||
- 카프카 스트림즈를 사용해서 개발된 애플리케이션에 정확성을 보장하기 위해 도입됨 | ||
- 스트림 처리 애플리케이션의 기본 패턴인 “읽기-처리-쓰기” 패턴에서 사용하도록 개발됨 | ||
|
||
### 트랜잭션 활용 사례 | ||
|
||
- 금융 애플리케이션 | ||
- 챗봇 | ||
|
||
### 트랜잭션이 해결하는 문제 | ||
|
||
- 애플리케이션 크래시로 인한 재처리 | ||
- 원본 클러스터로부터 메세지를 읽어서 처리 한 뒤 | ||
- 결과를 출력 토픽에 쓰고 | ||
- 읽어 온 메세지의 오프셋을 커밋 | ||
- 출력 토픽에는 이미 썼는데 입력 오프셋 커밋되기 전에 애플리케이션 크래시 발생 | ||
- 좀비 애플리케이션에 의해 발생하는 재처리 | ||
- 스스로 죽은 상태인지 모르는 컨슈머 = 좀비 | ||
- 좀비는 출력 토픽으로 데이터를 쓸 수 있음 → 중복된 결과 발생 | ||
|
||
### 트랜잭션은 어떻게 “정확히 한 번” 을 보장하는가? | ||
|
||
- 원자적 다수 파티션 쓰기 atomic multipartition write 기능 도입 | ||
- 읽어온 이벤트의 오프셋을 커밋함과 동시에 두 개의 파티션에 원자적 다수 파티션 쓰기를 수행 | ||
- 이를 위해서는 트랜잭션적 프로듀서 사용 필요 | ||
- 보통 프로듀서와의 차이점: transactional.id 설정, initTransactions() 호출해 초기화 | ||
- 애플피케이션의 좀비 인스턴스가 중복 프로듀서 생성 방지 → 좀비 펜싱, 애플리케이션의 좀비 인스턴스가 출력 스트림에 결과를 쓰는 것을 방지 | ||
- 에포크 epoch 사용 | ||
- 트랜잭션 메타데이터에 컨슈머 그룹 메타데이터 추가 옵션 | ||
- isolation.level 설정값 → 트랜잭션 기능을 써서 쓰여진 메세지 읽어오는 방식 제어 가능 | ||
- read_uncommitted/read_committed | ||
|
||
### 트랜잭션으로 해결할 수 없는 문제들 | ||
|
||
- 트랜잭션 기능 관련해서 자주하는 실수 두 가지 | ||
- “정확히 한 번 보장”이 카프카에 대한 쓰기 이외의 작동에서도 보장된다고 착각 | ||
- 컨슈머가 항상 전체 트랜잭션을 읽어온다고 가정하는 것 | ||
- 카프카의 트랜잭션 기능이 “정확히 한 번” 보장에 도움이 되지 않는 경우 | ||
- 스트림 처리에 있어서의 부수 효과 | ||
- 카프카 토픽에서 읽어서 데이터베이스에 쓰는 경우 | ||
- 하나의 트랜잭션에서 외부 데이터베이스에는 결과를 쓰고, 카프카에 오프셋 커밋해주는 매커니즘 X | ||
- 데이터베이스에서 읽어서, 카프카에 쓰고, 여기서 다시 다른 데이터베이스에 쓰는 경우 | ||
- 종단 보장에 필요한 기능 X | ||
- 한 클러스터에서 다른 클러스터로 데이터 복제 | ||
- 하나의 카프카 클러스터에서 다른 클러스터로 데이터 복사 시 “정확히 한 번 보장” | ||
- 하지만, 트랜잭션의 원자성 보장 X | ||
- 발행/구독 패턴 | ||
- read_committed 모드가 설정된 컨슈머들은 중단된 트랜잭션에 속한 레코드 보지 못함 → 오프셋 커밋 로직에 따라 메세지를 중복 처리 가능성 O | ||
|
||
### 트랜잭션 사용법 | ||
|
||
- 일반적 방법: 카프카 스트림즈에서 exactly-once 보장 활성화 | ||
- 카프카 스트림즈를 사용하지 않는 방법: 트랜잭션 API를 직접 활용 | ||
|
||
### 트랜잭션 ID와 펜싱 | ||
|
||
- 트랜잭션 ID 선택: 중요, 조금 어려운 일 | ||
- 핵심 요구 조건 | ||
- 트랜잭션 ID가 동일 애플리케이션 인스턴시 재시작했을 때에는 일관적으로 유지 | ||
- 서로 다른 애플리케이션 인스턴스에 대해서는 서로 달라야함 | ||
- (브로커가 좀비 인스턴스의 요청을 처리하기 위해서) | ||
- 펜싱 fencing 을 보장하는 방법 | ||
- (버전 2.5까지) 트랜잭션 ID를 파티션에 정적으로 대응시키는 것 | ||
- KIP-447: 트랜잭션 ID와 컨슈머 그룹 메타데이터를 함께 사용하는 펜싱 도입 | ||
|
||
### 트랜잭션의 작동 원리 | ||
|
||
- 기본적인 알고리즘: 찬디-램포트 스냅샷 알고리즘 | ||
- 현재 진행 중인 트랜잭션이 존재함을 로그에 기록. 연관된 파티션들도 함께 기록됨 | ||
- 로그에 커밋 혹은 중단 시도 기록 | ||
- 모든 파티션에 트랜잭션 마커를 씀 | ||
- 트랜잭션 종료되었음을 로그에 씀 | ||
- 트랜젹션 로그 필요 | ||
|
||
## 3. 트랜잭션 성능 | ||
|
||
- 트랜잭션은 프로듀서에 약간의 오버헤드 발생시킴 | ||
- 프로듀서에 있어서 트랜잭션 오버헤드는 트랜잭션에 포함된 메세지의 수와 무관 | ||
- 컨슈머의 경우, 커밋 마커를 읽어오는 작업에 관련해서 약간의 오버헤드 | ||
- 컨슈머는 아직 완료되지 않은 트랜잭션에 속하는 메세지들을 버퍼링할 필요가 없음 |