IT

Netty 컴포넌트와 설계

코딩하는 너구리 2020. 12. 10. 11:10
반응형

 

Channel, EventLoop, ChannelFuture

이제 네티의 네트워킹 추상화를 대표한다고 말할 수 있는 Channel, EventLoop, ChannelFuture 클래스를 더 자세히 알아보자. 이 세 가지 개념의 기능들을 다음과 같이 요약해볼 수 있다.

  • Channel : 소켓(Socket)
  • EventLoop : 제어 흐름, 멀티스레딩, 동시성 제어
  • ChannelFuture : 비동기 알림



Channel 인터페이스

자바 기반 네트워크에서 기본 구조는 Socket 클래스다. 네티의 Channel 인터페이스는 Socket으로 직접 작업할 때의 복잡성을 크게 완화하는 API를 제공한다.

ex) EmbeddedChannel, LocalServerChannel, NioDatagramChannel, NioSctpChannel, NioSocketChannel...



EventLoop 인터페이스

EventLoop연결의 수명주기 중 발생하는 이벤트를 처리하는 네티의 핵심 추상화를 정의한다.

 

다음 그림은 Channel, EventLoop, EventLoopGroup 간의 관계를 개략적으로 보여준다.


이러한 관계를 정리하면 다음과 같다.

  • EventLoopGroup은 하나 이상의 EventLoop를 포함한다.
  • EventLoopGroupChannelEventLoop를 할당
  • EventLoop는 수명주기 동안 하나의 Thread로 바인딩된다.
  • EventLoop에서 처리되는 모든 입출력 이벤트는 해당 전용 Thread에서 처리된다.
  • 하나의 Channel은 수명주기 동안 하나의 EventLoop에 등록할 수 있다.
  • EventLoop를 하나 이상의 Channel로 할당할 수 있다.

 

 

 

 

ChannelFuture 인터페이스

이전에 설명했듯이 네티의 모든 입출력 작업은 비동기적이다. 즉, 작업이 즉시 반환되지 않을 수 있으므로 나중에 결과를 확인하는 방법이 필요하다. 이를 위해 네티는 ChannelFuture를 제공하며, 이 인터페이스의 addListener() 메서드는 작업이 완료되면 알림을 받을 ChannelFutureListener 하나를 등록한다.

 

ChannelFuture는 미래에 실행될 작업의 결과를 위한 표시자라고 생각할 수 있다. 실행되는 시점은 여러 요소에 의해 좌우되므로 정확한 시점을 예측하기는 불가능하지만 실행된다는 점은 확실하다. 또한 동일한 Channel에 속하는 모든 작업은 호출된 순서와 동일한 순서로 실행된다.



ChannelHandler 인터페이스

개발자의 관점에서 네티의 핵심 컴포넌트는 인바운드와 아웃바운드 데이터의 처리에 적용되는 모든 애플리케이션 논리의 컨테이너 역할을 하는 ChannelHandler이다.

이런게 가능한 이유는 ChannelHandler의 메서드가 네트워크 이벤트에 의해 트리거되기 때문이다.

실제로 ChennelHandler는 데이터를 변환하거나 예외를 처리하는 등 거의 모든 종류의 작업에 활용할 수 있다.

 

ChannelPipeline 인터페이스

ChannelPipeline은 ChannelHandler 체인을 위한 컨테이너를 제공하며, 체인 상에서 인바운드와 아웃바운드 이벤트를 전파하는 API를 정의한다.

Channel이 생성되면 여기에 자동으로 자체적인 ChannelPipeline이 할당된다. ChannelHandler는 다음과 같이 ChannelPipeline 안에 설치된다.

  • ChannelInitializer 구현은 ServerBootstrap에 등록된다.
  • ChannelInitializer.initChannel()이 호출되면 ChannelInitializer가 ChannelPipelineChannelHandler의 커스텀 집합을 파이프라인에 설치한다.
  • ChannelInitializer는 ChannelPipeline에서 자신을 제거한다.

 

데이터를 전송하거나 수신할 때 어떤 일이 일어나는지 확인하면서 ChannelHandler와 ChannelPipeline간의 관계를 더 자세히 알아보자.

 

ChannelHandler는 ChannelPipeline을 통해 오가는 이벤트를 처리 코드를 위한 범용 컨테이너라고 할 수 있다.

파이프라인을 통해 이벤트를 이동시키는 역할은 Channelhandler가 담당한다.

이벤트를 수신하고, 구현된 처리 논리를 실행하며 체인 상의 다음 핸들러로 데이터를 전달한다.

핸들러가 실행되는 순서는 추가된 순서에 의해 결정된다.

ChannelPipeline이라고 말할 때는 이러한 Channelhandler의 정렬된 배치 전체를 의미한다고 보면 된다.

 

 

 

 

클라이언트의 관점에서 서버로 움직이는 이벤트는 아웃바운드이며, 그 반대는 인바운드다.

그림을 보면 인바운드와 아웃바운드 이벤트를 동일한 파이프라인에 설치할 수 있음을 알 수 있다. 메시지나 다른 인바운드 이벤트를 읽을 때는 파이프라인의 앞쪽에서 시작하며 첫 번째 ChannelInboundHandler로 전달된다. 데이터를 처리한 후에는 다음 ChannelInboundHandler로 데이터를 전달한다. 최종적으로 파이프라인의 뒤쪽에 이르면 모든 처리가 종료된다.

 

