980
技術社區[雲棲]
《Netty官方指南》把Netty當做一個通用的庫
Netty是一個用來開發基於網絡應用的框架,同時也提供了其他與socket I/O無關的基礎類。
Buffer API
io.netty.buffer 提供了一個通用的buffer類型ByteBuf類。他與java.nio.ByteBuffer類似,但是更加性能,對用戶更友好和可擴展。
友好性
當你在調用java.nio.ByteBuffer.flip()時,有沒有考慮為什麼buffer沒有包含所有的信息,他在ByteBuf 從不會發生,因為他有2個index,一個是讀取,另一個是寫入。
ByteBuf buf = ...;
buf.writeUnsignedInt(42);
assertThat(buf.readUnsignedInt(), is(42));
他擁有豐富的讀取方法能更加方便的讀取buffer的內容。例如,他擁有方法能讀取無符號,有符號數字和字符串。
可擴展
你無法繼承java.nio.ByteBuffer,但是你可以繼承ByteBuf。一個抽象的實現可以為你帶來方便,你可以基於他做自己的buffer實現,例如基於文件的緩存,buffer組合或者更加複雜的實現。
高性能
當一個新的java.nio.ByteBuffer 被分配,他的內容將以零字符串進行填充。零字符串填充會帶來CPU和內存的消耗。通常buffer馬上會被數據源填充,因此零字符串填充並不是最好的方式。
需要指出的是,java.nio.ByteBuffer是基於JVM內存收集的,他能在Heap內存工作的不錯,但是直接內存訪問就不行。從設計上說,直接內存訪問通常會存活很長一段時間。因此,分配許多短時間直接內存buffer通常會導致OutOfMemoryError,而且,回收一個直接內存所使用的API通常不是很快。
一個ByteBuf的生命周期是基於他被引用的次數,當引用數為0,他底層的內存區(byte[] or direct buffer)將被回收,或者返回內存池。
Netty也提供一種buffer池的實現,並且不浪費CPU和內存來以零來填充。
ByteBufAllocator alloc = PooledByteBufAllocator.DEFAULT;
ByteBuf buf = alloc.directBuffer(1024);
...
buf.release(); // The direct buffer is returned to the pool.
然而,引用數並不是銀彈。如果在他底層內存換回內存池之間,JVM就收集了buffer,內存泄漏最終會導致池的資源被耗盡。
為了幫助你調試內存泄漏,Netty提供了一個泄露檢測機製能靈活的在你的應用性能和泄露報表之間權衡,更多信息,請參照Reference-counted-objects
Listenable futures and event loops
執行一個異步任務——調度一個任務,並在任務完成的時候得到通知,應該很普遍而且很方便。當java.util.concurrent.Future 出現,我們並沒有激動很久。我們需要阻塞以等待任務完成通知。在異步編程,你需要指定任務完成,你做什麼而不是被動等待結果。
io.netty.concurrent.Future是JDK Future的子類,他允許你添加listener,而且當future完成時,這個listener會被eventloop調用。
io.netty.util.concurrent.EventExecutor是繼承自java.util.concurrent.ScheduledExecutorService的單線程event loop。你可以建立自己的event loop或者使用一個豐富功能的task executor。通常,你會建立多個EventExecutors來利用計算機的並行計算能力。
EventExecutorGroup group = new DefaultEventExecutorGroup(4); // 4 threads
Future<?> f = group.submit(new Runnable() { ... });
f.addListener(new FutureListener<?> {
public void operationComplete(Future<?> f) {
..
}
});
...
The global event loop
有些時候,你想要一個唯一的executor,他一直可用並且不需要生命周期管理。GlobalEventExecutoris是一個單線程的EventExecutor 他會在他的線程延遲啟動,在沒用需要執行的任務後停止。
Platform-dependent operations
注意這個功能隻是內部使用,我們在考慮在有足夠需求的情況下,再把他從internal包中移出。
io.netty.util.internal.PlatformDependent 提供依賴於平台和潛在不安全的操作。你可以認為他是一個在sun.misc.Unsafe 和其他依賴平台API的上麵一個薄薄的層。
Other utilities
為了構建一個高效的網絡應用框架,我們引入了一些工具,你能找到一些有用的。
Thread-local object pool
如果你的程序現在是長時間運行,而且需要分配許多同類型的短生命周期對象,你可以使用thread local對象池Recycler類。他減少了大量的內存垃圾,節省了內存的消耗和垃圾收集。
public class MyObject {
private static final Recycler<MyObject> RECYCLER = new Recycler<MyObject>() {
protected MyObject newObject(Recycler.Handle<MyObject> handle) {
return new MyObject(handle);
}
}
public static MyObject newInstance(int a, String b) {
MyObject obj = RECYCLER.get();
obj.myFieldA = a;
obj.myFieldB = b;
return obj;
}
private final Recycler.Handle<MyObject> handle;
private int myFieldA;
private String myFieldB;
private MyObject(Handle<MyObject> handle) {
this.handle = handle;
}
public boolean recycle() {
myFieldA = 0;
myFieldB = null;
return handle.recycle(this);
}
}
MyObject obj = MyObject.newInstance(42, "foo");
...
obj.recycle();
User-extensible enum
對於一些靜態的變量,enum非常適合,但是你無法繼承他。當你需要在運行時增加更多的變量或者允許第三方定義更多的變量,考慮使用io.netty.util.ConstantPool
public final class Foo extends AbstractConstant<Foo> {
Foo(int id, String name) {
super(id, name);
}
}
public final class MyConstants {
private static final ConstantPool<Foo> pool = new ConstantPool<Foo>() {
@Override
protected Foo newConstant(int id, String name) {
return new Foo(id, name);
}
};
public static Foo valueOf(String name) {
return pool.valueOf(name);
}
public static final Foo A = valueOf("A");
public static final Foo B = valueOf("B");
}
private final class YourConstants {
public static final Foo C = MyConstants.valueOf("C");
public static final Foo D = MyConstants.valueOf("D");
}
Netty使用ConstantPool 來定義ChannelOptions,所以非核心的transports可以以安全的方式定義transport相關的選項。
Attribute map
使用io.netty.util.AttributeMap 接口來定義一個快速,類型安全,線程安全的key-value集合。
public class Foo extends DefaultAttributeMap {
...
}
public static final AttributeKey<String> ATTR_A = AttributeKey.valueOf("A");
public static final AttributeKey<Integer> ATTR_B = AttributeKey.valueOf("B");
Foo o = ...;
o.attr(ATTR_A).set("foo");
o.attr(ATTR_B).set(42);
就像你已經知曉的,AttributeKey 是一個常量。
Hashed wheel timer
HashedWheelTimer是一個可擴展的,可用於替代java.util.Timer 或者java.util.concurrent.ScheduledThreadPoolExecutor。他可以處理許多計劃的任務,並且他很容易取消任務。
foo | Schedule a new task | Cancel a task |
---|---|---|
HashedWheelTimer | O(1) | O(1) |
java.util.Timer and ScheduledThreadPoolExecutor | O(logN) | O(logN) where N = number of pending tasks |
在它的內部,使用一個Hash Table,大多數timer的操作,Hash Table的主鍵存放調度任務到yield的常數時間(it uses a hash table whose key is a task’s timing to yield constant time for most timer operations)。(java.util.Timer 使用二進製堆。)
更多有關hashed wheel timer,請參閱these slides (“Hashed and Hierarchical Timing Wheels,” Dharmapurikar)and this paper (“Hashed and Hierarchical Timing Wheels: Data Structures for the Efficient Implementation of a Timer Facility,” Varghese and Lauck)。
下麵的類也非常有用,但是你可以在其他類例如Guava中找到類似的。
- io.netty.util.CharsetUtil 提供常用的java.nio.charset.Charsets
- io.netty.util.NetUtil 提供常用的基於網絡的常量例如IPv4和IPv6的回送地址。
- io.netty.util.DefaultThreadFactory 是一個通用的ThreadFactory 實現,方便你配置線程池。
與 Guava and JDK8 的比較
因為Netty設法最小化依賴,它的許多工具類與其它的常用庫類似,例如Guava。
這樣的庫提供了多樣的工具類和其它的數據類型,這使我們使用JDK少些痛苦,而且這樣的庫也做的不錯。
Netty關注於提供
- 異步編程
- 底層操作
- 堆外內存訪問
- 訪問底層進行操作
- 平台獨立操作
Java有時采取並加入了Netty的一些類。例如,JDK 8 加入了CompleteFuture,這與io.netty.util.concurrent.Future相重疊,在這樣的情況下Netty提供了很好的移植方式。在API的開發上,我們考慮移植性。
最後更新:2017-05-18 20:31:20