>  기사  >  Java  >  Java의 netty 원칙은 무엇입니까?

Java의 netty 원칙은 무엇입니까?

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼원래의
2019-07-25 09:57:356847검색

Java의 netty 원칙은 무엇입니까?

1. Netty 소개

Netty는 JAVA NIO에서 제공하는 API를 기반으로 하는 고성능 비동기 이벤트 중심 NIO 프레임워크입니다. 이는 TCP, UDP 및 파일 전송을 지원합니다. Netty의 모든 IO 작업은 비동기식이며 비차단입니다. Future-Listener 메커니즘을 통해 사용자는 알림 메커니즘을 통해 쉽게 IO 작업을 얻을 수 있습니다. . 현재 가장 널리 사용되는 NIO 프레임워크인 Netty는 인터넷 분야, 빅데이터 분산 컴퓨팅, 게임 산업, 통신 산업 등에서 널리 사용되고 있습니다. 업계에서 잘 알려진 일부 오픈 소스 구성 요소도 Netty의 NIO 프레임워크를 기반으로 구축되었습니다.

2. Netty 스레드 모델

JAVA NIO 측면에서 Selector는 Selector 모드와 Reactor 모드를 결합하여 효율적인 스레드 모델을 설계하는 기반을 제공합니다. 먼저 Reactor 패턴을 살펴보겠습니다.

2.1 Reactor 패턴

Wikipedia는 Reactor 모델을 다음과 같이 설명합니다. “리액터 설계 패턴은 하나 이상의 입력에 의해 동시에 전달되는 서비스 요청을 처리하기 위한 이벤트 처리 패턴입니다. 그런 다음 들어오는 요청을 역다중화하고 이를 연관된 요청 핸들러에 동기식으로 전달합니다." 우선, Reactor 모드는 하나 이상의 동시 입력 소스, 서버 핸들러 및 여러 요청 핸들러가 있습니다. 이 서비스 핸들러는 입력 요청을 동기식으로 다중화하여 해당 요청 핸들러에 배포합니다. 아래 그림에서 볼 수 있습니다.

Java의 netty 원칙은 무엇입니까?

는 구조적으로 생산자 및 소비자 모델과 유사합니다. 즉, 하나 이상의 생산자가 이벤트를 대기열에 넣고, 하나 이상의 소비자가 적극적으로 이 대기열에서 이벤트를 가져옵니다. 이벤트는 리액터 모드에서 처리되지만 리액터 모드에는 버퍼링을 위한 큐가 없습니다. 이벤트가 서비스 핸들러에 입력될 때마다 서비스 핸들러는 처리를 위해 다양한 이벤트 유형에 따라 이를 해당 요청 핸들러에 적극적으로 배포합니다.

2.2 Reator 패턴 구현

Java NIO 구성 Reator 패턴과 관련하여 Doug lea는 "Scalable IO in Java"에서 Reator 패턴 구현을 설명하는 PPT 인터셉트를 제공합니다. 첫 번째 유형 구현 모델은 다음과 같습니다.

Java의 netty 원칙은 무엇입니까?이것은 가장 간단한 Reactor 단일 스레드 모델입니다. Reactor 모드는 비동기 비차단 IO를 사용하므로 이론적으로 하나의 스레드가 처리할 수 있는 모든 IO 작업이 차단되지 않습니다. 모든 IO는 독립적으로 작동합니다. 현재 Reactor 스레드는 소켓 역다중화, 새로운 연결 수락, 처리 체인에 요청 배포를 담당하는 일반 스레드입니다.

일부 소규모 애플리케이션 시나리오의 경우 단일 스레드 모델을 사용할 수 있습니다. 하지만 고부하, 대용량 동시성 애플리케이션에는 적합하지 않습니다. 주된 이유는 다음과 같습니다.

(1) NIO 스레드가 동시에 수백, 수천 개의 링크를 처리하면 성능이 지원되지 않습니다. NIO 스레드의 CPU 부하가 100%에 도달하여 메시지를 완전히 처리할 수 없습니다.

(2) NIO 스레드가 과부하되면 처리 속도가 느려지고 이로 인해 많은 수의 클라이언트 연결이 시간 초과됩니다. 시간 초과가 발생하면 재전송되는 경우가 많아 NIO 스레드의 로드가 증가합니다.

(3) 낮은 신뢰성 스레드의 예상치 못한 무한 루프로 인해 전체 통신 시스템을 사용할 수 없게 됩니다.

이러한 문제를 해결하기 위해 Reactor 멀티스레딩 모델이 등장했습니다.

2.Reactor 멀티스레딩 모델:

Java의 netty 원칙은 무엇입니까?이 모델은 이전 모델과 비교하여 처리 체인 부분에서 멀티스레딩(스레드 풀)을 사용합니다.

대부분의 시나리오에서 이 모델은 성능 요구 사항을 충족할 수 있습니다. 그러나 예를 들어 일부 특수 애플리케이션 시나리오에서는 서버가 클라이언트의 핸드셰이크 메시지에 대해 보안 인증을 수행합니다. 이러한 종류의 시나리오에서는 단일 Acceptor 스레드의 성능이 부족할 수 있습니다. 이러한 문제를 해결하기 위해 세 번째 Reactor 스레드 모델이 제작되었습니다.

