23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
안녕하세요! KafakaKRU(카프카 한국 사용자 모임)의 “카프카 데이터 플랫폼의 최강자”, “실전 카프카 개발부터 운영까지”
두 책의 저자 고승범님께서 진행하신 카프카 스터디로 만나게 된 황한희, 김명관, 서수진입니다.
4주간 데보션 전문가 고승범님이 진행하신 카프카 입문 내용을 토대로 각 팀별로 관심있는 연구과제를 선정하여 진행하였습니다.
저희 팀의 연구과제는 “Kafka MirrorMaker2의 성능을 간단한 카오스 엔지니어링 기법을 활용해 테스트해보자!”입니다.
타이틀이 거창해보이지만, 간단한 실습 환경을 구성해서 테스트하는 형식으로 진행하였습니다. 여러분의 넓은 마음으로 귀엽게 봐주시기 바랍니다🙂
Apache Kafka는 또 다른 Kafka 클러스터를 대상으로 데이터를 미러링 하는 기능인 Kafka MirrorMaker라는 솔루션을 제공
하고 있습니다. 가장 최근에 release된 버전은 2(이하 MM2)로, Kafka를 사용하는 수 많은 프로젝트에서 활발하게 사용되고
있으며 아래와 같은 기능들을 제공하고 있습니다.
각 클러스터 간 Topic Configuration에 대한 Sync 기능
모니터링에 필요한 클러스터 간 Metric 제공
클러스터 간 데이터 미러링을 단일 properties파일로 정의 가능
새로운 Topic, Partition 감지 기능
기존 MirrorMaker1에서는 위와 같은 기능들을 제공하지 않아 DR(Disaster Recovery)와 같은 상황에 적합하지 않아
사용되지 못한다는 단점이 있었지만, 버전 2가 등장하면서 어느 정도 개선이 이루어지게 되었습니다.
MM2의 Topic을 미러링하는 과정을 구현하기 위해서는 공식적으로 아래와 같은 사항들이 고려되어 집니다.
Source, Target의 Topic Partition은 1대1로 매핑되며 해당 Partition 내부에 데이터 순서는 동일해야 합니다.
Source, Target의 Topic의 Partition수는 동일해야 합니다.(ACTIVE-PASSIVE인 경우는 고려할 필요 없음)
Target의 Topic은 Source 클러스터의 Topic이 1대1로 매핑되어야 합니다.
Partition도 1대1 매핑이 이루어져야 합니다.(Partition의 번호까지 동일해야함)
출처 : https://cwiki.apache.org/confluence/display/KAFKA/KIP-382%3A+MirrorMaker+2.0
그렇다면 활용하는 방법들에는 무엇이 있을지도 한번 알아보겠습니다.
Fan-out : 1개의 클러스터로부터 2개 이상의 클러스터로 데이터를 분산하는 방식
Aggregation :2개 이상의 클러스터로부터 1개의 클러스터로 데이터를 미러링하여 활용하는 방식
Active-Active : 양쪽 클러스터 간에 서로의 데이터를 미러링 하는 방식
Active-Passive : 소스 클러스터의 데이터를 목적지인 클러스터로 데이터를 미러링하는 방식
이 실습에서는 가장 간단한 방식인 Active-Passive 방식을 활용해 데이터 손실에 대한 성능 테스트를 진행하도록 하겠습니다.
이런 설정과 관련된 내용들은 mm2.properties를 통해서 사용자의 목적에 맞게 수정하여 활용할 수 있습니다
--mm2.properties--
# 카프카 클러스터 리스트 정보
clusters=clusterA, clusterB
clusterA.bootstrap.servers=broker1A:29092,broker2A:39092,broker3A:49092
clusterB.bootstrap.servers=broker1B:29093,broker2B:29094,broker3B:29095
# Record를 저장하는 토픽의 Replication Facotr 설정
clusterA.config.storage.replication.factor=3
clusterB.config.storage.replication.factor=3
# 오프셋 정보를 저장하는 토픽의 Replication Facotr 설정
clusterA.offset.storage.replication.factor=3
clusterB.offset.storage.replication.factor=3
# 클러스터의 상태 정보를 업데이트하는 토픽의 Replication Facotr 설정
clusterA.status.storage.replication.factor=3
clusterB.status.storage.replication.factor=3
# 클러스터 간 메세지 전송 허용/차단 여부 설정
clusterA->clusterB.enabled=true
clusterB->clusterA.enabled=true
offset-syncs.topic.replication.factor=3
heartbeats.topic.replication.factor=3
checkpoints.topic.replication.factor=3
# 모든 토픽과 그룹을 동기화하도록 설정(기본값)
topics=.*
groups=.*
tasks.max=2
replication.factor=3
refresh.topics.enabled=true
sync.topic.configs.enabled=true
refresh.topics.interval.seconds=30
# 각 클러스터에 독립적으로 존재해야하는 태스크 관련 정보를 가진 토픽은 복제하지 않도록 설정
topics.blacklist=.*[\\-\\.]internal, .*\\.replica, __consumer_offsets
groups.blacklist=console-consumer-.*, connect-.*, __.*
# heartbeats와 checkpoints를 상호간에 허용하도록 설정
clusterA->clusterB.emit.heartbeats.enabled=true
clusterA->clusterB.emit.checkpoints.enabled=true
clusterB->clusterA.emit.heartbeats.enabled=true
clusterB->clusterA.emit.checkpoints.enabled=true실습에 들어가기에 앞서, 카오스 엔지니어링에 대해 개념을 먼저 알아보도록 하겠습니다.
“카오스 엔지니어링이란 서비스 환경이 예기치 못한 에러 상황에서도 견딜 수 있도록 그에 대한 신뢰를 쌓아가는 학문.”
추상적인 의미이기 때문에 바로 이해하기가 어려운 거 같으니 좀 더 풀어서 알아보도록 하겠습니다!
복잡한 구조를 가진 인프라 환경일수록 하나의 서비스가 다운됐을 때,
연쇄적으로 발생하는 장애에 대한 대책방안을 마련해둘 필요가 있다는 것은 누구나 생각은 할 수 있지만, 구체적으로 어떤 식으로 방안을 마련해야 할지에 대해서는 계획한다는 건 당연하게도 쉬운 일이 아닙니다.
모든 시스템에 대해 완벽하게 파악하고 있다면 사고가 발생하기 전에 문제점을 인지하고 선조치가 가능하겠지만 저희는 사람이기 때문에 현실적으로 불가능하죠😢
그렇기 때문에 저희는 차선책으로 미래에 발생할 문제들에 대해 미리 경험해보고 이를 기반으로 대응 방안을 마련하는 방식을 선택해야만 합니다.
바로 이러한 접근방식을 통해 경험을 쌓아가면서 서비스 환경에 대한 대책방안을 세워나가면서 어떠한 환경에서도 서비스는 지속할 수 있도록 하는 접근법을 카오스 엔지니어링이라고 이해할 수 있겠습니다.
그럼 본격적으로 카오스 엔지니어링 접근방식을 기반으로 Kafka MirrorMaker2의 성능테스트 실습을 진행해보겠습니다. (원하신다면 직접 따라 해보셔도 좋습니다.😊)
이제 본격적으로 Kafka MM2를 이용한 카오스 엔지니어링 실습을 해보도록 하겠습니다.
실습의 구조는 아래 그림과 같이 진행됩니다.
우선, 실습에 필요한 데이터와 MM2 환경 구성에 필요한 docker-compose 파일 등을 다운받아야 합니다.
git clone https://github.com/hhh6593/chaos-test-with-kafka.git※ Windows의 경우는 WSL2 환경에서만 실습이 가능합니다.
도커 컴포즈를 활용해 미리 구성한 이미지를 활용해 컨테이너를 실행합니다.
구성 목록은 다음과 같습니다.
ClusterA : 브로커 3대로 구성한 클러스터(Source Cluster)
Broker1A
Broker2A
Broker3A
ClusterB : 브로커 3대로 구성한 클러스터(Target Cluster)
Broker1B
Broker2B
Broker3B
ZookeeperA : ClusterA를 구성하는 주키퍼
ZookeeperB : ClusterB를 구성하는 주키퍼
Mirror-Maker : ClusterA, ClusterB 간 데이터 미러링을 돕는 Connect, Connector
Kafdrop : 각 클러스터 모니터링을 위해 지원하는 UI
KafdropA : ClusterA 모니터링 용도
KafdropB : ClusterB 모니터링 용도
docker-compose up -dKafka MM2는 파이프라인 구성 작업을 편리하게 할 수 있도록 돕는 Kafka Connect를 기반으로 작성되었으며, 총 3개의 Connector로 구성되어 있습니다.
MirrorSourceConnector : Topic의 데이터를 복제, Topic의 파티션 정보 및 ACLs 동기화
MirrorCheckpointConnector : Consumer Group offset 동기화
MirrorHeartbeatConnector : 복제 모니터링을 위한 Hearbeat 전송
# 컨테이너 터미널 접속
docker exec -it {mirror-maker containerID} /bin/bash
# Kafka Log4j configuration 설정
export KAFKA_LOG4J_OPTS="-Dlog4j.configuration=file:/etc/kafka/connect-log4j.properties"
# Kafka MM2 실행
connect-mirror-maker /tmp/kafka/config/mm2.propertiesKafdrop UI 통해서 Topic을 생성할 수 있기 때문에 해당 기능을 활용하여 두 클러스터 간 동일한 구성으로 Cluster를 생성해준다.
Kafdrop UI 접속
KafdropA : localhost:9000
KafdropB : localhost:9001
ClusterA Topic 생성
최하단 Topic 카테고리 내 +NEW 버튼 클릭
Topic명 : stream_sample_data_topic
파티션 : 3
Replication factor : 3
※ MM2를 이용하기 위해서는 데이터 미러링을 하는 두 Topic의 파티션이 동일해야 합니다.
KafdropB에서 확인한 Topic 리스트
KafdropB UI에 접속하면 MM2를 실행한 후에 자동으로 생성된 토픽들을 확인할 수 있다.
__consumer_offsets : Consumer Group이 읽어간 offset의 정보
clusterA.checkpoints.internal : 상대 클러스터와의 offset 동기화 작업을 확인하는 토픽
clusterA.heartbeats : ClusterA로부터 정상적으로 작동중인지 확인하는 토픽
*clsuterA.stream_sample_data_topic : 소스 클러스터(ClusterA)의 이름이 prefix로 붙어 생성된 복제 토픽
heartbeats : 데이터 미러링이 잘 이루어지고 있는지 확인하는 토픽
mm2-configs.clusterA.internal : 상대 클러스터의 설정 변경사항을 확인하는 토픽
이처럼 새로 생성된 토픽을 MM2가 감지하고 미러링되는 클러스터에 자동으로 생성해주는 것을 확인할 수 있습니다.
이제 생성한 Kafka Cluster에 데이터 유실 검증을 위하여 간단하게 구현한 Producer와 Consumer를 로컬에서 실행시켜 줍니다.
# run Consumer
python3 ./scripts/consumer.py
# run Producer
python3 ./scripts/producer.py※Producer에서 사용한 데이터는 MovieLens에서 제공하는 1970년도 영화 평점 데이터를 활용하였습니다.(10만건)
출력결과
Broker1A Producer.py / Broker1B Consumer.py
Pumba 이미지 출처 : https://disney.fandom.com/wiki/Pumbaa
PUMBA는 카오스 엔지니어링을 테스팅하기 위해 도커 기반의 환경에 제공되는 카오스 테스팅 도구로, 컨테이너 애플리케이션 간 충돌을 일으키거나 네트워크 장애를 고의적으로 발생시킬 수 있는 기능을 제공합니다.
예상치 못한 장애에 대해 탄력적인 서비스를 구축하기 위해서 미리 PUMBA와 의도적인 오류를 발생시키는 카오스 테스팅 도구를 활용하여
서비스를 운영하기에 앞서 문제점을 파악하고 복원력에 대한 정책을 세우는 작업을 수행할 수 있습니다.
PUMBA는 우리에게 익숙한 라이온 킹에 나오는 등장인물로 이름은 기억하지 못할지라도 이미지를 본다면
누구나 익숙한 느낌을 주는 캐릭터로 멍청하고, 부주의하며 산만하다는 특징을 가지고 있습니다. 그래서인지 애플리케이션이 동작하는 방식 또한 이름에 걸맞게(?) 작동합니다.
컨테이너 중지
컨테이너 내 실행 중인 프로세스 중지
네트워크 에뮬레이션을 통해 네트워크 장애, 대역폭 제한, 패킷 손실
etc
※소프트웨어를 통해 하드웨어적 기능처럼 동작하게 하는 방법
이러한 장애 유발은 특정 정규표현식을 통해 선별되는 컨테이너만 특정하는 기능도 제공합니다.
# Pumba 설치(오래된 버전에서는 특정 옵션을 지원하지 않기 때문에 최신버전 사용을 권장합니다.)
sudo curl -L <https://github.com/alexei-led/pumba/releases/download/0.9.0/pumba_linux_amd64> -o /usr/bin/pumba &&
sudo chmod +x /usr/bin/pumba간단한 테스트 환경이기 때문에 단순히 브로커 컨테이너만을 주기적으로 중단하고 다시 살리는 방식으로 구성하여 실행합니다.
# Pumba 임시 컨테이너를 로컬에 설치한 Pumba와 도커 소켓을 마운트하여 명령어를 도커 데몬에서 활용할 수 있도록 설정합니다.
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \\ | sudo pumba -skip-error \\
--log-level info --interval 10m stop -limit 2 \\
--restart --duration 10s "re2:broker"-skip-error : 동작중 에러가 발생하여도 중지하지 않고 진행하도록 하는 옵션
-dry-run : 실제로 카오스를 진행하지 않고 시뮬레이션 로그만 출력하는 옵션(작동 테스트시 활용)
-log-level : 출력되는 로그 수준을 설정하는 옵션
-interval : 카오스 액션 수행 주기를 설정하는 옵션
-restart : 중지한 컨테이너를 다시 재시작하도록 해주는 옵션
-duration : restart의 수행 주기를 설정하는 옵션
"re2:" : 정규표현식을 활용해 매치되는 컨테이너만 카오스를 진행할 때 사용하는 옵션
10 만 건의 메세지를 전송하는 과정이 대략 2시간 동안 수행하며, 10분 간격으로 브로커 컨테이너 2개가 랜덤하게 중지되고, 살아나는 방식으로 실습을 진행하였습니다. 그 결과 데이터의 유실이 얼마나 일어났는지 확인해보도록 하겠습니다.
Raw Record count : 100,000
ClusterA(Source Cluster)
총 10만 건 중 약 300건 정도의 손실이 일어난 것을 확인할 수 있었으며, 예상을 했던 것과 반대로 Target에 쌓인 데이터가 더 많이 쌓여있었습니다.
이는 미러링 과정에서 Target 클러스터에서 offset이 업데이트되지 않고 컨테이너가 중지되어 재기동한 후에
Target #0 Partition이 동일한 데이터를 Consuming 하면서 중복된 데이터가 넘어간 것으로 추측됩니다. (다른 의견이 있으시다면 적극적으로 남겨주세요!)
결론적으로 데이터의 손실은 5% 이하였으며, 가장 중요한 미러링의 경우 1건의 중복 데이터를 제외하고는 제대로 복제가 이루어진 것을 확인 할 수 있었습니다.
한 가지 아쉬웠던 점은 각 클러스터의 Zookeeper를 1대가 아닌 3대로 늘려서 구성한 후에 브로커뿐만 아니라 Zookeeper까지 카오스 테스팅을 진행해보는 등
좀 더 다양한 상황에 대해서 테스트를 할 수 있었으면 좋았을 것 같다는 점이 아쉽게 남는 것 같습니다.
마지막으로 그렇다면 실제로 사용하고 있는 사례들이 있는지에 대해서도 궁금증을 가지고 계시는 분들이 있을 것 같아 몇 가지 대표적인 사례들을 남기면서 마치도록 하겠습니다.
Oracle - OCI streaming service 에서 MM2 사용사례
Strimzi - MM2 도입
https://strimzi.io/blog/2020/03/30/introducing-mirrormaker2/
AWS - MSK에서의 MM2 활용
지금까지 긴 글 읽어주셔서 감사드리며, 다음에 기회가 더 생긴다면 보다 좋은 글로 찾아뵙도록 하겠습니다.
https://cwiki.apache.org/confluence/display/KAFKA/KIP-382%3A+MirrorMaker+2.0
https://www.baeldung.com/ops/docker-compose-restart-policies
https://blog.cloudera.com/a-look-inside-kafka-mirrormaker-2/
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.