프로듀서는 카프카에 데이터를 저장하는 첫 단계이다.
카프카의 acks
옵션은 0, 1, all(또는 -1)값을 가질 수 있다. 이 옵션을 통해 프로듀서가 전송한 데이터가 카프카 클러스터에 얼마나 신뢰성 높게 저장할지 지정할 수 있다. acks
옵션에 따라 성능이 달라질 수 있으므로 acks
옵션에 따른 카프카의 동작 방삭을 자세히 알아야 한다.
acks
를 0으로 설정하는 것은 프로듀서가 리더 파티션으로 데이터를 전송했을 때 리더 파티션으로 데이터가 저장되었는지확인하지 않는다는 뜻이다. 리더 파티션은 데이터가 저장된 이후 데이터가 몇 번째 오프셋에 저장되었는지 리턴하는데, acks
가 0으로 설정되어 있다면 프로듀서는 리더 파티션에 데이터가 저장되었는지 여부에 대한 응답값을 받지 않는다.
프로듀서에서 데이터의 전송이 실패했을 때 재시도를 할 수 있도록 retries
옵션을 설정할 수 있는데, acks
가 0일 때 프로듀서는 전송을 하자마자 데이터가 저장되었음을 가정하고 다음 데이터를 전송하기 때문에 retries
가 2 이상으로 설정되어 있어도 재시도를 하지 않는다.
acks
를 0으로 설정했을 경우, 데이터가 유실되더라도 프로듀서는 리더 파티션으로부터 응답값을 받지 않기 때문에 지속적으로 다음 데이터를 보낸다. 그러므로 acks
0 옵션이 다른 옵션들보다 빠르다.
acks
를 1로 설정할 경우 프로듀서는 보낸 데이터가 리더 파티션
에만 정상적으로 적재되었는지 확인한다. 만약 리더 파티션에 정상적으로 적재되지 않았다면 리더 파티션에 적재될 때까지 재시도할 수 있다.그러나 리더 파티션에 적재되었음을 보장하더라도 팔로워 파티션에는 데이터가 동기화되지 않을 수 있기 때문에 데이터는 유실될 수 있다.
acks
를 all
또는 -1로 설정하는 경우 프로듀서는 보낸 데이터가 리더 파티션
과 팔로워 파티션
에 모두 정상적으로 적재되었음을 확인한다. 리더 파티션뿐만 아니라 팔로워 파티션까지 데이터가 적재되었는지 확인하기 때문에 0 또는 1 옵션보다 속도가 느리다. 그러나 일부 브로커에 장애가 발생하더라도 프로듀서는 안전한게 데이터를 전송하고 저장할 수 있음을 보장할 수 있다.
acks
를 all
로 설정할 경우에는 토픽 단위로 설정 가능한 min.insync.replicas
옵션값에 따라 데이터의 안정성이 달라진다. all
옵션값을 모든 리더 파티션과 팔로우 파티션의 적재를 뜻하는 것은 아니고 ISR
에 포함된 파티션들을 뜻하는 것이기 때문이다. min.insync.replicas
옵션은 프로듀서가 리더 파티션과 팔로워 파티션에 데이터가 적재되었는지 확인하기 위한 최소 ISR
그룹의 파티션 개수이다.
min.insync.replicas
를 설정할 때는 복제 개수도 함께 고려해야 한다. 왜냐하면 운영하는 카프카 브로커 개수가 min.insync.replicas
의 옵션값보다 작은 경우에는 프로듀서가 더는 데이터를 전송할 수 없기 때문이다. 복제 개수를 3으로 설정하고 min.insync.replicas
를 3으로 설정한 것을 예로 들 수 있다. 브로커 3대 중 1대에 이슈가 발생하여 동작하지 못하는 상황이 생기면 프로듀서는 데이터를 해당 토픽에 더는 전송할 수 없다. 왜냐하면 최소한으로 복제되어야 하는 파티션 개수가 3개인데 팔로워 파티션이 위치할 브로커의 개수가 부족하기 때문이다.
min.insync.replicas
옵션을 설정할 때 추가로 주의해야 할 점은 절대 보르커 개수와 동일한 숫자로 설정하면 안 된다는 것이다. 브로커 3대로 클러스터를 운영하면서 min.insync.replicas
옵션을 3으로 설정하는 경우를 예로 들 수 있다. 이런 상황에서 카프카 클러스터의 버전 업그레이드와 같은 상황이 발생하면 브로커는 롤링 다운 타임이 생기는데, 브로커가 1대라도 중단되면 프로듀서가 데이터를 전송할 수 없다. 왜냐하면 min.insync.replicas
가 3일 경우에는 최소한 브로커가 3대 이상 실행 중이여야 3개의 복제본이 생기는 것을 만족할 수 있기 때문이다. 그러므로 토픽별 min.insync.replicas
옵션 값은 브로커 개수 미만으로 설정해야 한다.
프로듀서가 데이터를 가장 안정적으로 보내려면 토픽의 복제 개수는 3, min.insync.replicas
를 2로 설정하고 프로듀서는 acks
를 all
로 설정하는 것을 추천한다.
멱등성이란 여러 번 연산을 수행하더라도 동일한 결과를 나타내는 것을 뜻한다. 멱등성 프로듀서는 동일한 데이터를 여러 번 전송하더라도 카프카 클러스터에 단 한 번만 저장됨을 의미한다.
enable.idempotence
옵션을 사용하여 정확히 한번 전달을 지원한다. enable.idempotence
옵션의 기본값은 false
이며 정확히 한번 전달을 위해서는 true
로 옵션값을 설정해서 멱등성 프로듀서로 동작하도록 만들면 된다. 멱등성 프로듀서는 기본 프로듀서와 달리 데이터를 브로커로 전달할 때 프로듀서 PID
와 시퀀스 넘버를 함께 전달한다. 단, 멱등성 프로듀서는 동일한 세션에서만 정확히 한번 전달을 보장한다. 여기서 말하는 동일한 세션이란 PID
의 생명 주기이다. 만약 멱등성 프로듀서로 동작하는 프로듀선 애플리케이션에 이슈가 발생하여 종료되고 애플리케이션을 재시작하면 PID
가 달라진다. 동일한 데이터를 보내더라도 PID
가 달라지면 브로커 입장에서 다른 프로듀서 애플리케이션이 다른 데이터를 보냈다고 판단하기 때문에 멱등성 프로듀서는 장애가 발생하지 않을 경우에만 정확히 한번 적재하는 것을 보자한다는 점을 고려해야 한다.
멱등성 프로듀서를 사용하기 위해 enable.idempotence
를 true
로 설정하면 정확히 한번 적재하는 로직이 성립되기 위해 프로듀서의 일부 옵션들이 강제로 설정된다. retries
는 Integer.MAX_VALUE
로 설정되고 acks
옵션은 all
로 설정된다.
멱등성 프로듀서의 시퀀스 넘버는 0부터 시작하여 숫자를 1씩 더한 값이 전달된다. 브로커에서 멱등성 프로듀서가 전송한 데이터의 PID
와 시퀀스 넘버를 확인하는 과정에서 시퀀스 넘버가 일정하지 않은 경우 OutOfOrderSequenceException
이 발생할 수 있다.
트랜잭션 프로듀서는 다수의 파티션에 데이터를 저장할 경우 모든 데이터에 대해 동일한 원자성을 만족시키기 위해 사용된다. 트랜잭션 프로듀서를 사용하려면 enable.idempotence
를 true
로 설정하고 transactional.id
를 임의의 String
값으로 정의한다. 그리고 컨슈머의 isolation.level
을 read_committed
로 설정하면 프로듀서와 컨슈머는 트랜잭션으로 완료된 데이터만 쓰고 읽게 된다.
트랜잭션은 파티션의 레코드로 구분한다. 트랜잭션 프로듀서는 사용자가 보낸 데이터를 레코드로 파티션에 저장할 뿐만 아니라 트랜잭션의 시작과 끝을 표현하기 위해 트랜잭션 레코드를 한 개 더 보낸다. 트랜잭션 컨슈머는 파티션에 저장된 트랜잭션 레코드를 보고 트랜잭션이 완료되었음을 확인하고 데이터를 가져간다.