관련 추천: "

java Development Tutorial

"
3. Reactor 마스터-슬레이브 모델

Java의 netty 원칙은 무엇입니까?이 모델은 두 번째 모델과 비교하여 Reactor를 두 부분으로 나눕니다. mainReactor는 서버 모니터링을 담당합니다. 소켓을 설치하고 새 소켓을 수락하고 subReactor에 설정된 소켓을 할당합니다. subReactor는 연결된 소켓을 역다중화하고, 네트워크 데이터를 읽고 쓰고, 비즈니스 처리 기능을 위해 작업자 스레드 풀에 전달하는 역할을 합니다. 일반적으로 하위 리액터의 수는 CPU 수와 같을 수 있습니다.

2.3 네티 모델

이제 2.2의 Reactor 3가지 모델에 대한 이야기를 마쳤는데, 어떤 것이 Netty일까요? 실제로 Netty의 스레드 모델은 Reactor 모델의 변형으로, 스레드 풀을 제거한 세 번째 변형 형태입니다. 이는 Netty NIO의 기본 모드이기도 합니다. Netty에서 Reactor 모드의 참여자는 주로 다음 구성 요소를 포함합니다.

(1) Selector

(2) EventLoopGroup/EventLoop

(3) ChannelPipeline

Selector는 NIO에서 제공하는 SelectableChannel 멀티플렉서 역할을 합니다. 디멀티플렉서의 경우 여기서는 자세히 설명하지 않겠습니다. Netty의 Reactor 모드에서 다른 두 기능과 해당 역할은 아래에 소개되어 있습니다.

3. EventLoopGroup/EventLoop

시스템이 실행 중일 때 스레드 컨텍스트 전환이 자주 발생하면 추가 성능 손실이 발생합니다. 여러 스레드가 비즈니스 프로세스를 동시에 실행할 때 비즈니스 개발자는 동시에 스레드 안전에 대해 항상 주의해야 하며, 이를 보호하는 방법은 무엇입니까? 이는 개발 효율성을 감소시킬 뿐만 아니라 추가적인 성능 손실을 초래합니다.

위 문제를 해결하기 위해 Netty는 메시지 읽기, 인코딩 및 핸들러의 후속 실행부터 IO 스레드 EventLoop가 항상 책임을 지며, 이는 전체 프로세스가 스레드 컨텍스트를 전환하지 않음을 의미합니다. . , 데이터가 동시에 수정될 위험이 없습니다. 이는 또한 Netty 스레드 모델이 Reactor 마스터-슬레이브 모델에서 스레드 풀을 제거하는 이유를 설명합니다.

EventLoopGroup은 EventLoops 그룹의 추상화입니다. EventLoopGroup은 작업을 처리하기 위해 특정 규칙에 따라 EventLoops 그룹의 EventLoops 중 하나를 얻는 데 사용할 수 있는 다음 인터페이스를 제공합니다. Netty에 있습니다. Netty 서버 프로그래밍에서는 작업할 두 개의 EventLoopGroup인 BossEventLoopGroup과 WorkerEventLoopGroup이 필요합니다. 일반적으로 서비스 포트, 즉 ServerSocketChannel은 Selector와 EventLoop 스레드에 해당하는데, 이는 BossEventLoopGroup의 스레드 번호 매개 변수가 1임을 의미합니다. BossEventLoop은 클라이언트의 연결을 수신하고 IO 처리를 위해 SocketChannel을 WorkerEventLoopGroup에 전달하는 역할을 담당합니다.

EventLoop의 구현은 Reactor 패턴에서 Dispatcher 역할을 합니다.

4. ChannelPipeline

ChannelPipeline은 실제로 Reactor 모드에서 요청 프로세서 역할을 합니다.

ChannelPipeline의 기본 구현은 DefaultChannelPipeline입니다. DefaultChannelPipeline 자체는 연결된 목록 대기열의 헤드와 테일에 각각 위치한 사용자가 볼 수 없는 테일과 헤드 ChannelHandler를 유지합니다. 꼬리는 위쪽에 있고 머리는 네트워크 계층에 가까운 방향에 있습니다. Netty에는 ChannelHandler에 대한 두 가지 중요한 인터페이스인 ChannelInBoundHandler와 ChannelOutBoundHandler가 있습니다. 인바운드는 네트워크 데이터가 외부에서 시스템 내부로 흐르는 것으로 이해될 수 있고, 아웃바운드는 네트워크 데이터가 시스템 내부에서 시스템 외부로 흐르는 것으로 이해될 수 있다. 사용자가 구현한 ChannelHandler는 필요에 따라 하나 이상의 인터페이스를 구현하고 이를 파이프라인의 연결된 목록 대기열에 넣을 수 있습니다. 동시에 ChannelPipeline은 다양한 IO 이벤트 유형에 따라 처리할 해당 핸들러를 찾습니다. 연결된 목록 대기열은 변형, 하향식 또는 상향식 모드에 있으며 이벤트 상관 관계를 충족하는 모든 핸들러는 이벤트를 처리합니다.

