카프카 내부 메커니즘에 대해 학습하면서 네트워크에서 클라이언트의 요청이 어떻게 처리되는지 살펴보았다.
억셉터(Acceptor) 스레드, 프로세서(Processor) 스레드를 중심으로 요청이 처리되는 과정이 정리가 되어있는데, 책에서는 간단하게만 정리되어 있는 것 같아 이에 대해 자세히 알아보았다.
🧑💻 다양한 블로그들을 보고 정리한 글이며, 틀린 부분이 있다면 댓글 부탁드립니다.
1️⃣ New IO
네트워크에서 Input과 Ouput을 처리하는 것을 IO라고 하는데, 자바에서 가장 간단하게 소켓 통신을 할 수 있는 방법은 무엇일까?
바로 각 클라이언트마다 I/O 스레드를 생성하는 것이다(Multi Thread 방식). 하지만 위 방식에는 문제점이 존재한다.
- 하나의 개별 요청마다의 스레드 생성으로 메모리 사용량이 증가하고, Context Switching에 부담이 있다.
- 동작 도중 대기 상태가 되어도, 계속 메모리에 유지되어 리소스 낭비가 지속된다.
- 요청이 많아질수록 동기화 이슈가 발생할 확률이 커진다.
- 비동기 통신을 지원하지 않아, 요청이 처리되고 있는 동안 Block이 발생한다.
New IO
그래서 이를 보완한 것이 바로 NIO(New IO)이다.
NIO는 기존 IO에 Non-Blocking 과 Multiplexing의 특징이 추가된 것을 말한다.
- 기존 IO는 각 요청의 결과마다 동기적으로(Blocking) 처리하기 때문에 여래 개의 스레드가 필요했지만, NIO에서는 Non-Blocking 설정의 해줌으로써 하나의 소켓 서버 스레드로 요청을 처리할 수 있게 되었다.
- 이처럼 하나의 스레드로 여러 개의 연결을 관리하는 방식을 멀티플렉싱(Multiplexing)라고 한다.
- 여러 개의 연결( 여러 개의 소켓 ) 관리는 OS에서 직접하기 때문에, 클라이언트는 연결 전 OS에 관리 대상 소켓 정보를 등록해야한다.
카프카 내부에서 사용하고 있는 Java NIO는 Selector라는 컴포넌트를 이용해 여러 소캣 채널을 관리하고 있다.
2️⃣ 카프카 브로커 네트워크 구조
소켓 서버( Socket Server )
Plane
- Data Plane : Broker 끼리 혹은 client의 요청을 처리하기 위한 네트워크로, 카프카에서 읽고 쓰는 전체 데이터를 관리
- Control Plane : Broker와 Controller 간의 통신을 위한 네트워크로, 메타데이터를 관리
Acceptor
- 클라이언트의 요청을 감지하는 역할로, 요청을 확인한 후에 하위 Processor 중 하나가 읽기/쓰기 처리하도록 할당한다.
Processor
- 읽기/쓰기 요청을 감지하고, Request Channel의 Request Queue에 요청을 전달하는 역할을 수행한다. 이후에 작업이 완료되면 Response Queue에 담긴 작업 결과를 클라이언트에게 전달하는 역할 또한 수행한다.
- Data Plane은 여러 개의 Processor를 구성할 수 있는 반면, Control Plane에는 한 개만 구성할 수 있다. (` num.network.threads `)
Request Channel
- Processor, Handler(밑에 나옴), API가 공유하는 저장공간으로 요청에 대한 작업 결과를 Processor의 Response Queue에 전달하는 역할을 수행한다.
요청 핸들러 ( Request Handler )
소켓 서버 다음으로 요청 핸들러와 Kafka API가 구성되어 있다.
- Pool로 요청 핸들러를 관리하고 있으며, 핸들러는 클라이언트 요청을 받아 API에 전달하고, 작업 결과를 Reqeust Channel에 전달하는 역할을 한다.
- 여러개의 스레드로 핸들러를 구성할 수 있다. ( `num.io.threads` )
3️⃣ 동작 과정
Client의 접속 요청
1. Client가 접속 요청을 보내면 Acceptor가 인식하여 수락하고, Processor를 할당한다. 이후 요청을 전달한다. ( 여기서 할당은 Processor의 newConnetions 버퍼에 전달하는 것을 말한다. )
2. Processor는 자신의 Kafka Selector에 요청하여 등록하고, 추후에 있을 요청에 준비한다. 이후 접속 요청 완료를 반환한다.
Kafka Selector의 역할
주 역할은 Client 요청에 대한 정보를 저장하는 것이다. 아래와 같은 내부 프로퍼티를 구성하여 관리하고 있다.
- channel : 프로세서를 통해 연결된 Client의 Channel을 의미한다. Connection Id 와 KafkaChannel로 이루어진 Map 형태로 API 응닶값을 클라이언트에게 전달할때 사용한다.
- completedSends, completedReceives, disconnected : 요청을 임시 저장하는 Buffer로 요청을 전달 받았을때, 요청을 클라이언트에게 잘 전달했을때, close() 처리될 때 요청을 임시로 저장한다.
Client의 데이터 읽기/쓰기 요청
1. Client가 데이터 요청을 보내면, Kernel이 감지함과 할당받은 프로세서의 Kafka Selector가 해당 요청을 저장한다. 그리고 이를 Request Channel의 Queue에 전달한다.
2. Handler는 Request Queue에 존재하는 요청을 fetch하여 해당 요청을 API에 전달한다.
3. API에게 응답을 받으면 핸들러는 응답값을 Reqeust Channel에 전달한다.
4. Request Channel은 프로세서의 Id 값을 보고 Response Queue에 보낸다.
5. 프로세서는 Queue에 있는 데이터를 확인하고 Client에게 전달하며 마무리된다.
📚 Reference
'Kafka' 카테고리의 다른 글
Kafka : 메세지 중복 및 유실을 어떻게 방지할 수 있을까? (1) | 2024.12.02 |
---|---|
Kafka : 파티션 개수 설정에 대하여 (2) | 2024.11.17 |