카프카 시스템의 사용자를 카프카 클라이언트라고 부른다. 기본은 프로듀서와 컨슈머 둘이고, 카프카 커넥트와 카프카 스트림즈 같은 고급 클라이언트도 이 둘을 기본 요소로 쓰면서 더 고차원적인 기능을 얹은 것이다.
쓰는 쪽과 읽는 쪽
프로듀서는 새로운 메시지를 만든다. 발행자, 작성자로도 불린다. 기본적으로 토픽에 속한 파티션들 사이에 고르게 쓰고, 특정 파티션을 지정하고 싶으면 파티셔너를 쓴다.
컨슈머는 발행된 메시지를 읽는다. 구독자, 독자로도 불린다. 하나 이상의 토픽을 구독해서 각 파티션에 쓰여진 순서대로 읽고, 오프셋을 기록해 어디까지 읽었는지 유지한다. 읽는다고 메시지가 사라지지는 않는다.
오프셋 커밋과 개별 응답의 차이
전통적인 발행 구독 시스템에서 컨슈머는 각 메시지마다 응답을 보낸다. 카프카는 오프셋을 커밋할 뿐 개별 메시지에 응답하지 않는다.
여기서 나오는 결과가 있다. “이 메시지 하나만 실패했다”를 표현할 방법이 없다. 오프셋은 “여기까지 다 했다”는 선이라서 중간에 구멍을 낼 수 없다.
실패한 레코드의 재시도
그래서 재시도가 두 갈래로 갈린다. 동기 방식은 성공한 마지막 레코드의 오프셋을 커밋하고, 나머지는 버퍼에 담고 pause()로 추가 poll()이 데이터를 리턴하지 않게 막은 뒤 처리를 계속한다. 비동기 방식은 별도의 재시도 토픽(dead letter queue)에 메시지를 발행하고 기존 처리는 그대로 진행한다.
poll() 사이에 유지해야 하는 상태
poll() 호출 사이에 상태를 유지해야 하는 경우가 있다. 이동평균 계산이 대표적이다. 카프카에서 새 메시지를 폴링할 때마다 평균값을 갱신해야 하므로, 재시작했을 때 마지막 오프셋에서 읽기를 재개하는 것만으로는 부족하다. 이동평균값 자체를 복구해야 한다.
방법은 오프셋을 커밋할 때 마지막으로 누적된 값도 results 토픽에 함께 쓰는 것이다. 그러면 스레드가 시작될 때 중단 시점과 누적값을 함께 가져온다. 이 발상이 상태를 가진 스트림 처리에서 체인지 로그로 확장된다.