KafkaConsumer (소비자) 각 폴 호출 () 메소드는 항상 생산자에 의해 작성된 기록 카프카를 반환하지만 아직 소비자 읽지 않은, 따라서 우리는 기록이 그룹있는 추적 할 수있는 소비자의 누가 읽어 보시기 바랍니다. 앞에서 설명한, 카프카는 고유 카프카의 인 다른 JMS 큐처럼 소비자로 확인 할 필요가 없습니다. 대신, 사용자가 메시지를 파티션에서 카프카 위치 (오프셋)를 추적하는 데 사용할 수 있습니다.
우리는 현재 운영 위치의 파티션이 제출라고 업데이트합니다.
그래서 소비자가 메시지를 보낼 오프셋이? 특별 테마 소비자 _consumer_offset 호출에 의해 작성 방법, 메시지는 각 파티션의 오프셋 (offset)가 포함되어 있습니다. 소비자가 실행 된 경우, 거의 사용 오프셋. 요금은 조용한 충돌하거나 그룹에 가입 할 수있는 새로운 소비자 인 경우 그러나, 그것은 재조정 완료 후, 모든 소비자가 새 파티션에 할당하고, 처리되지 전에 해당 할 수있다, 재조정을 트리거합니다. 이전 작업을 계속 할 수 있도록하기 위해, 소비자는 각 파티션의 마지막 제출의 오프셋을 읽은 다음 오프셋 지정된 장소에서 처리를 계속해야합니다.
오프셋보다 작 으면 마지막 오프셋 클라이언트를 처리하는 메시지 전송, 메시지는도 4-6에 나타내는 공정을 반복 될 것 둘 사이에 오프셋된다.
자동 커밋
가장 쉬운 방법은 조용한 수수료가 자동으로 오프셋 제출 제출하는 것입니다. enable.auto.commit가 true, 다음 각 5 초에 설정되어있는 경우, 소비자는 자동으로 넣어 것입니다 () 메소드는 설문 조사로부터 제출 최대 오프셋을받습니다. 제어 시간 간격에 의해 제출 된 Auto.commit.interval.ms, 기본값은 5 초입니다. 다른 것들에 소비자는 자동 제출처럼 내부 설문 조사 (설문 조사 ())에서 수행된다. 소비자는 오프셋이 제출 여부를 각각 조사하는 동안 확인됩니다, 그래서 경우, 반환에 대한 설문 조사에서 오프셋을 제출합니다.
그러나이 간단한 방법을 사용하기 전에, 그 결과 어떤 종류를 알아야합니다. 우리는 여전히 기본 5 초 시간 간격을 커밋 사용하는 가정, 재조정 재조정 후, 소비자가 커밋에게 마지막의 오프셋 위치에서 메시지를 읽기 시작, 마지막으로 제출 한 후 3 초에서 일어났다. 오프셋이 시간은 이미 3 초 뒤에, 그래서 범위 내에서이 메시지 3S는 반복됩니다. 반복 메시지가 발생할 수있는 시간 창을 줄이고, 더 자주 제출 오프셋 시간 간격을 수정하여 신청하지만,이 상황은 완전히 피할 수 없습니다.
자동 제출을 사용하는 경우, 각 다시 최고의 호출하기 전에 현재의 모든 호출이 반환을 보장하기 때문에이 메시지가 처리 된을 정확하게 모르는, 파티 분위기는 마지막 호출에 제출할 반환 오프셋됩니다 폴링 전화 메시지 (자동 close () 메소드를 호출하기 전에 제출 함) 처리되었다. 예외 또는 조기 종료 폴링을 처리 할 때 정상적인 상황에서 문제가되지 않습니다,하지만 조심.
자동 제출은 편리하지만, 개발자가 복제 과정에게 메시지를 방지하기위한 공간을 확보하지 않습니다.
현재의 오프셋 (offset)에 제출
손실 메시지의 가능성을 제거하기 위해 오프셋 시간을 조절하여 제출 대부분의 개발자는, 우물은 재조정의 경우에 중복 메시지의 수를 줄일 수 있습니다. 소비자의 API는 개발자가 시간 간격에 따라 필요한 경우 현재의 오프셋 판을 제출하기보다는 수, 오프셋을 제출하는 또 다른 방법을 제공합니다.
자동 제출, false로 설정 auto.commit.offset 취소, 응용 프로그램은 오프셋 제출시기를 결정합니다. commitSync ()를 사용하는 가장 쉽고 안정적인 오프셋 제출. 이 API는 설문 조사 () 메소드에 의해 제출 될 것이다는이 예외가 발생합니다 제출하지 않을 경우, 즉시 성공적인 복귀를 제출 한 후, 최신의 오프셋 (offset)를 돌려줍니다.
() 설문 조사 (에 의해 제출 될 것입니다)이 오프셋 최신 반환, 그래서 모든 레코드를 처리 한 후 commitSync ()를 호출하거나, 그렇지 않으면 메시지를 잃는 위험을 감수해야하는, commitSync을 기억하십시오. 이 다시 균형 발생하면 재조정 사이의 모든 메시지에 대한 메시지의 가장 최근의 배치는 반복됩니다 일어난다.
여기에 오프셋 제출 우리가 메시지의 배치 () 메소드를 처리 한 후 가장 최근의 commitSync를 사용하는 예입니다.
비동기 제출
동기화가있다가, 응용 프로그램이 차단되었습니다,이 응용 프로그램의 처리량을 제한 할 것이다 제출 요청에 응답하기 위해 브로커 전에 결함을 제출합니다. 우리는 주파수를 줄여 처리량을 개선하기 위해 제출할 수 있습니다, 그러나 않는 경우 재조정 중복 메시지의 수를 증가 할 것이다.
이 시간은 비동기 API를 사용하여 제출 할 수있다. 우리는 응답 브로커을 기다리지 않고, 제출 요청을 보냈습니다.
commitAsync는 ()는 콜백을 지원하는 경우 콜백을 수행하기 때문에 중요성과 우리가이 문제를 언급하는 이유의 제출의 순서의 복잡성, 브로커를 응답합니다. 콜백은 종종 기록하거나 버그를 제출 메트릭을 생성하는 데 사용됩니다,하지만 당신은 제출 순서에주의를 지불해야합니다 다시 시도를 사용하는 경우.
비동기 전송 재시도
우리는 순서 비동기 적으로 제출을 유지하기 위해 일정하게 증가하는 시퀀스 번호를 사용할 수 있습니다. 각 커밋 후에 오프셋 또는 콜백 오프셋 제출할 때 일련 번호를 증가. 재 시도를 수행하기 전에, 콜백의 일련 번호를 확인하고는 새로운 제출, 안전하게 시도 할 수없는 것을 나타내는, 동일한 경우는 제출 오프셋은 동일하다. 일련 번호가 발송 된 새 제출이 있음을 나타내는 비교적 큰 경우에는 중지하고 다시 시도해야합니다.
동기 및 비동기의 조합을 제출
커밋 경우는 일시적인 문제는 그것이 후속 항상 성공적이 될 것이다 제출 발생하기 때문에 실패하기 때문에 일반적으로 제출 가끔 실패, 더 시도는 큰 문제가되지 않을 것입니다. 이 재조정하기 전에 소비자의 가까운 또는 마지막 제출에 일어나는 경우에, 우리는 제출이 성공하는지 확인해야합니다.
따라서, 소비자들은 일반적으로 조합 commitAsync () 및 commitSync에 사용하기 전에 폐쇄된다 (). 그들은 (청취자 나중에 재조정에 대해 이야기 할 때, 우리는 재조정이 발생하기 전에 오프셋을 제출하는 방법에 대해 설명합니다) 다음과 같이 작동합니다 :
특정 제출 오프셋 (offset)
주파수 처리부 주파수 오프셋 메시지 일괄 제출 동일하다. 더 자주 제출 싶다면 어떻게 할까? 만약 여론 조사 () 메소드의 원인이 당신이 수행하는 방법의 중간에 오프셋 배치를 제출하고자하는 메시지의 전체 배치를 재조정의 적법 절차의 중복을 방지하기 위해, 데이터의 큰 숫자를 반환? 이 상황은 그들 만 마지막되는 메시지의 일괄 처리되지 않은 포인트, 제출 오프셋 때문에, commitSync () 또는 commitAsync ()를 호출하여 달성 될 수 없다.
다행히도, API는 소비자가 파티션에 전달할 수 있습니다 그리고 당신이 commitSync ()와 commitAsync () 메서드를 호출 할 때지도를 제출하려는 오프셋. 당신이 메시지의 절반 일괄 처리 가정, 오프셋 영역에서 마지막 테마 "고객"메시지는 5000 3, 당신은 그것을 커밋 commitSync () 메서드를 호출 할 수 있습니다. 소비자는 파티션을 읽을 수 있기 때문에,이 수준의 제어 오프셋 제출 복잡한 코드를 만드는에 있으므로, 모든 파티션을 상쇄 추적 할 필요가있다.
특정의 예를 제출 오프셋 :
리 밸런싱 리스너
오프셋의 제출에 언급, 종료 및 재 파티션 평형 전에 소비자는 어떤 청소 작업을 할 것입니다.
당신은 파티션의 소유권이 소비자를 상쇄하기 전에 최종 기록이 처리 된 제출 잃게됩니다. 소비자가 가끔 이벤트를 버퍼를 처리 할 준비가되어있는 경우, 소유권을 상실하기 전에 파티션은 버퍼에 축적 된 기록에 해결 될 필요가있다. 또한 파일 핸들, 데이터베이스 연결을 종료해야합니다.
새 파티션을 할당하거나 소비자에게 기존의 파티션을 제거하면, 소비자 API를 통해 일부 응용 프로그램 코드를 수행 할 수있는 그것의 () 메소드 ConsumerRebalancelistener 예를 구독 호출시에 전달합니다. ConsumerRebalancelistener는 두 가지 방법이 구현 될 필요가있다.
(1) 공공 무효 재조정이 시작되기 전에 중지 뉴스와 소비자를 읽은 후 (컬렉션 파티션) 메소드가 호출됩니다 onPartitionsRevoked. 여기에 오프셋 제출할 경우 소비자가 읽기 시작 위치를 알의 다음 파티션을 인수합니다.
파티션의 재 할당 후 메시지를 읽기 시작합니다 (2) 공공 무효 onPartitionsAssigned (컬렉션 파티션) 방법과 소비자 전에 호출된다.
다음 예는 onPartitionsRevoked () 파티션의 소유권을 잃기 전에 방법에 의해 상쇄 제출하는 방법을 보여줍니다. 다음 섹션에서, 우리는 예 onPartitionsAssigned () 메소드의 또 다른 사용 방법을 설명합니다.
처리는 기록에서 특정 오프셋에서 시작
지금까지, 우리는 메시지를 처리하기 시작 각 파티션의 오프셋 (offset) 최근의 여론 조사 () 메서드를 사용하는 방법을 알고있다. 그러나 때때로 우리는 오프셋 특정 메시지를 읽기 시작해야합니다.
당신은 파티션의 시작 위치에서 메시지를 읽기 시작하거나 메시지를 시작 파티션의 끝으로 직접 이동하려면 seekToBeginning (컬렉션 TP)와 seekToEnd (컬렉션 TP)이 두 가지 방법을 사용할 수있다.
그러나 카프카는 우리가 특정 오프셋 API를 찾는 데 사용합니다. 그러한 후방이나 여러 메시지는 순방향 (순방향 메시지를 스킵 할 수 히스테리시스 다수의 처리의 경우 원하는 시간에 민감한 애플리케이션) 여러 메시지 롤백 이동 많은 용도를 갖는다. (가) 오프셋 저장 카프카가 아닌 다른 시스템을 사용하는 경우, 그것은 우리에게 큰 놀라움을 줄 것이다.
이 시나리오를 상상 : 응용 프로그램이 다음 데이터베이스에 결과를 저장 (아마도 세션 정보를 추가 할 수도 클릭을 정리하기 위해 자동화 된 프로그램을 사용)을 처리하기 위해, 카프카의 이벤트를 읽고 (사용자가 될 수있는 이벤트 흐름의 사이트를 클릭) NoSQL의 스토리지 엔진이나 하둡. 우리가 정말 모든 데이터를 잃고 싶지 않아 가정뿐만 아니라 동일한 결과가 반복적으로 데이터베이스에 저장하지 않습니다.
이 경우, 소비자 코드는 다음과 같습니다
기록 - 보관 및 오프셋이 원자 작동 할 수있는 경우, 위의 상황은 피할 수있다. 기록과 하나가 성공적으로 제출 제출하거나되지 않은 오프셋. 레코드가 데이터베이스에 저장하고, 카프카에 제출 오프셋 경우, 그것은 원자 작업을 구현할 수 없습니다.
그리고 레코드에 동일한 트랜잭션이 데이터베이스에 기록됩니다 오프셋 경우, 다음이 일어날까요? 그리고 우리는 기록을 알고 하나가 성공적으로 제출하거나, 다음 녹화를 다시 처리되지 않은 오프셋 수 있습니다.
문제는 지금 : 오프셋 데이터베이스보다는 카프카에 저장된 경우, 소비자 () 메서드를 추구 사용할 수있는이 시간을 읽기 시작하는 곳에서 새 파티션을 얻는 방법을 알 수 있도록? 소비자가 시작하거나 새 파티션에 할당하는 경우, 당신은이 데이터베이스에 저장된 오프셋을 찾기 위해 () 메소드를 추구 사용할 수 있습니다.
다음 예는 거의 API를 사용하는 방법을 보여줍니다. ConsumerRebalancelistener를 사용하여 우리가 메시지를 처리 시작에 의해 지정된 데이터베이스 오프셋 위치에서 저장되는 것을 보장하기 위해 () 측 전투를 추구합니다.
어떻게 종료하는 방법
투표 전에 토론 중에 말씀하신, 소비자가 무한 루프에 폴링 메시지에 대해 걱정할 필요가 없습니다, 우리는 어떻게 우아하게 루프를 종료하는 소비자에게 말할 것이다.
당신이주기를 종료하려면 다른 스레드에 의해 consumer.wakeup () 메소드를 호출해야합니다. 주기가 메인 스레드에서 실행되는 경우,이 방법 ShutdownHook 년 호출 할 수 있습니다. consumer.wakeup () 메소드는 다른 스레드에서 호출 소비자를 확보 할 수있는 유일한 사람입니다 기억하십시오. ) (슬로우 호출 consumer.wakeup () 출구 조사 () 및 WakeupException에 이상 던져, 또는 스레드가 폴링 호출 cconsumer.wakeup () 대기하지 않는 경우는 예외가 설문 조사를 호출하는 다음 라운드에있을 것입니다. 이 루프에서 점프하는 단지 방법이기 때문에 우리는 WakeupException 처리 할 필요는 없습니다. 종료 스레드가 consumer.close ()가 필요하다 호출하기 전에 그러나, 아직 아무것도 제출 최선을 다하고, 그들은 그룹을 떠날 필요가 그룹 코디네이터 (브로커) 메시지를 전송되며, 다음 단계 이 세션 제한 시간을 기다리지 않고, 재조정을 트리거합니다.
다음은 스레드 종료 코드의 메인 스레드에서 소비자입니다.