Open hubtwork opened 2 months ago
신뢰성 있는 시스템을 구축하기 위해서는 트레이드 오프가 필요하다. 카프카는 트레이드 오프를 할 수 있도록 설정을 세밀하게 조절하여 신뢰성을 필요한 만큼 지정할 수 있도록 되어 있다.
unclean.leader.election.enable 설정을 통해 out-of-sync 상태에서 Leader를 선출할 수도 있고, replica를 항상 in-sync 상태로 유지할 수도 있다. 앞에서 나왔던 auto.offset.reset 설정이 earliest이냐, latest이냐에 따라 중복 가능성이 달라지고 신뢰성을 보장하는 정도가 다르다. 여기에 더해서 enable.auto.commit와 auto.commit.interval.ms로 오프셋 커밋 설정을 조정할 수 있기도 하다. 신뢰성이 중요한 경우 모든 설정값에 대해 이해하고 이를 세밀하게 조정할 필요가 있는 것 같다. 하지만 이 때문에 생기는 중복 읽기라던지 유실이라던지 성능 저하라던지.. 적절한 비즈니스 상황에 맞게 선택해야 하는 점이 중요하다. Producer 같은 경우는 앞에서도 강조한 것처럼 acks 설정을 통해 조정한다. acks=0이라고 무조건 latency가 높다고 볼 순 없다. produce latency는 낮출 수 있지만, consumer가 놓칠 수 있으니 end to end latency가 좋아지지 않기 때문이다. DB에러 등으로 처리를 못하는 상황 같으면 pause()해서 추가 polling을 막거나 retry할 것을 다른 retry topic을 만들어서 거기에 쓰고 그것도 구독하는 등으로 해결할 수도 있다.
기본적으로 위에 나열된 방법으로 신뢰성을 보장 할 수 있지만 시스템 전체를 완전하게 신뢰성 있게 만들어 주지 못하여 트레이드 오프가 있고, 카프카는 트레이드 오프를 조정할 수 있도록 개발자 혹은 운영자가 설정 매개변수를 조절함으로써 어느 정도의 신뢰성이 필요한지를 결정 할 수 있도록 되어 있다.
카프카의 복제 메커니즘은 파티션별로 다수의 레플리카를 유지한다는 특성과 함께 신뢰성 보장의 핵심이다.
복제 중요 부분
❌주의 : in-sync replica 수가 줄어들면 파티션의 실질적인 복제 팩터가 줄어들면서 중단 시간이 길어지거나 데이터가 유실될 위험성이 높아진다.
모든 토픽들을 제어할 수도 있고 토픽 단위에서 적용되어 특정 토픽의 작동을 제어 가능하다.
토픽 단위에서 신뢰성 트레이드 오프를 제어 할 수 있다는 것은 신뢰성이 필요한 토픽과 아닌 토픽을 같은 클러스터에 저장할 수 있음을 의미한다.
중요하지 않은 데이터에 대해서는 복제 팩터를 3 미만으로 잡아 줘야한다.
토픽 단위 설정은 replication.factor, 자동으로 생선된 토픽들에 적용되는 브로커 단위 설정은 default.replication.factor
가용성
: 레플리카가 하나뿐인 파티션은 브로커를 재시작하면 작동 불능에 빠진다.
지속성
: 레플리카는 파티션 안의 모든 데이터의 복사본, 레플리카가 하나 뿐이고 디스크가 사용 불가능하면 파티션의 모든 데이터는 유실된다.
(복사본이 많을수록 데이터 유실 가능성이 줄어든다.)
처리량
: 레플리카가 추가될 때마다 브로커간 트래픽이 증가한다. (처리량 감소)
종단 지연
: 레플리카가 많을수록 이들 중 하나가 느려짐으로써 컨슈머까지 느려질 가능성이 높아진다.
비용
: 레플리카가 많을수록 저장소와 네트워크에 들어가는 비용이 증가한다. (복제 팩터를 보통 2로 잡는데 3인 경우에 비해 가용성이 줄어듬)
해당 설정은 브로커 단위에서만 가능하고 매개변수 이름은 unclean.leader.election.enable 이고 기본값은 false 이다.
클린 리더 선출
: 파티션의 리더가 더 이상 사용 가능하지 않을 경우 in-sync replica 중 하나가 새 리더가 된다.
언클린 리더 선출
: out-of-sync replica 중 하나가 새 리더가 된다.
Topic, Broker 단위 모두 min.insync.replicas 설정에서 잡을 수 있다.
클러스터의 민감도를 조절할 수 있는 브로커 설정을 가지고 있다.
세그먼트를 교체할 때, 재시작 직전에만 메세지를 디스크로 플러시하며, 그 외의 리눅스의 페이지 캐시 기능에 의존
가장 높은 신뢰성 설정을 브로커에 적용하더라도, 프로듀서 역시 신뢰성이 있도록 설정을 잡아주어야 한다. (데이터 유실 가능)
Producer 는 세 가지 응답 acknowledgement 모드 중 하나를 선택 가능하다.
acks = 0
acks = 1
acks = all
프로듀서 에러는 자동으로 처리해주는 에러, 라이브러리 사용하는 개발자들이 처리해야하는 에러 두개로 나뉜다.
컨슈머는 일관성이 보장되는 데이터만 읽는다.
파티션으로부터 데이터를 읽어 올 때, 컨슈머는 메세지를 배치 단위로 읽어온 뒤 배치별로 마지막 오프셋을 확인한 뒤 브로커로부터 받은 마지막 오프셋 값에서 시작하는 다른 메세지 배치를 요청한다. (데이터를 올바른 순서로 읽어온다.)
읽고 있는 각 파티션에 대해 어디까지 읽었는지 저장해 둬야 해당 컨슈머나 다른 컨슈머가 재시작한 뒤에도 어디서 작업을 계속 해야할지 알 수 있다.
필수 : 오프셋이 언제 어떻게 커밋되는지에 대해 신경써야 한다
신뢰성을 갖는 컨슈머를 설정하기 위한 속성은 네 개가 있다.
group.id
auto.offset.reset
earliest
: 파티션 맨 앞에서부터 읽기latest
: 파티션의 끝에서부터 읽기, 중복 처리는 최소화 하지만 메세지 누락 발생enable.auto.commit
auto.commit.interval.ms
세밀한 제어가 필요한 경우 정확성과 성능에 미치는 영향에도 신경써야한다.
메세지 처리 먼저, 오프셋 커밋은 나중에
: 아래에 세 가지로 오버헤드와 중복 처리 회피 사이의 요구 조건 균형을 맞춘다.
커밋 빈도는 성능과 크래시 발생시 중복 개수 사이의 트레이드 오프다
:
정확한 시점에 정확한 오프셋을 커밋
:
리밸런스
:
컨슈머는 재시도를 해야 할 수도 있다
:
컨슈머가 상태를 유지해야 할 수도 있다
:
세 개의 계층에 걸쳐서 검증을 수행할 것을 제안한다고 한다.
애플리케이션 로직과 격리된 브로커와 클라이언트 설정 검증
설정 검증 권장
선택한 구상이 요구 조건을 충족시킬 수 있는지 확인
시스템의 예상 작동을 추론해 보기 위한 좋은 방법
org.apache.kafka.tools 패키지에 해당 클래스로 검증 VerifiableProducer, VerifiableConsumer
VerifiableProducer에는 acks, retries, delivery.tiomeout.ms 등의 설정값을 잡아줄 수 있고 메세지를 쓰는 속도 역시 정해줄 수 있다.
테스트 고려 사항
리더 선출
: 리더를 정지시키면 어떻게 될지? 프로듀서와 컨슈머가 평상시처럼 작동을 재개하는데까지 얼마나 걸릴지?컨트롤러 선출
: 컨트롤러가 재시작한 뒤 시스템이 재개되는 데 얼마나 걸릴지?롤링 재시작
: 메세지 유실 없이 브로커들을 하나씩 재시작시킬 수 있을지?언클린 리더 선출 테스트
: out-of-sync 상태가 된 브로커를 시작시키면 어떻게 될지? 등테스트를 할때는 자제적인 프레임워크인 Trogdor(트록도르) 테스트 프레임워크를 포함
책에 나온 링크는 이전 링크라 아래에 남겨놓음 link : https://github.com/apache/kafka/tree/trunk/trogdor
클러스터의 상태를 모니터링 하는것 외에 클라이언트와 전체 데이터 흐름 역시 모니터링하는 것이 중요!!
컨슈머의 가장 중요한 지표는 컨슈머 랙이다.
버전 0.10.0 부터 모든 메세지는 이벤트가 생성된 시점을 가리키는 타임스탬프를 포함
신뢰성 있는
컨슈머, 프로듀서를 적절하게 시나리오에 따라 설정하는 것은 실제로 백엔드 현업자에게 매우 중요한 역량이다.
이번에 회사에서 랭킹시스템을 만들 때, 카프카를 극한으로 잘 활용할 수 있도록 각 퍼널을 설계하고, 기능에 대해 고려하는 것이 중요했는데 이미 현업의 다양한 Usecase 에서 카프카를 활용하고 있는 능력있는 미들 체급 개발자들 임에도 이 부분에서 많은 조언을 구해왔다.
예를 들면, 각 퍼널의 Throughput 이나 각 요인에 따른 Latency Delay 에 따라 메세지들을 적절하게 잘 제어할 수 있도록 설정하는 것, 처리 효율을 높이기 위해 이전 장에서 보았던 Compression
같은 테크닉을 컨슈머의 처리방식 설계를 통해 제어하는 것과 같은 데에서 알맞은 프로듀서/컨슈머 설계는 수십배에 달하는 성능 차이를 낼 수 있다.
보통은 컨슈머의 애플리케이션 처리 목적, 방식을 이해하고 이에 대해 신뢰성과 오프셋 관리, 이에 따른 하트비트 레이턴시 관리 등 성능에 직결되는 요인들을 튜닝하는 데에 집중하는 것을 매우 경시하는 경향이 있는데 이런 부분을 좀 잘 고려했으면 좋겠다.
특히, 프로덕션 환경의 신뢰성 모니터링 파트에서 나온 컨슈머 랙에 대한 이해도는 정말 중요하다. 컨슈머의 랙을 해소하기 위한 컨슈밍 동작 전략이라던지, 파티션 개수라던지 컨슈머가 도출해낼 RESULT
에 대한 신뢰도 및 실시간 성을 어떻게 보장할 것인지 등은 정말 개발자 순수 역량에 따라 달려있다. 단순히 랙을 해소하기 위해서 파티션을 늘린다? 그럼 뺨 맞아야지. 그럼 처리하려는 메세지에서 실제로 "처리가 필요하지 않은 것" 들을 스킵할 수 있도록 애플리케이션들을 어떻게 설계할 수 있을까? 등을 고려하는 개발자가 되길 바란다.
카프카와 함께 통합되는 시스템이 중요한 이유를 알 수 있는 챕터였다. 이전 챕터들에서도 알 수 있었지만, 카프카가 얼마나 분산, 분할, 복제를 신경쓰고 이를 통해 신뢰성을 얻고자 했는지 알 수 있었다. 우리가 트레이드 오프를 할 때 어떤 점을 고려해야 하는지 생각해보게 되었다.
유연성이 높은 만큼, 카프카를 사용하다 실수로 문제를 초래하기도 쉽다. 시스템의 신뢰성이 높다고 착각하기 때문이다.
착각하지 않도록 경계해야겠다.
이전 Consumer 챕터에서 언급했던 현재 회사에서 사용 중인 컨슈머 설정인데,
데이터를 유실하지 않기 위해 earliest
설정을 사용 중이다.
auto.offset.reset=earliest
메시지를 읽어올 때마다 커밋하는 방식은 매우 낮은 빈도로 메시지가 들어오는 토픽에나 사용할 수 있다.
아 이거 우리회사에서 딱이겠다 싶었다. 매우 낮은 빈도로 메시지가 들어오는 토픽... 카프카를 잘 사용 중이지만, 과연 카프카가 꼭 필요했는지 의문에 이르렀다.
이번 챕터를 읽으면서 느낀 것은 내용에 나와 있는 설정과 그 동작들에 대해 제대로 이해를 하지 못한 상태로 사용을 하게 된다면 얼마나 끔찍한 일이 벌어질 지 상상이 됐다. 사실 카프카에 대해 나 뿐만 아니라 주변 동료들에 대한 실력이 뒷밤침 되지 않으면 오히려 시스템 복잡도만 심해지고 오히려 기술 부채만 더 심해지는게 아닌가 하는 생각들이 맴돌았다. 이상.
~저는 사람이 아닙니다. 죄송합니다.~ 허재 : 그럴 수 있죠.
Chapter 7 Ownership : @kimsunhak