brunch

You can make anything
by writing

C.S.Lewis

by myner Nov 08. 2020

네티 ByteBuf

feat. 디자인 패턴

ByteBuf 는 Netty 프레임 워크에서 가장 중요한 클래스 중 하나이며 간단히 말해서 ByteBuf는 java.nio.ByteBuffer의 Netty 버전이다.


ByteBuf 논리 구조

클래스 이름에서 알 수 있듯이 ByteBuf는 논리적으로 바이트 컨테이너이다. ByteBuf의 데이터는 다음 그림과 같이 두 개의 포인터로 세 부분으로 나뉜다.


reader index 앞의 데이터는 읽은 데이터이며 이러한 데이터는 버릴 수 있다.

reader index부터 시작하여 writer index 이전의 데이터는 읽을 수있는 데이터이다.

writer index에서 부터는 쓰기 가능한 영역이다.


읽기 영역과 쓰기 가능 영역에 여유 공간이있는 한 ByteBuf는 동시에 데이터를 읽고 쓸 수 있으며, java.nio.ByteBuffer는 쓰기 상태에서 읽기 상태로 전환하기 위해 flip() 메서드를 호출해야한다.


ByteBuf 읽기 및 쓰기 포인터

1. ByteBuffer에서 읽기 및 쓰기 포인터는 모두 위치에 있고 ByteBuf에서는 읽기 및 쓰기 포인터가 각각 readerIndex 및 writerIndex이다.

2. 직관적으로 ByteBuffer는 두 포인터의 기능을 수행하기 위해 하나의 포인터 만 사용하여 변수를 저장하는 것처럼 보이지만 ByteBuffer의 읽기 및 쓰기 상태가 전환되면 flip 메서드를 호출해야하며 다음 쓰기 전에 Buffe에서 내용을 읽은 후 clear 메서드를 호출한다.

3. 각 읽기 전에 플립을 호출하고 쓰기 전에 클리어 호출 이것은 의심 할 여지없이 개발에 지루한 단계를 가져 오며, 내용을 읽지 않고는 쓸 수없는 매우 유연하지 않다.

4. 반대로 ByteBuf를 살펴 보겠다. 읽기시에는 readerIndex 포인터, 쓰기시에는 writerIndex 포인터에만 의존한다. 읽기 및 쓰기 전에 해당 메서드를 호출 할 필요가 없으며 한 번에 모두 읽어야한다는 제한이 없다.


제로 카피

1. Netty는 ByteBuffer를 수신 및 전송하기 위해 DIRECT BUFFERS를 채택하고 바이트 버퍼의 두 번째 사본이 필요없이 소켓 읽기 및 쓰기를 위해 힙 외부의 직접 메모리를 사용한다.

2. 소켓 읽기 및 쓰기에 기존 힙 메모리 (HEAP BUFFERS)를 사용하는 경우 JVM은 힙 메모리 버퍼를 직접 메모리에 복사 한 다음 소켓에 쓴다. 힙이 아닌 직접 메모리와 비교하여 메시지에는 전송 프로세스 중에 하나 이상의 버퍼 메모리 사본이 있다.

3. Netty는 여러 개의 ByteBuffer 객체를 통합 할 수있는 결합 된 Buffer 객체를 제공한다. 사용자는 결합 된 Buffer를 Buffer처럼 쉽게 조작 할 수 있으므로 여러 개의 작은 버퍼를 하나의 큰 버퍼로 병합하는 전통적인 메모리 복사 방법을 피할 수 있다.

4. Netty의 파일 전송은 파일 버퍼의 데이터를 대상 채널로 직접 전송할 수있는 transferTo 방법을 사용하여 기존의 순환 쓰기 방법으로 인한 메모리 복사 문제를 방지한다.


레퍼런스 카운팅 및 풀링 기술

1. Netty에서 적용된 각 버퍼는 Netty의 귀중한 자원이 될 수 있으므로 Netty는 메모리의 응용 및 복구에 대한 제어력을 높이기 위해 참조 계수 방법을 기반으로 메모리를 구현한다.

2. Netty의 버퍼 사용은 직접 메모리 (DirectBuffer)를 기반으로하여 I / O 작업의 효율성을 크게 향상시킨다.

3. 그러나 DirectBuffer 및 HeapBuffer와는 달리 I / O 작업의 효율성이 높을뿐만 아니라 DirectBuffer의 응용 프로그램이 HeapBuffer보다 효율성이 떨어지는 단점이 있다.

