Netty가 완료된 작업을 식별하는 메커니즘
일단 가장 먼저 잡아야할 개념은 connection, thread의 관계 즉 연결과 실행단위의 관계다.
기존의 Blocking(Tomcat) 방식은 thread per reqeust로 1:1의 관계를 맺고 연결이 생기면 하나의 스레드에 할당해서 그 연결이 끊어질때까지 바인드 되어있다.
그래서 사실 해당 요청에 대한 식별 방법이 굳이 없어도 된다 그 스레드는 오직 그 연결만 담당하니까
그러나 Non-Blocking(Netty) 시스템은 N개의 커넥션이 하나의 스레드에 할당되는데 연결은 그냥 그저 객체(메모리 덩어리)일 뿐이다.
스레드는 이 객체들을 관리하는 관리자로서 연결에 묶이지 않고 loop한다.
스레드가 여러 연결을 담당하므로 이벤트가 발생했을 때 이게 누구건지 찾아내는 조회장치 Selector가 필요하다.
I/O Multiplexing (Selector 패턴) #
Netty가 작업을 식별하는 과정은 subscirption - event - dispatch 3단계 구조이다.
구독 subscription #
클라이언트가 연결되거나 요청을 보낼때 네티는 os kernel에게 소켓(fd 101번)에 데이터가 들어오면 알려달라. 소켓의 주인은 Channel_A 객체다. 이런식으로
Selector라는 관리 테이블이 Key: socket_no, Value: Channel Object. 형태로 매핑하여 저장한다.
감지 Select #
Netty의 이벤트 루프 스레드는 평소에 select() 라는 메서드를 호출해두고 대기한다.
커널은 등록된 수천 개의 소켓 중 실제로 데이터가 도착한(완료된) 소켓만 추려낸다.
1000개가 연결되어 있어도ㅡ 실제로 데이터가 온 게 1개라면 스레드는 그 1개 때문에만 깨어난다.
식별 및 실행 dispatch #
커널이 101번 소켓에 읽을 데이터가 있다고 리턴하며 스레드는 Selector 테이블에서 101번 키를 조회한다.
거기에 붙어있는 Channel_A 객체를 획득하고 Channel_A.pipeline().fireChannelRead()를 호출해 비즈니스 로직을 수행한다.
그래서 예를들어 외부 연동 시스템에서 응답지연이 되게 된다면 내부 상태는 다음과 같다.
Blocking 모델은 스레드가 wait/sleep 상태에 빠지고 스레드 자체가 연결 정보를 들고 멈춰있으니 스택 점유하고 응답이 올때까지 그 스레드는 삭제된거랑 같이 사용 불가능한 상태로 빠짐 응답 오면 깨어날거고
Non-Blocking 모델은 스레드 해방이라 runnable 상태로 계속 돌거고 연결 정보는 Selector 테이블에 등록된채 Heap에만 존재함 스레드는 즉시 다른 요청을 처리하러 떠나고 응답이 온 이후에 커널이 알림을 주면 스레드가 다시 돌아와 처리한다.
요약하면 운영체제가 변화와 생긴 소켓 번호를 찝어주면 Netty는 미리 작성해둔 메핑 테이블 Selector에서 그 번호에 해당하는 객체 Channel을 즉시 꺼내온다.