KafkaConsumer and TCP connection
과도한 tcp connection으로 카프카 브로커 중 일부를 사망하게 한 장애 분석 경험(내가죽인건 아님..)
- 상황
카프카 클러스터의 브로커 노드중 하나가 죽기 시작하면서, 메세지의 컨슘에 이상이 생겼고, 데드레터 발생. 및 장애가 전파되기 시작함
(장애 전파를 막지 못한 아키텍쳐 적인 원인은 일단 논하지 않는다- 나도 아직 분석을 자세히 못해봐서 논할 자격이 안됨..) - 원인
특정 노드에 약 1000개 정도의 tcp connection이 생성되었고, 서버를 죽여버렸다. - Deepdive
질문 : 커넥션의 숫자가 정상적인가? 우리가 컨슘 하는 토픽의 갯수는 몇개인가? 토픽당 커넥션 생성 갯수는 몇개인가? 폭발적인 숫자의 증가 원인은 무엇인가?
확인: 커넥션 숫자가 비정상 적이다. -> 토픽의 갯수는 약 90개, 토픽당 동시성을 수행하는 쓰레드는 평균 3개, 270개 정도가 생길것 으로 예상한다.
증명: 로컬에서 재현을 해보자.
사실: 90개를 띄웠는데.. 커넥션이 거의 500개다…. 그럼 뭔가 틀렸다.
회귀:혹시 카프카가 1개의 KafkaConsumer를 생성할 때 여러개의 커넥션을 만드나??? 그래서 확인해봤다. - 결론
KafkaConsumer는 내부적으로 NetworkClient를 통해 Request를 생성하여 자신의 요청을 Broker에게 보낸다. 이 때 세가지로 기본 동작을 축약 할 수 있는데, 1. 메타데이터 요청, 2. 코디네이터 정보 요청, 3.컨슘
때문에 기본적으로 3개의 Tcp Connection을 물고 시작하게 된다.
하지만 혼란을 느꼈던 포인트가 있는데, 만약 해당 컨슘을 수행하는 Thread가 Partition을 할당 받지 못해서 유휴 상태가 된다면?
2개의 Tcp Connection만을 그대로 물고 종료되지 않는다.(다른 컨슈머가 죽으면 재할당 가능하기 때문으로 보임)
즉 커넥션 갯수와 현재 Thread * 3 의 숫자와 맞지 않는다면, 놀고 있는 Thread가 존재하고 커넥션이 2개씩 놀고 있다는 사실을 잘 알아야 한다.
백업의 용도로 Thread가 대기 하고 있는 것은 어느정도 필요하긴 하지만, 여러 인스턴스를 실행 할 경우 먼저 뜬 인스턴스가 더 많은 파티션을 처리하고 가져가서 자원이 비효율적으로 쓰일 가능성도 생각하면서 어플리케이션을 설계하고, 어떠한 전략으로 이를 커버할지에 대한 고민도 상당히 추가 되어야 한다고 생각한다.
요약! KafkaConsumer 구현체는 기본적으로 파티션을 할당 받았을 경우 3개의 Tcp Connection을 생성하며, 할당 받지 못했을 경우 2개를 유지 한다.
위 내용을 약간 정정 한다.
최초에 무조건 2개가 쓰이는건 메타데이터 업데이트, 코디네이터 찾기 정도 이다.
각 커넥션은 타임아웃을 갖고있고, 그 시간동안 새로운 정보로 업데이트 되지않으면 커넥션을 정리한다.
즉 시간이 지나면 1개의 fetcher에서 사용하는 커넥션만 남는다.
최초에는 2~3개
최종은 0~1개
이후 컨슈머가 파티션을 할당받게되면? 브로커 사이드의 코드를 분석해서 2탄 작성 예정!
추가: 장애상황에서의 커넥션의 증가는?
첫번째로 blue green depoly 를 하면서 inactive 되어야할 쪽에 stop hook이 동작 하지 않았다면? 최대 약 2배의 커넥션을 생성했을 수 있다.
두번째로 start hook 코드에 버그가 있었다. 기존 생성된 컨슈머들이 존재하면 실행시키지 말아야 하는데 이 조건이 없었고, 배포시 start hook의 성공까지 재시도 과정에서 n배로 실행되었을 수 있다. 원인은 복합적이지만, 정상 커넥션이 얼마인지를 알기 위해 확인한 과정을 기록으로 남겼고 이외의 전략들은 고민이 더필요하다.