4. 따라서 Netty는 참조 횟수를 결합하여 PolledBuffer, 즉 풀링 사용을 구현한다. 참조 횟수가 0 일 때 Netty는 버퍼를 풀로 재활용하고 다음 버퍼 응용 프로그램에서 어느 시점에서 재사용된다.


요약  

별도의 읽기 인덱스와 쓰기 인덱스

flip 메서드 없이 읽기 쓰기 가능

가변 바이트 버퍼

프레임워크 레벨의 바이트 버퍼 풀 제공

복합 버퍼

Java ByteBuffer와 호환됨

자료형에 따른 클래스를 제공하지 않고 별도의 method로 제공


바이트 버퍼 풀링

Netty의 가장 중요한 특징은 바이트 버퍼 풀링이다.


ByteBuf는 각자의 reference counting을 가지고 있어 객체의 재활용이 가능하며 GC 에 부담을 적게 준다.

보통 Direct Allocating, Deallocating 비용이 비싸기 때문에 사용된다.


객체 생성 등의 비용을 최대한으로 줄이기 위해 풀링 방법을 사용하며 다이렉트/힙 버퍼에 대해 모두 사용할 수 있다. 이러한 풀링으로 인해 GC에 부담을 적게 주며 메모리를 다른 곳에 더 사용할 수 있도록 한다.


ReferenceCountUtil 클래스에 정의된 retain/release 메소드를 사용하여 풀링의 크기를 관리할 수 있으며, 

C언어와 같이 변수에 부호가 없는 경우 Netty는 한단계 더 큰 데이터형에 저장한다.


retain : 자체적인 reference counting 증가

release : 자체적인 reference counting 감소. 만약에 count가 0이라면 객체를 할당 해제하거나 pool로 되돌려준다. 이 작업은 객체에 마지막으로 접근한 지점에서 수행한다.


ChannelPipeline 내부에서 사용되는 ByteBuf는 몇가지 특징을 더 가지고 있는데 inbound handler에서 사용되는 ByteBuf는 자동으로 release 하지 않으며 release를 직접 수행해야한다. outbound handler에서 사용되는 ByteBuf는 write 한 이후에 자동적으로 release 수행한다.


ByteBufAllocator-Abstract 팩토리 패턴

Netty에서 ByteBuf 인스턴스는 일반적으로 ByteBufAllocator에 의해 생성되어야한다.

Allocator의 buffer() 메서드는 ByteBuf의 인스턴스를 만들고 ByteBuf의 alloc() 메서드는 자신의 Allocator를 만들기 위해 반환된다.. ByteBufAllocator 구현은 추상 팩토리 패턴을 사용한다.


CompositeByteBuf - Composite 패턴

CompositeByteBuf를 사용하면 여러 ByteBuf를 하나의 큰 Buf로 처리 할 수 있다. ByteBufAllocator는 CompositeByteBuf를 생성하기 위한 compositeBuffer() 팩토리 메소드를 제공한다.


ByteBufInputStream - Adpater 패턴

ByteBufInputStream 은 어댑터 모드 를 사용하므로 ByteBuf를 Java InputStream으로 사용할 수 있다. 같은 방식으로 ByteBufOutputStream 을 사용하면 ByteBuf를 OutputStream으로 사용할 수 있다.


ReadOnlyByteBuf - Deocrator 패턴

ReadOnlyByteBu f는 어댑터 모드 를 사용하여 ByteBuf를 읽기 전용으로 전환한다. ReadOnlyByteBuf는 Unpooled.unmodifiableBuffer (ByteBuf) 메서드를 호출하여 얻는다.


ByteBuf - Factory 패턴

앞서 언급했듯이 생성자를 통해 직접 ByteBuf 인스턴스를 생성 할 필요가 거의 없지만 Allocator를 통해 생성된다. 데코레이터 패턴에서 ByteBuf를 얻는 또 다른 방법은 다음 과 같이 ByteBuf의 팩토리 메서드 를 호출하는 것임을 알 수 있다.


ByteBufProcessor - visitor + 반복자 패턴 ?

ByteBuf는 방문자 모드 와 반복자 모드 가 혼합 된 것처럼 보이는 ByteBuf의 데이터에 대한 특정 처리 또는 검색을 수행하기 위해 4 개의 forEachByte() 메서드를 제공 



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 

https://runningup.tistory.com/entry/부트스트랩-1 

https://juyoung-1008.tistory.com/23


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari