본문 바로가기

STUDY/실전 카프카 개발부터 운영까지

5장 - 프로듀서의 내부동작 원리와 구현

파티셔너

 

메시지를 각 파티션으로 나누어주는 파티셔너

카프카는 토픽마다 병렬처리를 위한 파티션을 가지고 있고, 이에따라 각 메시지가 어느 파티션에 들어가야 하는지 결정하는 로직이 필요하다. 이때 사용하는 것이 바로 파티셔너이다. 카프카는 별도의 파티셔너를 정의하지 않으면 기본적으로 라운드 로빈 알고리즘을 사용하는 파티셔너를 사용했었다. 그러나 2019년 부터는 이를 개량한 스티키 파티셔닝 알고리즘을 사용한다.

 

라운드 로빈 알고리즘

라운드 로빈 알고리즘은 메시지를 각 파티션에 순서대로 하나씩 넣는다. 이렇게 하면 각 파티션에 동일한 수의 메시지가 들어가게 되고, 자연스럽게 각 파티션을 가져가는 컨슈머도 동일한 부하를 가지도록 한다. 하지만 카프카의 기본 특징인 메시지의 배치 전송 때문에 라운드 로빈 전략은 약점이 존재한다. 위 이미지처럼 batch.size가 3으로 설정되어있고 5개의 메시가 존재하는 경우, 아직 batch.size에 도달하지 못했기 때문에 메시지는 브로커로 전달되지 못한다. 이는 메시지 전송에 불필요한 지연을 발생시킨다.

 

스틱키 라운드 로빈 알고리즘

그래서 2019년 부터는 개선된 알고리즘인 스틱키 라운드 로빈을 사용한다. 스틱키 라운드 로빈은 각 파티션을 배치사이즈 까지 채우고 다음 파티션을 채운다. 이렇게 되면 자연스럽게 메시지 전송에 걸리는 지연시간이 줄어들고, 본래 의도했던 각 파티션간의 부하 분산도 큰 차이없이 달성할 수 있다.

 

 


파티션 사용시 주의사항 - 적절한 파티셔너 구현의 필요성

 

과거 보안 센서 관련 프로젝트를 수행하다 파티션 관련 이슈를 경험한 적이 있다. 보안 센서들이 보내는 정보를 수신하는 서버를 만들어야 했는데, 이때 클라우드 메시지 브로커 서비스를 사용하였다. 센서에서 넘어오는 정보는 처리 서버의 상태와 상관없이 수집되어야 했다. 그렇기에 자연스럽게 메세지 브로커를 사용하기로 했다. 그리고 성능 향상을 위해 여러개의 파티션으로 나누어 센서 정보를 수집했다. 

 

순서대로 처리되는 메시지
처리 순서가 보장되지 않는 메시지

하지만 파티션을 나누고 각 컨슈머에서 이를 병렬로 처리하다보니 이슈가 발생하였다. 바로 센서 정보의 처리 순서가 꼬여버린 것이다. 예를 들어 "문을 여는 정보" > "문을 닫는 정보"가 순서대로 처리되어야 하는데, 병렬처리를 하다보니 순서가 꼬여서 이미 닫혀있는 문을 또 닫고다서 문을 여는식으로 해석하는 경우가 있었다. 그래서 이를 해결하기위해, 건물단위로 센서를 묶어서 키를 만들고, 해당 키로 파티션을 나누는 파티셔너를 구현했었다.

 

 


전송 전략

 

프로듀서가 메시지를 전송할 때, 어떤 전략을 사용하느냐도 굉장히 중요한 고려요소이다. 경고 알람 메시지를 보낸다고 할 경우, 메세지 전송이 실패하면 안된다. 따라서 확실히 전송이 될때까지 메시지를 계속 재전송 할 수도 있다. 반대로 고객의 제품 구매 메시지는 중복전송을 하면, 하나의 제품을 구매했는데 여러개의 제품이 배송될 수도 있다. 따라서 최대 한번만 메시지가 전송되도록 해야한다. 이처럼 서비스에 따라서 적절한 전송 전략을 선택해야 한다.

 

 


적어도 한 번 전송

 

적어도 한 번 전송 전략은 브로커로부터 메시지 수신 응답이 올때까지, 메시지를 계속 재 전송하는 전략이다. 프로듀서는 메시지를 보내고 브로커의 신호가 올때까지 기다리고, 브로커의 수신 신호가 오지 않으면 동일한 메시지를 다시 보낸다. 이렇게 되면 메시지는 최소 한번은 브로커로 보내지는게 보장이 된다. 하지만 동일한 메시지를 중복 전송 할 수도 있다는 약점이 있다.

 

 


최대 한 번 전송

 

최대 한 번 전송 전략은 브로커의 메시지 수신 여부에 상관없이 메시지를 보내는 전략이다. 위 그림에서 프로듀셔가 message2를 보내고 브로커의 수신 신호를 받지 못했지만, 별도의 처리 없이 바로 다음 메시지를 보낸다. 이렇게 동작할 경우 메시지를 중복 전송하지는 않지만, 메시지가 중간에 유실될 위험이 있다.

 

 


중복 없는 전송

 

중복 없는 전송 전략은 적어도 한 번 전송 전략에 Id를 추가하여 중복 여부를 확인하는 방식이다. 프로듀서의 경우 메시지를 보내고 브로커로부터 수식 응답이 없으면 재전송하는 로직은 동일하지만, 여기서 주고 받는 메시지에는 프로듀서 Id와 메시지 번호가 포함되어있다. 따라서 프로듀서가 메시지를 중복 전송 하여도, 브로커는 해당 정보로 메시지 중복여부를 식별한다. 그리고 중복된 메시지일 경우 별도 동작없이 ACK 신호를 프로듀서로 전송 한다.

 

 


정확히 한 번에 전송 (트랜잭션)

 

정확히 한 번 전송(트랜잭션)이 필요한 이유

하나의 메시지를 중복없이 보내는 것은 중복 없는 전송 전략에서 완성 되었다. 그러나 복수의 메시지가 정확히 한 번 전송되어야 하는 경우가 있는데, 이때 사용하는 전략이 정확히 한 번 전송이다. 예를 들어 A 계좌에서 B 계좌로 돈을 이체하는 경우, A계좌에서 출금하는 메시지와 B계좌로 입금하는 메시지 2개가 존재할 수 있다. 이때 둘 중 하나의 메시지만 브로커에 전달되고, 이를 컨슈머가 가져가서 처리한다면 문제가 발생한다.

 

정확히 한 번 전송은 여러개의 메시지 전송을 하나의 트랜잭션 단위로 관리 한다. 하나의 트랜잭션을 열고 메시지를 보낸 후, 그 결과에 따라 트랜잭션을 커밋하거나 어볼트 하여 컨슈머가 일부의 메시지만 가져가는 일이 없도록 보장한다.

 

 


정리

 

카프카 프로듀서의 입장에서 파티션/파티셔너와 메시지 전송전략에 대한 내용을 알아보았다. 각 방식의 장단점에 대한 내용이었고, 어떤 방식을 적용할지는 개발자의 판단이다. 게시글 조회수 같은 데이터를 굳이 메시지 전송 순서를 지키고, 적어도 한 번 전송 방식을 사용해서 성능을 저하시키면 안될 것이다. 구매 데이터를 무지성으로 전송 순서를 무시하고, 중복 전송을 허용해버리면 안될것이다.

728x90