feat. 스레드 풀
NioEventLoopGroup 객체는 내부적으로 스레드 그룹을 유지하는 스레드 풀로 이해할 수 있다.
각 스레드는 여러 채널에서 이벤트를 처리하고 채널은 하나의 스레드에만 해당하므로 여러 스레드에서 데이터 동기화 문제를 피할 수 있다.
세 가지 Reactor 스레딩 모델이 있다.
단일 스레드 모델
다중 스레드 모델
마스터-슬레이브 Reactor 스레딩 모델
NIOEventLoopGroup은 Reactor와 어떤 관련이?? 실제로 NIOEventLoopGroup은 스레드 풀 구현으로, 서로 다른 NIOEventLoopGroup 메서드를 설정하여 세 가지 Reactor 스레드 모델에 대응할 수 있다.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup).channel(NioServerSocketChannel.class);
.
@Override public ServerBootstrap group(EventLoopGroup group) {
return group(group, group);
}
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);
bossGroup에는 스레드가 하나뿐이다. workerGroup 스레드 풀에 스레드 수를 지정하지 않았으므로 기본값은 CPU 코어 수에 2를 곱한 것이므로 Reactor 스레드 모델에 해당하므로 이러한 방식으로 설정된다.
EventLoopGroup bossGroup = new NioEventLoopGroup(4);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);
Netty의 서버 측 Acceptor 단계는 멀티 스레딩을 사용하지 않으므로 위의 마스터-슬레이브 멀티 스레딩 모델은 Netty의 서버 측에 존재하지 않는다.
서버 측의 ServerSocketChannel은 bossGroup의 하나의 스레드에만 바인딩되므로 Java NIO Selector.select를 호출하여 클라이언트 연결 요청을 처리 할 때 실제로 하나의 스레드만 사용되므로 서비스가 하나만있는 애플리케이션의 경우 bossGroup 설정 다중 스레드는 효과가 없지만 자원 낭비를 유발한다.
Google에 따르면 Netty의 bossGroup이 스레드 풀을 사용하는 이유는 다양하지만 stackoverflow 에서 더 신뢰할 수있는 답변 을 찾았다.
Netty의 제작자는 NioEventLoopGroup을 서로 다른 서버 부트 스트랩간에 공유하는 경우 여러 보스 스레드가 유용하다고 말했지만 그 이유는 모르겠다.
NioEventLoopGroup의 핵심 클래스 상속 관계는 다음과 같다.
NioEventLoopGroup – "MultithreadEventLoopGroup –"MultithreadEventExecutorGroup
이전 BootStrap 글에서 잠깐 다루었다.
이전 BootStrap Netty 소스 코드 분석 중 NioEventLoopGroup의 초기화 프로세스를 간략하게 소개했다.
1. EventLoopGroup (실제로 MultithreadEventExecutorGroup)은 스레드 풀을 구성하는 크기가 nThreads 인 EventExecutor 자식 유형의 배열을 내부적으로 유지한다.
2. NioEventLoopGroup을 인스턴스화하는 경우 스레드 풀 크기가 지정되면 nThreads가 지정된 값이고 그렇지 않으면 프로세서 코어 수 * 2이다.
3. MultithreadEventExecutorGroup은 newChild 추상 메서드를 호출하여 자식 배열을 초기화한다.
4. 추상 메서드 newChild는 NioEventLoop 인스턴스를 반환하는 NioEventLoopGroup에서 구현된다.
NioEventLoopGroup은 실제로 스레드 풀이다.
NioEventLoopGroup은 백그라운드에서 n NioEventLoop을 시작하여 채널 이벤트를 처리한다.
각 NioEventLoop은 m 개의 채널을 처리한다.
NioEventLoopGroup은 NioEventLoop 배열에서 NioEventLoop을 하나씩 가져와 채널을 처리한다.
- https://segmentfault.com/a/1190000007282789
- https://www.slideshare.net/kslisenko/networking-in-java-with-nio-and-netty-76583794
- https://www.slideshare.net/JangHoon1/netty-92835335?from_action=save
- https://blog.csdn.net/zxhoo/article/details/17419229
- https://slowdev.tistory.com/16
- https://sina-bro.tistory.com/15
- https://github.com/YonghoChoi/develop-note/blob/master/md/Netty/3장_부트스트랩.md
- https://blog.csdn.net/zxhoo/article/details/17532857
- https://clairdelunes.tistory.com/26