카프카 핵심 가이드 2E: 대규모 실시간 데이터와 스트림 처리
그웬 샤피라 , 토드 팔리노 , 라지니 시바람 , 크리트 페티 저자(글) · 이동진 번역
제이펍 · 2023년 04월 14일
10. 클러스터간 데이터 미러링하기
카프카에서는 같은 클러스터 내의 노드간 데이터 교환을 `복제(replication)`라 부르기로 하고, 다른 클러스터간 데이터 복제는 `미러링(mirroring)`이라고 부르기로 한다.
10.1 클러스터간 미러링 활용 사례
- 지역 및 중앙 클러스터: 각 도시의 데이터센터에 클러스터를 갖고, 각 데이터들을 중앙 클러스터에 미러링하여 비즈니스적인 분석을 해야하는 경우 활용
- 고가용성(high availability)와 재해 복구(disaster discovery): 여분 준비
- 규제: 국가별, 법적 문제 등으로 클러스터별로 서로 다른 설정과 정책을 적용해야할 때 사용
- 클라우드 마이그레이션: 온프레미스의 클러스터와 클라우드의 클러스터간 동기화가 필요할 때가 있을 수 있음
- 엣지클러스터로부터의 데이터 집적: IoT처럼 실시간으로 많은 데이터가 들어오고 네트워크가 불안정할 수 있는 경우, 집적용 클러스터를 구성하여 가용성을 높이는데 사용할 수 있다
10.2 다중 클러스터 아키텍처
10.2.1 데이터센터간 통신의 현실적인 문제들
- 높은 지연(high latency): 클러스터간 물리적 거리나 네트워크 홉(hop) 개수가 증가함에 따라 통신 지연이 증가
- 제한된 대역폭(limited bandwidth): 물리적으로 거리가 떨어지면 광역 통신망(wide area network, WAN)을 사용하며, 대역폭이 데이터 센터 내부보다 훨씬 낮으며 시시각각 바뀐다.
- 높은 비용: 대역폭을 확장하는데 엄청난 비용이 들고, 보통은 인터넷 공급자가 서로 다른 데이터센터, 리전, 클라우드와의 데이터 전송에 추가 과금을 한다.
10.2.2 허브-앤-스포크 아키텍처
- 각 지역의 데이터들이 중앙 클러스터에 미러링되는 형태
- 지역에 있는 데이터 센터가 다른 지역의 데이터센터의 데이터를 이용할 수는 없다
- 중앙 클러스터에 각 지역의 데이터를 미러링하는 프로세스를 하나씩 설정하여 원격 클러스터의 데이터를 중앙 클러스터에 쓰도록 한다
10.2.3 액티브-액티브 아키텍처
- 2개 이상의 데이터센터가 전체 혹은 일부를 모두 읽거나 쓸 수 있는 형태
- 여러 위치에서 비동기적 읽기 또는 쓰기가 발생하는 경우 충돌이 날 수 있다
- 예를 들어 인터넷 서점이라면 하나의 데이터 센터에서 위시리스트에 책을 추가하고, 곧바로 다른 데이터센터에서 데이터를 읽어오는 경우 위시리스트에 방금 추가한 책이 없을 수도 있다. 이런 경우 각 사용자를 특정 데이터센터에 고정하는 방법 등을 고려해야한다.
- 데이터 클러스터간 순환 미러링을 방지해야한다.
- 예를 들어 users 토픽은 샌프란시스코에서는 SF.users, 뉴욕에서는 NYC.users라는 토픽을 두고 운영하며, NYC 데이터센터의 토픽을 샌프란시스코에 미러링하는 경우 NYC.users 라는 토픽을 샌프란시스코에 미러링하여 구분하면 순환 미러링이 방지될 수 있다
- 레코드 헤더(record header) 기능 등을 활용하면 순환 미러링을 방지할 수도 있다. 카프카 0.11.0 에서 추가되었고 미러링 방지를 위해 적용하는 것은 책을 집필하는 시점에는 아직 반영되지 않았다고 한다
10.2.4 액티브-스탠바이 아키텍처
- 장애 복구용으로 여분의 클러스터를 두는 방식
- 아키텍처는 간단하지만 자원의 낭비가 발생한다.
- 장애 복구용 클러스터를 DR(disaster recovery) 클러스터라고 표현한다.
재해 복구 계획
두 개의 지표를 목표로 한다. `복구 목표 시간(recovery time objective, RTO)`, `복구 지점 목표(recovery point objective, RPO)`
- RTO를 줄일려면 동기적으로 미러링을 수행해야한다.
계획에 없던 장애 복구에서의 데이터 유실과 불일치
예상치 못한 장애로 메시지가 유실될 경우, DR 클러스터로의 미러링 프로세스가 불완전할 수도 있다. 이럴 경우를 대비해서 애플리케이션 단에서 유실된 메시지를 처리하는 방법을 마련해두어야한다.
장애 복구 이후 애플리케이션의 시작 오프셋
다른 클러스터로 데이터를 옮긴 후 애플리케이션이 데이터를 읽어오는 오프셋을 지정해야한다. 이것은 어려운 일이다. 몇 가지 방법론이 있다.
- 오프셋 토픽 복제: __consumer_offsets 토픽에 가장 최근의 오프셋이 저장되어 있으므로 이를 DR 클러스터로 미러링해주는 방식이다.
- 주 클러스터와 DR 클러스터간 오프셋 불일치, 오프셋 랙 등으로 인한 어느 정도의 중복 처리는 감수해야할 수 있다.
시간 기반 장애 복구
[kafka-consumer-groups.sh](http://kafka-consumer-groups.sh) 의 기능을 사용하면 특정 컨슈머 그룹의 모든 토픽에 대한 컨슈머 오프셋을 특정 시점으로 초기화할 수 있게 해준다. 이를 이용하면 특정 시점으로 오프셋을 복구할 수 있다. 물론 복구 후부터 메시지를 처리함에 있어서 애플리케이션상 중복 등의 문제가 없도록 처리해야한다.
오프셋 변환
미러링되는 클러스터간의 오프셋 매핑을 저장하기 위한 툴로 예전에는 아파치 카산드라 등을 사용했다. 최근에는 카프카 토픽을 사용한다.
오프셋이 틀어질 때마다 저장된다. 예를 들어 주클러스터 496 오프셋이 DR 클러스터 500 오프셋에 매칭된다면 (496, 500)을 저장하는 식이다. 이를 기반으로 실제 장애 복구 작업 시 오프셋 차이만큼 더하거나 빼서 메시지들을 처리한다.
장애 복구 후
복구 후 원래 주클러스터에는 기존의 데이터가 남아있을 수 있다. 가장 간단한 방법은 기존 주클러스터의 데이터와 오프셋을 초기화하는 방법이다.
10.2.5 스트레치 클러스터
하나의 카프카 클러스터를 여러 개의 데이터센터에 걸치도록 설계하는 방식이다.
- 각 파티션이 하나 이상의 데이터센터에 분산해서 저장되도록 랙(rack) 설정을 해주고, min.insync.replicas 설정을 잡아주고, acks를 all로 잡아주면 된다.
- 설정을 개별적으로 둘 수 없고 주키퍼 클러스터를 사용한다면 한 리전 안에 3개의 가용영역을 사용 중일 때 가능하다.
10.3 아파치 카프카의 미러메이커
다른 카프카 클러스터에서 데이터를 읽어오기 위해서 소스 커텍터를 사용한다. 미러메이커에서는 커넥터가 나눈 각각의 태스크들이 한쌍의 컨슈머와 프로듀서로 이루어진다.
아래 그림은 액티브-스탠바이 아키텍처 구성 시 미러메이커의 프로세스
10.3.1 미러메이커 설정하기
미러메이커는 카프카 커넥트를 기반으로 한다.
실행
```bash
bin/connect-mirror-maker.sh etc/kafka/connect-mirror-maker.properties
```
각 클러스터의 별칭 및 부트스트랩 서버를 적어주고, 미러링할 토픽이나 미러링을 제외할 토픽을 정규식으로 지정해줄 수 있다.
- 위 액티브-액티브 모드에서 살펴본 것처럼 각 클러스터의 별칭이 토픽 앞에 접두사로 붙어서 순환 참조를 방지한다.
RemoteClusterUtils
주기적인 오프셋 마이그레이션: 주 클러스터에서 DR 클러스터로 __consumer_offsets를 주기적으로 커밋해준다. DR 클러스터로 복구가 일어날 때, 컨슈머들이 별도의 마이그레이션 작업이 필요없이 오프셋에서 바로 작업을 재개할 수 있게 해준다. 다만 DR 클러스터의 컨슈머 그룹을 사용 중인 컨슈머들이 있다면 이 기능이 __consumer_offsets를 덮어쓰지 않도록 해서 오프셋 충돌이 나는 것은 방지한다.
토픽 설정 및 ACL 마이그레이션
데이터 외에 설정 및 ACL(Access Control List)를 미러링할 수도 있다. 어떤 설정이나 토픽을 포함하거나 제외할 지 커스터마이징이 가능하다.
커넥터 태스크
tasks.max 값으로, 2 이상으로 잡을 것을 권장한다. 복제할 토픽 파티션이 많은 경우 병렬 처리 수준 향상을 위해 더 높게 설정한다.
10.3.3 미러메이커 보안
원본과 대상 클러스터 양쪽에 보안이 적용된 브로커 리스너를 사용해야한다. 또한 각 클러스터에 대해 클라이언트 쪽 보안 옵션들 역시 적용되어야 한다. 모든 트래픽에는 SSL 옵션이 적용되어야 한다.
클러스터에 authorization이 설정되어있을 경우, 미러메이커에 필요한 권한
- 원본 클러스터의 Topic:Read 권한
- 원본 및 대상 클러스터에 Topic:Create, Topic:Write 권한
- 원본 클러스터의 Topic:DescribeConfig 권한(설정을 읽을 때 필요)
- 대상 클러스터에 Topic:Alter 권한
- 원본 클러스터에 Group:Describe 권한(오프셋 및 컨슈머 그룹의 메타데이터를 얻어오기 위함)
- 대상 클러스터의 Group:Read 권한(오프셋을 클러스터에 커밋해주기 위한 권한)
- 원본 클러스터의 Cluster:Describe 권한, 대상 클러스터의 Cluster:Alter 권한(ACL을 원본에서 가져오고, 대상에 커밋)
10.3.4 프로덕션 환경에 미러메이커 배포하기
- 미러메이커는 도커 컨테이너 안에서 사용할 수 있으며 무상태이다. 모든 필요한 데이터 및 상태는 카프카에 저장된다
- 동일한 대상 클러스터를 갖게 하면 자동으로 서로를 인식해서 부하 균형을 맞춘다.
- 되도록이면 미러링의 대상이 되는 클러스터의 데이터센터에서 실행하는 것을 권장한다. 즉 컨슈머 쪽에 설치하는 것인데, 이는 문제가 생겼을 때 이벤트를 읽어오지 못하는 것은 괜찮지만 프로듀서 자체가 동작하지 않아서 이벤트가 유실되는 것보다는 안전하기 때문이다.
모니터링
미러링 시 모니터링할 사항들과 설정값들에 대해 정리한다
- 카프카 커넥트 모니터링
- 미러메이커 지표 모니터링
- replication-latency-ms: 레코드의 타임스탬프와 대상 클러스터에 성공적으로 쓰여진 시각의 차이를 보여줌
- record-age-ms: 복제 시점에 레코드가 얼마나 오래되었는지
- byte-rate: 복제 처리량
- checkpoint-latency-ms: 오프셋의 마이그레이션 지연값
- 랙 모니터링
- kafka-consumer-groups 툴로 현재 미러메이커가 읽고 있는 각 파티션의 오프셋을 확인가능하다. 기본값이 1분이며 미러메이커가 항상 오프셋을 커밋하는 것은 아니라서 완벽히 정확하지는 않다.
- 프로듀서/컨슈머 지표 모니터링
- 컨슈머: fetch-size-avg, fetch-size-max, fetch-rate, fetch-throttle-time-avg, fetch-throttle-time-max
- 프로듀서: batch-size-avg, batch-size-max, requests-in-flight, record-retry-rate
- 둘 다: io-ratio, io-wait-ratio
10.3.5 미러메이커 튜닝하기
커넥터 태스크 수에 따른 미러메이커 처리량
kafka-performanc-producer 툴을 통해서 미러메이커를 1, 2, 4, 8, 16, 32개 태스트와 실행해본 뒤 어느 지점에서 성능이 줄어드는지 본다. 그리고 tasks.max 설정값을 그 값 이하로 잡아준다.
TCP 네트워크 튜닝
send.buffer.bytes.receive.buffer.bytes를 설정해서 프로듀서, 컨슈머의 버퍼 크기를 잡아주거
나 socket.send.buffer.bytes, socket.receive.buffer.bytes 설정을 잡아주어서 브로커쪽 버퍼 크기를 설정해주는 것이 유효할 수 있다. 다만 이 때는 아래 리눅스 네트워크 설정까지 최적화가 필요하다.
- TCP 버퍼 크기 증가(net.core.rmem_default, net.core.rmem_max, net.core.wmem_default, net.core.wmem_max, net.core.optmem_max
- 자동 윈도우 스케일링 설정(cysctl -w net.ipv4.tcp_window_scaling=1 혹은 /etc/sysctl.conf 파일에 net.ipv4.tcp_window_scaling=1을 추가해 준다)
- TCP 슬로우 스타트 시간 줄이기(/proc/sys/net/ipv4/tcp_slow_start_after_idle 설정값을 0으로 잡아준다)
프로듀서 튜닝
- linger.ms, batch.size: batch가 충분하게 채워지지 않은 채 메시지가 발송되는데 메모리에 여유가 있는 경우 설정
- max.in.flight.requests.per.connection: 메시지 순서가 중요하다면 이 값을 1로 설정해서 응답이 오고 나서 다음 메시지가 가도록 해야한다. 만약 순서가 중요하지 않은 경우라면 5 정도로 높여주는게 처리량을 확실히 증가시켜줄 수 있는 방법일 수 있다
- fetch.max.bytes: fetch-size-avg, fetch-size-max의 크기가 이 값과 비슷하게 나오고 있는지 체크해야한다. 메모리가 충분하다면 컨슈머가 요청마다 더 많은 데이터를 가져오도록 이 값을 늘려주면 된다.
- fetch.min.bytes, fetch.max.wait.ms: fetch-rate 지표가 높은 경우 요청대비 받은 데이터가 적다는 의미이다. 두 설정값을 늘려주면 컨슈머가 한 번에 더 많은 데이터를 받게 된다.
10.4 기타 클러스터간 미러링 솔루션
10.4.1 우버 uReplicator
토픽이 추가되었을 때 컨슈머를 재할당하기 위해 리밸런싱이 일어날 때, 파티션 수가 많은 경우 시간이 많이 걸린다. 이를 해결하기 위해 apache helix를 사용하여 컨트롤러를 구현했다. 이 컨트롤러에서 파티션을 받아오는 방식으로 리밸런스를 회피한다.
10.4.2 링크드인 브루클린
- 데이터 저장소와 스트림 처리 시스템 연결
- 서로 다른 데이터 저장소에 대해 CDC 이벤트 스트리밍
- 클러스터간 카프카 미러링
10.4.3 컨플루언트 레플리케이터
스트레치 클러스터를 위한 Multi-Region-Cluster(MRC) 탑재
- 옵저버를 두고, min.insync.replicas 이하로 떨어지면 옵저버를 승격시켜 데이터를 복제한다. 리전 복구가 완료되면 옵저버는 다시 승급 해제되어 감시자 역할을 한다.
- 클러스터 링킹: 서로 다른 클러스터간 토픽 설정, 파티션, 컨슈머 오프셋, ACL 등 모두를 동기화한다. 미러링되는 토픽들은 대상 클러스터에서 읽기 전용으로 표시되어 쓰기 작업이 불가능하다.
# 강의 내용 추가
https://developer.confluent.io/courses/hybrid-cloud/intro/
Confluent Cluster Linking, 오픈 소스 MirrorMaker2, 그리고 Confluent Replicator
## Cluster Linking
- 컨플루언트의 cloud linking을 사용하면 커넥터, 가상 머신 등 추가 구성 요소가 필요없다.
- REST API, k8s, CLI를 이용해서 동적으로 업데이트할 수 있다.
- 중복 레코드가 없고, 브로커 중단이나 파티션 재할당 등에 내구성 있게 설계되었다.
미러 토픽
여기서는 대상이 되는 클러스터에 생성하는 토픽을 미러 토픽이라고 부른다. 아키텍처 구조들은 위에서 배운 방식들과 동일하다.
미러메이커2
유일한 오픈 소스. 위 책에서 다룬 내용도 미러메이커2 내용이다.
- 모니터링을 위해 사용자가 직접 커스터마이징 필요
- 오프셋을 직접 설정해주어야함
- 변경 사항을 각 클러스터의 인스턴스에 적용해야하고, 이를 위해 재시작이 필요함
- 각 대상마다 카프카 커넥터 필요하여 오버헤드 유발
컨플루언트 레플리케이터
- 화이트리스트, 블랙리스트, 정규 표현식을 사용한 토픽 선택
- 파티션 수, 복제 인수, 토픽 구성 재정의가 일치하는 동적 토픽 생성
- 소스 클러스터에 새로운 파티션이 추가될 때 토픽 크기 자동 조정
- 소스 클러스터에서 토픽 구성이 변경될 때 토픽 자동 재구성
- 타임스탬프 보존
- 최소 한 번의 전달 보장, 즉 각 레코드가 대상 토픽에 전달되지만 대상 토픽에 중복 레코드가 있다.
- JMX 메트릭을 통해 복제 지연 시간과 처리량 포함한 모니터링 기능 제공
- RESTful API를 통해 Replicator에 필요한 변경 사항 적용 가능
'Programming-[Backend] > Kafka' 카테고리의 다른 글
[카프카 핵심가이드] 9. 모니터링 (2) | 2024.11.17 |
---|---|
[카프카 핵심가이드] 7. 멱등적 프로듀서와 트랜잭션 (1) | 2024.11.15 |
[카프카 핵심가이드] 5. 카프카 어드민 (0) | 2024.11.10 |
[카프카 핵심가이드] 3. 프로듀서 (2) | 2024.11.09 |
[카프카 핵심 가이드] 1. 카프카 시작하기 (1) | 2024.11.07 |