ChannelInBoundHandler는 클라이언트에서 서버로 보낸 메시지를 처리하며 일반적으로 하프 패킷/고정 패킷, 디코딩, 데이터 읽기, 비즈니스 처리 등을 수행하는 데 사용됩니다. 일반적으로 클라이언트에 메시지를 인코딩하고 보내는 데 사용됩니다.

다음 그림은 ChannelPipeline의 실행 과정을 보여줍니다.

Java의 netty 원칙은 무엇입니까?

파이프라인에 대한 자세한 내용은 다음을 참조하세요. A Brief Talk on Pipeline Model (Pipeline)

5. Buffer

확장 Netty에서 제공하는 Buffer는 상대적으로 NIO에 많은 장점이 있습니다. 데이터 접근에 있어서 매우 중요한 부분으로, Netty에서 Buffer의 특징을 살펴보겠습니다.

1. ByteBuf 읽기 및 쓰기 포인터

ByteBuffer에서는 읽기 및 쓰기 포인터가 위치인 반면, ByteBuf에서는 읽기 및 쓰기 포인터가 각각 readerIndex 및 WriterIndex입니다. 직관적으로 ByteBuffer는 두 개의 포인터를 구현하는 데 하나의 포인터만 사용하는 것 같습니다. .함수는 변수를 저장하지만 ByteBuffer의 읽기 및 쓰기 상태를 전환할 때는 Flip 메소드를 호출해야 하며, 다음 쓰기 전에 Buffer의 내용을 읽은 후 Clear 메소드를 호출해야 합니다. 매번 읽기 전에는 Flip을 호출하고 쓰기 전에는 Clear를 호출합니다. 이는 의심할 여지 없이 개발 단계를 지루하게 만들고 콘텐츠를 읽을 때까지 콘텐츠를 작성할 수 없으므로 매우 유연하지 않습니다. 반면에 ByteBuf를 살펴보겠습니다. 읽을 때는 readerIndex 포인터에만 의존하고, 쓸 때는 writeIndex 포인터에만 의존합니다. 각 읽기 및 쓰기 전에 해당 메서드를 호출할 필요가 없으며 제한도 없습니다. 한 번에 다 읽으려고요.

2. 제로 카피

(1) Netty는 바이트 버퍼의 보조 복사본이 필요 없이 소켓 읽기 및 쓰기를 위해 오프 힙 직접 메모리를 사용하여 직접 버퍼를 사용하여 ByteBuffer를 주고받습니다. 소켓 읽기 및 쓰기에 기존 힙 메모리(HEAP BUFFERS)가 사용되는 경우 JVM은 힙 메모리 버퍼를 직접 메모리에 복사한 다음 이를 소켓에 씁니다. 힙 외부의 직접 메모리와 비교할 때 메시지에는 전송 프로세스 중에 버퍼의 추가 메모리 복사본이 있습니다.

(2) Netty는 여러 개의 ByteBuffer 객체를 집계할 수 있는 결합된 Buffer 객체를 제공합니다. 사용자는 메모리 복사를 통해 여러 개의 작은 버퍼를 하나로 병합하는 전통적인 방법을 피하면서 결합된 버퍼를 버퍼를 운영하는 것처럼 편리하게 사용할 수 있습니다.

(3) Netty의 파일 전송은 transferTo 메서드를 사용합니다. 이 메서드는 파일 버퍼의 데이터를 대상 채널로 직접 보낼 수 있어 기존 순환 쓰기 방법에서 발생하는 메모리 복사 문제를 방지합니다.

3. 참조 카운팅 및 풀링 기술

Netty에서는 적용된 각 버퍼가 Netty에게 매우 귀중한 리소스가 될 수 있으므로 메모리 적용 및 재활용에 대한 더 많은 제어권을 얻기 위해 Netty에서는 참조 카운팅을 기반으로 메모리 관리를 구현했습니다. Netty의 Buffer 사용은 직접 메모리(DirectBuffer)를 기반으로 하여 I/O 작업의 효율성을 크게 향상시킵니다. 그러나 DirectBuffer 및 HeapBuffer에 비해 높은 I/O 작업 효율성 외에도 본질적인 단점도 있습니다. 즉, DirectBuffer용 애플리케이션은 HeapBuffer보다 효율성이 떨어지므로 Netty는 참조 카운팅, 즉 풀링 사용과 함께 PolledBuffer를 구현합니다. 참조 카운트가 0이 되면 Netty는 Buffer를 풀로 재활용하고 아무도 적용하지 않습니다. 다음 번에는 버퍼가 재사용됩니다.

요약

Netty는 본질적으로 Selector를 멀티플렉서로, EventLoop를 반복기로, Pipeline을 이벤트 프로세서로 사용하여 Reactor 패턴을 구현한 것입니다. 그러나 일반적인 Reactor와 달리 Netty는 직렬화를 사용하고 파이프라인에서 책임 체인 모델을 사용합니다.

Netty의 버퍼는 NIO의 버퍼에 비해 최적화되어 성능이 크게 향상되었습니다.

위 내용은 Java의 netty 원칙은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.