데이터의 아웃바운드 이동 역시 개념상 동일하며 ChannelOutboundHandler가 뒤쪽에서 시작해 앞쪽까지 이를 때까지 이동한다. 이 지점에서 아웃바운드 데이터는 그림에 Socket으로 나오는 네트워크 전송에 도달한다. 보통은 이때 쓰기 작업이 트리거된다.

 

 

인코더와 디코더

Netty로 메시지를 전송하거나 수신할 때는 데이터를 변환해야 한다.

인바운드 메시지바이트에서 다른 포맷(보통 자바 객체)으로 변환되는 디코딩을 거친다.

아웃바운드 메시지는 반대로 현재 포맷에서 바이트인코딩된다.

이러한 두 가지 변환이 필요한 이유는 네트워크 데이터는 반드시 연속된 바이트여야하기 때문이다.



부트스트랩

네티의 부트스트랩 클래스는 프로세스를 지정된 포트로 바인딩(서버 부트스트랩)하거나 프로세스를 지정된 호스트의 지정된 포트에서 실행중인 다른 호스트로 연결(클라이언트 부트스트랩)하는 등의 일을 하는 애플리케이션의 네트워크 레이어를 구성하는 컨테이너를 제공한다.

 

서버 부트스트랩은 ServerBootstrap을 이용하고 클라이언트 부트스트랩은 Bootstrap을 이용한다.

 

 

 

클라이언트를 부트스트랩할 때는 EventLoopGroup 하나가 필요하지만 서버는 두 개가 필요하다.

서버는 각기 다른 Channel의 두 집합을 필요로 한다.

첫 번째 집합은 로컬 포트로 바인딩된 서버 자체의 소켓을 나타내는 ServerChannel

두 번째 집합은 서버가 수락한 연결마다 하나씩 들어오는 클라이언트 연결을 처리하기 위해 생성된 모든 Channel

 

 

정리

Channel: 자바 기반 네트워크에서 기본 입출력 작업을 하며 소켓(Socket)으로 작업할 때의 복잡성을 완화시켜주는 API

Socket 통신에서 Socket 정도로 생각해두자.

 


ChannelFuture
비동기 작업에서 알림 기능을 함. 특정 시점에 할 행동들을 정의할 수 있음

( ex_채널이 연결되면 인증과정을 해라.)

 

이전에 설명한 것처럼 약속된 미래의 시점으로 생각해두자.(채널 연결됨, 채널 연결 끊어짐 등..)

 


ChannelPipeLine:
 ChannelHandler 체인을 위한 컨테이너 역할. 채널이 생성되면 ChanelPipeline은 자동으로 할당된다.

Channel에 할당된 InboundHandler, OutboundHandler 등 이벤트들이 Channel 내에서 움직이는 통로 정도로 생각하자.

 


ChannelHandler : 
이벤트 수신, 구현된 이벤트 논리 실행, 다음 핸들러로 데이터 전달 등 모든 애플리케이션 논리의 컨테이너 역할을 함.

Channel 통로를 타고 이동하는 이벤트들.

ex ) 나는 서버에 채널이 연결되면 "Hello" 라고 보내야지

         -> ChannelInboundHandler에서 channelActive() 메소드에 "Hello" 를 전송하도록 설정.

 


EventLoopGroup 
EventLoop들을 포함하는Group

 


EventLoop
 : 수명 주기동안 하나의 쓰레드로 바인딩되며 이벤트를 관리하여 제어흐름, 멀티스레딩, 동시성 제어 등의 기능을 수행할 수 있음

Channel과 연결할 이벤트 묶음으로 생각해두자. Handler로 정의된 이벤트들의 묶음 말이다.

Channel당 하나의 EventLoop로 할당되므로 내가 (서버 또는 클라이언트에) 할당해줄 이벤트의 묶음을 EventLoop에 모아서 Channel에 할당해줄꺼야!

 

 

네트워크 데이터는 연속된 바이트여야 하기 때문에 인코더와 디코더의 개념이 필요하다.

 

(JAVA) 내가 보낼 데이터 -> (인코딩) -> (Byte) 데이터 전송 완료
인코더 : 
아웃바운드 메시지는 현재 포맷에서 바이트로 인코딩하는 과정을 거치는데, 이 과정을 인코더가 수행

 

(Byte) 내가 받을 데이터 -> (디코딩) -> (JAVA) 데이터 수신 완료
디코더 : 
인바운드 메시지의 경우 바이트에서 다른 포맷(보통 자바 객체)로 변환하는 디코딩 과정을 거치는데, 이 과정을 디코더가 수행

 

부트스트랩
서버 vs 클라이언트

서버를 지정된 포트로 바인딩할 서버 부트스트랩과,

지정된 호스트의 지정된 포트에서 실행중인 호스트로 연결하는 클라이언트 부트스트랩이 있다는 정도만 알고 넘어가자.

 

 

 

 

 

출처 : 네티인 액션

https://book.naver.com/bookdb/book_detail.nhn?bid=10462610

 

네티 인 액션

네티는 복잡한 네트워킹, 멀티스레드, 동시성을 관리하는 자바 기반 네트워킹 프레임워크로서, 반복적인 저수준 코드를 내부로 감춤으로써 비즈니스 논리를 분리하고 쉽게 재사용할 수 있게 해

book.naver.com

 

반응형

'IT' 카테고리의 다른 글

Netty ByteBuf - 바이트 버퍼  (0) 2020.12.29
Netty 전송 API  (0) 2020.12.28
Java Netty 에코 서버-클라이언트 구현하기  (1) 2020.12.09
Netty의 개념과 아키텍처  (0) 2020.12.09
[ERROR] JSON 순환 참조 문제 해결하기  (0) 2020.09.19