관리 메뉴

HAMA 블로그

Netty 버전 별 차이점 정리 본문

Netty, Java IO

Netty 버전 별 차이점 정리

[하마] 이승현 (wowlsh93@gmail.com) 2015. 9. 4. 18:04


스택오버플로우에 이희승씨가 요렇게 남겼네요.


- 3.x 은  deprecated 되었습니다. 유저들이 아직 많이들 사용하니깐 유지보수는 해드려요.

- 4.0 는 현재 안정화 버전입니다. 먼가 의심스러우면 요걸 쓰세요.

- 4.1 는 4.0 의 하위호환버전입니다.  몇가지 쩌는 것들을 추가했는데요. HTTP/2 나  asynchronous DNS resolver 같은거 말이죠.  그래서  4.1 은 이미 님의 어플이 4.0에서 돌아간다면 새버전으로 바꾸시는게 어떨까 하네요.

- 5.0 은 하위호환되지 않는 버전입니다.이건 4.0 처럼 rewrite 된건 아닌데요. 몇가지 디자인 결함을 바로 잡았습니다. Netty4 를 사용하고계시다면 Netty5 로 바꾸려면 몇가지 코드를 수정해야합니다.그건 Netty 3 을 Netty4 로 포팅하는것과는 다릅니다. 결국 4.x 도 deprecated  될것이고 5.0이 안정화 버전이 되겠지요.





4.0 의 주요 새로운점 


1. Buffer API changes


* ChannelBuffer  ByteBuf

- 패키지가 분리되었고 네티를 쓰지 않더라도 독립적으로 buffer API 를 쓸수있도록 하였다.그에 따라  이       름이 바뀌었다. 

- 새로운 버퍼를 생성하는 ChannelBuffers 는  Unpooled  과 ByteBufUtil 두개의 유틸리티 클래 스로 나뉘었으며, 이름에서 나타나듯이 4.0에서 새로 만들어진 풀링기능을 가진 ByteBufs가 
ByteBufAllocator  에 의해  만들어진다.

* ByteBuf is not an interface but an abstract class

* Most buffers are dynamic with maximum capacity


- 3.x 에서는 고정/동적 버퍼가 있었는데, 4.0 이래로는 모든 버퍼가 동적이 되었다. 또한 이전의 동적버퍼들보다

 더 나아졌다. ByteBuf.capacity(int newCapacity) 때문에 줄거나 늘어나는 작업을 하기 쉬워졌다.

 단 wrappedBuffer 로 생성된것은 예외다.

// No more dynamicBuffer() - use buffer().
ByteBuf buf = Unpooled.buffer();

// Increase the capacity of the buffer.
buf.capacity(1024);
...

// Decrease the capacity of the buffer (the last 512 bytes are deleted.)
buf.capacity(512);

 * Pooled buffers

  Netty 4 는 고성능 버퍼풀을 제공하며 jemalloc 의 다른 버전으로  buddy allocation 과 slab allocation 를 
   결합시켰습니다.  이것을 이용하면 좋은점은 

  • 버퍼에 대한 빈번한 메모리 할당/해제로 일어나는 GC 의 부담을 덜수있습니다.
  • 새로운 버퍼를 만들때 일어나는 메모리 대역소비를 줄였습니다. 새버퍼를 만들때는 필연적으로 0 를 채우죠.
  • 다이렉터 버퍼의 해제를 적시에 일어나게 합니다.

만약 사용자가 풀되지 않는 버퍼를 얻길 원치 않는다면, ByteBufAllocator 로 부터 버퍼를 가져오면 됩니다.

Channel channel = ...;
ByteBufAllocator alloc = channel.alloc();
ByteBuf buf = alloc.buffer(512);
....
channel.write(buf);

ChannelHandlerContext ctx = ...
ByteBuf buf2 = ctx.alloc().buffer(512);
....
channel.write(buf2)

일단 ByteBuf 가 리모트 피어로 쓰여지면 자동적으로  버퍼를 가져온 풀로 회수됩니다.

디폴트  ByteBufAllocator  는 PooledByteBufAllocator.만약 이것을 쓰기 원치 않으면 Channel.config().set

Allocator(...) 를 통해 원하는것을 넣어주면됩니다.UnpooledByteBufAllocator 이런거 말이죠.

노트:  현재 기본할당자는 UnpooledByteBufAllocator 입니다. 메모리릭의 존재가 확인되지 않는다면 

PooledByteBufAllocator 가 디폴트로 사용될것입니다.


ByteBuf 는 항상 레퍼런스 카운트 기능이 사용됩니다.


ByteBuf 의 더 예측가능한 생존싸이클을 컨트롤하기위해 Netty 는 더이상 가비지컬렉션에 의존하지 않고 레퍼런스 카운터를 사용합니다. 기본적인 룰은 :

  • 버퍼가 할당되면 레퍼런스 카운트는  1 입니다.
  • 레퍼런스 카운트가 0 이되면 해제되며  풀로 되돌아갑니다.
  • 다음은 IllegalReferenceCountException 를 일으킵니다.

    • 레퍼런스 카운트 0 인 버퍼로의 접근
    • 마이너스 값으로 레퍼런스카운트 변경 
    • Integer.MAX_VALUE 이상으로 레퍼런스카운트 증가
  • Derived buffers (e.g. slices and duplicates) 와  swapped buffers (i.e. little endian buffers) 는 그것을 생성하기위해 사용한  버퍼와 레퍼런스 카운트를 공유합니다. 


ByteBuf 가 ChannelPipeline 에서 사용될때 추가적인 룰이 있는데 명심하십시요.

  • 각각의 파이프라인안의 인바운드 ( upstream ) 핸들러는 받은 메세지를 릴리즈 해야합니다. 네티는 자동적으로 릴리즈 해주지 않아요.

    • 노트: 코덱 프레임워크는 자동적으로 릴리즈 합니다. 그리고 유저는 만약 다음 핸들러로 메세지를 넘겨주고 싶을때는 반드시 레퍼런스카운트를 증가시켜줘야합니다.
  • 아웃바운드 (downstream) 메세지가 파이프라인의 끝에 도달하면 네티는 쓰고나서 릴리즈합니다.


   자동 버퍼 릭 탐지

레퍼런스 카운팅이 강력하더라도 에러가 발생하기 쉽습니다. 버퍼를 해제하는것을 까먹을수가 있는데 이때 릭 탐지기는 로그를 써줍니다. 릭 탐지기는 PhantomReference 과 스택트레이스를 얻기때문에 높은 성능낭비를 가져올수있기때문에 릭을 발견하기위해 오랫동안 돌려본후에 기능을 꺼야합니다.

 -Dio.netty.noResourceLeakDetection  JVM 옵션으로 끌수있습니다.


2. Channel API changes




4.1 의 주요 새로운점 







5.0 의 주요 새로운점 

http://netty.io/wiki/new-and-noteworthy-in-5.0.html 정리중 



Comments