티스토리 뷰

멱등성이란?

전달 신뢰성으로 여러번 연산을 수행하더라도 동일한 결과를 나타내는 것을 뜻한다. 따라서 이러한 멱등성 프로듀서는 동일한 데이터를 여러번 전송해도 카프카 클러스터에 단 한번만 저장되게 된다.

반면에, 기본 프로듀서의 동작 방식은 적어도 한번 전달(at least once delivery)를 지원한다. 여기서 적어도 한번 전달이란 프로듀서가 클러스터에 데이터를 전송하여 저장할 때 적어도 한번 이상 데이터를 적재할 수 있고 데이터가 유실되지 않음을 의미한다. 하지만 두 번 이상 적재할 가능성이 있으므로 데이터의 중복이 발생할 수 있다.

 

메시지 전달에는 아래와 같이 3가지의 경우가 존재한다.

  • at least once: 적어도 한번 이상 전달
  • at most once: 최대 한번 전달
  • exactly once: 정확히 한번 전달

멱등성 프로듀서

프로듀서가 보내는 데이터의 중복 적재를 막기 위해 프로듀서에서 제공하는 기능이다. enable.idempotence 옵션을 사용하여 Exatly once delivery (정확히 한번 전달)을 지원한다. 해당 옵션의 default는 false이며 true로 설정 시 멱등성 프로듀서로 동작한다.

참고로 카프카 3.0.0 부터는 기본 값이 해당 옵션이 true + acks = all)로 변경되므로 주의하자!

  • 앞에서 말했듯 acks가 all이 되면 팔로워 프로듀서의 적재여부를 모두 확인하게 되므로 처리성능의 저하가 있을 수 있다
멱등성 프로듀서의 동작

일반 프로듀서와 다르게멱등성 프로듀서는 데이터를 브로커로 전달할 때 프로듀서 PID & 시퀀스 넘버를 함께 전달한다. 따라서 브로커는 프로듀서 PID & 시퀀스 넘버를 확이낳여 동일한 메시지의 적재 요청에 대해 단 한번만 적재하도록 하여 exactly once로 동작한다.

  • PID: 프로듀서의 고유한 ID
  • 시퀀스 넘버: 레코드의 전달 번호 ID

멱등성 프로듀서가 아닌 경우

프로듀서에서 send()를 통해 메시지를 보내어 파티션에 적재되었음에도 acks를 받지 못하여 재송신하여 중복 적재될 가능성이 존재한다. (강사님 왈 흔한 상황은 아니니 너무 걱정은 하지말자) 이때 멱등성 프로듀서의 경우 시퀀스 ID가 이미 존재하므로 중복 적재를 하지 않게 된다.

멱등성 프로듀서의 한계

그렇다면 전부 멱등성 프로듀서로 하면 되지 않나 싶을 수 있다. 하지만 멱등성 프로듀서에도 한계점이 존재한다.

멱등성 프로듀서는 동일한 세션에서만 정확히 한번 전달을 보장한다. 여기서의 동일한 세션이란 PID의 생명주기를 뜻하며, 만약 멱등성 프로듀서로 동작하는 애플리케이션에 이슈가 발생하여 재시작하는 경우 PID가 달라지게 된다. 이렇게 되면 동일한 데이터를 보내도 PID가 다르므로 중복 적재가 이뤄지게 된다.

멱등성 프로듀서로 설정할 경우 옵션

멱등성 프로듀서를 사용하기 위해 enable.idempotence = true로 설정하게 되면 정확히 한번 전달 보장을 위해 프로듀서의 일부 옵션들이 강제로 설정된다.

  • 데이터 재전송 횟수를 정하는 retries의 기본값이 INT.MAX_VALUE 로 설정된다.
  • 리더 파티션 및 팔로워 파티션의 데이터 적재를 확인하는 ACKS의 옵션이 ALL로 설정된다.

이렇게 설정되는 이유는 적어도 한번 이상 데이터를 보내어 브로커에 정확히 한번 적재되는 것을 보장하기 위해서이다. 즉, 정확히 한번 적재되는 것을 보장하지, 정확히 한번 보내는 것이 아니다. 따라서 여러번 전송으로 인한 프로듀서 및 네트워크의 부담 및 ACKS 설정 등으로 인한 속도의 저하가 불가피하다.

멱등성 프로듀서 사용시 오류 확인

멱등성 프로듀서의 시퀀스 넘버는 0부터 시작하여 숫자를 1씩 더한 값이 전달된다. 이때 시퀀스 넘버를 확인 할 때 일정한 증가가 깨지는 경우 OutOfOrderSequenceException이 발생할 수 있다. 이 오류는 브로커가 예상한 시퀀스 넘버와 다른 번호의 시퀀스 데이터 적재 요청이 온 경우 발생하게 된다. 즉, 데이터의 역전 현상이 발생할 수 있기 때문에 순서가 중요한 데이터를 번송하는 프로듀서의 경우 적절한 대응 로직을 고려해야한다.

이때 브로커에서 데이터를 처리하는 컨슈머에서 멱등성 있게 처리한다면 굳이 멱등성 프로듀서를 설계하지 않아도 되므로 더 좋은 아키텍쳐를 설계할 수 있으니 고민하자.


트랜잭션 프로듀서 & 컨슈머

트랜잭션은 어떤 개별의 요소들을 하나의 atomic한 데이터로 활용하는 것을 의미하며 이를 위해서는  트랜잭션 프로듀서로 동작하도록 해야한다. 카프카에서 다수의 파티션에 데이터를 저장할 때 해당 모든 데이터들에 대해 하나의 원자성을 만족하는 것을트랜잭션이라고 지칭한다. 원자성을 만족시킨다는 것은 다수의 데이터를 동일 트랜잭션으로 묶는다라는 것이며, 트랜잭션 프로듀서와 트랜잭션 컨슈머로 구현할 수 있다.

트랜잭션 프로듀서는 사용자가 보낸 데이터를 파티션에 저장하고, 추가적으로 트랜잭션의 시작과 끝을 표현하기 위한 트랜잭션 레코드를 하나 더 보낸다.

트랜잭션 컨슈머의 동작

트랜잭션 컨슈머는 파티션에 저장된 데이터를 바로 꺼내지 않는다. 파티션에 저장된 트랜잭션 레코드를 보고 트랜잭션이 완료, 즉 commit 되었음이 확인 된 데이터만 가져가게 된다.

트랜잭션 프로듀서 / 컨슈머 설정

트랜잭션 프로듀서로 동작하기 위해서는 transactional.id 만 설정하면 된다. 이때 값은 프로듀서 별로 고유한 ID 값이여야 함을 주의하자. init, begin, commit 순서대로 수행되어야 한다. 트랜잭션 단위로 전달을 원하는 데이터(목록)를 begin 이후 보낸 후 commit 하면 된다.

트랜잭션 컨슈머는 커밋이 완료된 레코드만 읽기 위해 isolation.level = read_commited로 설정만 해주면 된다. 기본 값은 read_uncommited로 커밋 여부와 상관 없이 계속 모든 데이터를 읽게 된다. read_commited로 설정된 컨슈머는 커밋이 완료된 레코드들만 읽어들인다.

반응형
Comments
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday