자바 네트워크 소녀 Netty" 공부하면서 정리한 내용입니다.
1. 이벤트 루프
a. 이벤트 처리 방식
애플리케이션이 이벤트를 처리하는 방법은 크게 2가지로 구분된다.
1. 이벤트 리스너 + 이벤트 처리 스레드
- 일반적으로 UI 프레임워크에서 사용하는 방식
- 이벤트 메서드를 이벤트 리스너에 등록하고, 이벤트가 발생했을 때 이벤트 처리 스레드(싱글 스레드)에서 등록된 메서드 수행
2. 이벤트 큐 + 이벤트 루프
- 1번 방식보다 프레임워크 구현이 복잡하지만 프레임워크 사용자는 간단하게 사용할 수 있음.
- 이벤트 큐에 이벤트 등록하고, 이벤트 루프가 이벤트 큐에 접근하여 처리
- 이벤트 큐는 다중 스레드(이벤트 루프)에서 공유
- 이벤트 결과를 돌려주는 방식으로는 콜백패턴과 퓨쳐패턴이 있다.
b. 싱글스레드와 멀티스레드 이벤트 루프
1. 싱글 스레드 이벤트 루프
- 이벤트 처리 스레드가 하나로 단순하고 예측 가능한 동작을 보장
- 다중 코어 CPC에서 리소스를 비효율적으로 사용(처리시간이 오래 걸린다.)
2. 멀티 스레드 이벤트 루프
- 이벤트 처리 스레드가 여러 개로 구현이 복잡
- 다중 코어 CPU 리소스를 효율적으로 활용(여러 개의 작업을 동시에 처리하기 때문에 처리시간이 빠를 수 있음)
- 멀티스레드의 단점이 그대로 적용(스레드 경합, 컨텍스트 스위칭, OOM 발생)
- 이벤트 발생순서와 실행 순서 불일치 문제(다중 스레드가 하나의 이벤트 큐를 공유하기 때문)
c. Netty의 이벤트 루프
Netty는 싱글 스레드/멀티 스레드 이벤트 루프를 모두 지원한다.
이벤트 루프 스레드 설정
EventLoopGroup bossEventLoopGroup = new NioEventLoopGroup(1); // 스레드 개수 설정
또한 멀티 스레드에서 이벤트 발생순서와 실행 순서 보장
이벤트 큐를 이벤트 루프 스레드의 내부에 둠으로써 순서를 보장.
채널에서 이벤트가 발생하는데 채널은 이벤트 루프에 등록되며 각 이벤트 루프(스레드) 내부에서 이벤트 큐를 관리하기 때문에 이벤트 발생순서와 실행순서 불일치 문제를 해결할 수 있었다.
2. Netty의 비동기 I/O 처리
Netty에서는 비동기 호출을 위 두 가지 패턴을 제공한다. 첫번째는 리액터 패턴의 구현체인 이벤트 핸들러, 두번째는 퓨처 패턴의 구현체인 ChannelFuture이다.
이벤트 핸들러(리액터 패턴)는 앞에서 많이 다루었기 때문에 다루지 않겠다.
https://soonmin.tistory.com/73
ChannelFuture 예제 코드
클라이언트로부터 데이터를 수신하면 클라이언트에게 데이터를 그대로 전송한 후 데이터 전송이 완료되면 연결된 채널을 닫는 코드이다.
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ChannelFuture channelFuture = ctx.writeAndFlush(msg); // 비동기 메서드(ChannelFuture를 돌려 받는다.)
channelFuture.addListener(ChannelFutureListener.CLOSE); // 채널 종료하는 리스너 등록
}
}
Netty는 몇가지 기본 채널 리스너를 제공한다.
- ChannelFutureListener.CLOSE
- ChannelFuture 객체가 작업 완료 이벤트를 수신했을 때 채널을 닫는다.(성공여부 상관없이 수행)
- ChannelFutureListener.CLOSE_ON_FAULURE
- ChannelFuture 객체가 작업 완료 이벤트를 수신하고 결과가 실패일 때 채널을 닫는다.
- ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE
- ChannelFuture 객체가 작업 완료 이벤트르 수신하고 결과가 실패일 때 채널 예외 이벤트를 발생시킨다.
채널 리스너를 직접 구현하여 사용할 수 있다.
위 예제와 동일한 동작을 하는 코드이다. ChannelFutureListenr 인터페이스를 구현해서 리스너에 등록할 수 있다.
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 데이터가 수신될 때 수행할 코드
ChannelFuture channelFuture = ctx.writeAndFlush(msg);
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
System.out.println("전송한 msg: " + msg);
future.channel().close();
}
});
}
}
'Back-end > 기타' 카테고리의 다른 글
[Netty] Netty 단위 테스트 작성하기 (0) | 2024.01.17 |
---|---|
[Netty] 바이트버퍼(ByteBuffer) (0) | 2024.01.15 |
[Netty] 채널 파이프라인과 코덱 (0) | 2024.01.12 |
[Netty] Netty의 Bootstrap(부트스트랩) (0) | 2024.01.12 |
[Netty] 네트워크 프레임워크 Netty란? (1) | 2024.01.11 |