공부하고 기록하는, 경제학과 출신 개발자의 노트

학습일지/architecture

KakaoTechMeet - 신뢰성 있는 kafka application을 만드는 3가지 방법

inspirit941 2024. 11. 21. 13:57
반응형

https://youtu.be/7_VdIFH6M6Q?si=elt0JfJEcTO9i3tj

 

 

스크린샷 2024-11-20 오후 5 38 01

 

Event Driven Architecture / Stream Data pipeline

스크린샷 2024-11-20 오후 5 38 34스크린샷 2024-11-20 오후 5 38 55

 

이벤트 또는 메시지 기반 메시지 전달의 신뢰성 확보하기.

  • Exactly Once: 이벤트 발행 / 처리를 1회만 수행.
  • At least Once: 장애 데이터가 중복으로 적재 / 처리될 수 있음.
  • At most Once: 장애 등으로 데이터가 유실될 수 있으나, 중복은 발생하지 않음.

스크린샷 2024-11-20 오후 6 09 52

 

kafka 구조 간단 소개

  • Producer: kafka 최소단위인 Record를 Broker로 전달
    • 데이터가 제대로 전달되었는지 ACK로 확인
  • Consumer: broker에 저장된 Record를 가져감.
    • 데이터를 정상적으로 받았는지 Offset commit으로 전달.
  • 데이터 담는 공간인 topic / partition.
  • 정상적으로 데이터가 전달되었는지는 offset으로 확인함.

1. Producer의 메시지 전달 신뢰도 확보

스크린샷 2024-11-20 오후 6 23 09

 

Producer가 특정 topic 특정 partition으로 record 저장할 때, ACK를 받는다.

  • 만약 ACK가 네트워크 장애로 유실될 경우.. 같은 데이터를 여러 번 저장할 수 있음
  • 이 문제는 멱등성 프로듀서 - Idempotence producer 로 해결.

스크린샷 2024-11-20 오후 6 23 33

 

producer 옵션의 enable.idempotence=true 로 설정해준다.

  • 3.0부터는 default true
  • record를 전달할 때 PID(producer unique id) + Sequence Number를 같이 전달함.
  • broker는 PID와 Seq 가지고 있다가 중복 적재요청이 오면, 이후에 들어온 건 적재하지 않는다.

이거 true 설정하면 acks=all이 활성화된다. kafka의 모든 리더/팔로워에 분산저장되었는지 확인해야 중복 방지가 되기 때문.

  • 일반적으로 acks=all은 acks=0 (kafka 적재 확인하지 않음), acks=1(리더에 적재 확인) 보다 느리다.
  • acks=1과 동일한 성능을 내려면
    • max.in.flight.requests.per.connection=3 설정하고
    • async producer 사용
    • 의미: producer의 sender가 connection 개수만큼 병렬로 record를 전달 + ACK 응답을 동기로 받지 않음.

스크린샷 2024-11-21 오전 10 20 59

 

2. Topic to Topic의 메시지 전달

스크린샷 2024-11-21 오전 10 21 30스크린샷 2024-11-21 오전 10 29 19

 

예컨대 광고시스템의 경우

  • 사용자의 광고 클릭 로그를 받아서
  • 광고주에게는 비용 청구를
  • 매체사에게는 CPC 수익을 나누는 로직이
  • Atomic하게 수행되어야 한다.

스크린샷 2024-11-21 오전 10 31 04

 

만약 광고 클릭로그를 수집해서 B topic으로 전달하는 앱에 문제가 생겨서 이벤트 중복이 발생한다?

  • 광고주에게 비용이 두 번 청구되거나
  • 매체사에게 CPC 수익을 두 번 전달하게 될 수 있음.ㅓ

즉, 두 개의 프로세스를 하나의 Transaction으로 묶어야 한다

  • 광고 클릭로그를 topic에서 Consume + Offset commit 전달
  • record를 B topic으로 전달

스크린샷 2024-11-21 오전 10 57 37

 

Transaction을 선언하고, 내부 로직에 Producer와 Consumer 로직을 동시에 정의한 모습.

  • 특이점: 일반적으로는 Consumer가 commit offset 수행하지만, Producer에 transaction을 걸어두고 로직을 수행할 땐 producer가 sendOffsetsToTransaction() 메소드에서 commit offset까지 수행한다.

스크린샷 2024-11-21 오전 11 00 14

 

transaction이 commit되지 않으면, Consumer도 다음 작업을 수행하지 않도록 한다

  • Consumer의 isolation level을 read_committed로 변경.
    • default는 read_uncommitted. commit여부와 관계없이 topic에 올라온 record는 읽는다.

이렇게 만들면 처리속도에 문제는 없나? 라고 생각할 수 있는데, 외부자료나 내부테스트 결과에 따르면

  • Producer: 대략 3% 낮은 성능.
  • Consumer: 어차피 commit된 record만 읽는 거라 성능하락이 있진 않음

대신 commit완료까지는 기다려야 하기 때문에 End-to-End Latency는 증가할 수 있다.

3. Consumer의 중복 적재 방지

스크린샷 2024-11-21 오후 1 27 44

 

2번처럼 transaction으로 묶는 방식은 Topic to Topic인 경우에 해당함.

Consumer가 kafka topic 말고 다른 작업(i.e. DB로직) 을 수행할 경우 Transaction으로 묶기는 어렵다.

Transaction 말고 다른 방법으로 세 가지 제안.

스크린샷 2024-11-21 오후 1 29 36

 

Unique Key 활용한 멱등성 컨슈머.

  • Oracle / Mysql 등의 DB
  • Record Key를 DB unique Key로 지정.

스크린샷 2024-11-21 오후 1 35 29

 

Upsert 활용. 중간결과값인 Window Result도 DB에 저장.

스크린샷 2024-11-21 오후 1 36 13

 

Write-ahead log 활용

  • transaction 만들기 전에 Log 기록 -> 적재 과정을 Atomic하게 관리.
  • 어디까지 적재했는지를 WAL 파일로 관리함.
  • Record Offset 관리 등이 필요해서 로직이 복잡해질 수 있다.

세 가지 다 적재성능은 큰 차이 없다.

정리

스크린샷 2024-11-21 오후 1 38 18

 

  • idempotent Producer 활용
  • Transaction Consumer / Producer
  • DB저장할 때는 unique key / Upsert / WAL 등을 활용.

내부활용 사례

스크린샷 2024-11-21 오후 1 39 59

 

스마트 메시지 서비스

  • 톡채널에 소재최적화, 타겟최적화 활용해서 적합한 광고를 소비자에게 전달하는 서비스
  • kafka streams / MongoDB 사용.

스크린샷 2024-11-21 오후 1 41 04스크린샷 2024-11-21 오후 1 42 38

 

이벤트 하나하나마다 실행하는 게 아니라, Tumbling window 단위로 묶어서 MongoDB에 저장함.

  • 일정 주기마다 계산 -> 타겟팅 확인.
  • MongoDB에 upsert 방식으로 저장. upsert에 활용할 unique key로는 Window key 사용함.
    • kafka streams의 경우, commit할 때마다 window의 중간 기록이 output으로 나옴.
    • 최종 window data만 원한다면 suppress 메소드 등이 필요하지만, 중간기록을 upsert로 저장하고 최종기록도 upsert로 저장할 수도 있음

마무리

스크린샷 2024-11-21 오후 1 44 57

 

  • 위 모든 예시는 자바 기준, 다른 언어와 라이브러리에서는 확인 필요
  • 메시지 전달 신뢰성 테스트는 재현이 까다롭다.
  • topic to topic의 경우 단일 kafka cluster를 상정했음. 서로 다른 kafka cluster 간 연동에는 다른 관점이 필요하다.
반응형