標籤:trap pen except 通過 style use span async 系統
Netty介紹
Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.
netty 官網如是說。大概意思是netty 是一個非同步事件驅動的網路應用程式框架,能夠高速開發可維護的高效能網路server、client應用。
asynchronous非同步,netty中非常大一部分方法都是非同步,配合事件驅動模型可以處理很多其它請求。
netty的一致性API相比於JDK的API有非常高的使用者體驗,
使用起來也非常方便。netty使我們不用考慮太多底層問題和各種各樣的bug。讓開發人員可以更專註於商務邏輯。
netty現狀
這是netty在github的首頁 https://github.com/netty/netty 。眼下已經有5000+的star
非常多知名公司和項目在使用netty,包含facebook、IBM、RedHat等大公司和Spark、Finagle、Nifty等項目。
很多其它的adaptor在http://netty.io/wiki/adopters.html。
眼下netty的主要維護版本號碼有3.x 、4.x 、5.x。
我接觸比較多的是5.x,非常多架構是基於3.x開發的。3 4 5之間有一些區別,
我覺得新的版本號碼是在以往的經驗和教訓上開發出來的。用的基本的5。
netty做什麼事情
http://netty.io/images/components.png
netty對JDK的NIO進行了封裝,為開發人員提供了一致性和良好的API。
netty提供了非常多更好的"JDK API"實現。比方它的ByteBuf。
快的定義是什麼
快, 我想儘快得到一個東西和我想儘快得到全部的東西。
在ServerClient編程中。前者能夠覺得是low latency, 更低的延遲, 儘快完畢一個請求; 而後者是high throughput。更大的系統輸送量。
可擴充性scalability
我們須要系統在大量請求時可以平滑的減少效能而且當我們提升硬體設定時可以獲得對應的效能提升。
不同paradigm的Server1.單線程模式
handle假設沒有在新線程中運行那麼while迴圈將會block在handle處理上,一次僅僅能處理一個請求。
</pre></h3><h3 style="margin:30px 0px 0px; font-size:16px; line-height:1.5; color:rgb(51,51,51); font-family:Arial,sans-serif"><pre name="code" class="java">ServerSocket serverSocket = new ServerSocket(port);while(true){ Socket socket = serverSocket.accept(); handle(socket);}private void handle(Socket socket){ try( InputStream inputStream = socket.getInputStream(); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); ){ String line; while((line = br.readLine()) != null){ System.out.println("Read line : " + line); writer.println(line); } } catch (IOException e) { e.printStackTrace(); }}
2.多線程運行
一個請求相應一個線程。當湧現大量請求時線程的建立、銷毀、ContextSwitch的overhead都回影響系統效能
ServerSocket serverSocket = new ServerSocket(port);while(true){ Socket socket = serverSocket.accept(); new Thread(){ @Override public void run(){ handle(socket); } }.start();}
3.線程池
線程池並沒有解決一請求一線程的問題。僅僅能有限降低線程建立的開銷和控制線程的建立。
Executor executor = Executors.newFixedThreadPool(100);ServerSocket serverSocket = new ServerSocket(port);while(true){ Socket socket = serverSocket.accept(); executor.execute(new Runnable() { @Override public void run() { handle(socket); } });}
4.JDK NIO
思考一下。問題出在handle(socket)上。InputStream 和OutputStream的基於位元組的讀寫方式,的read write操作都是block操作,當沒有bytes能夠read或者write時運行線程都會block。
graph from 《netty in action》
JDK1.4 提供了nio實現, nio當時有兩種說法,new io 和non blocking io, 如今過去這麼多年了。已經不再new了,大家都稱之為non blocking io。
介紹幾個核心java.nio包中包含一些Buffer,核心是ByteBuffer,程式與網路層互動還是以byte流的形式。ByteBuffer有heap buffer 和direct buffer(non heap buffer)兩種。head buffer 在Java heap 堆中。
使用byte數組作為其內部資料結構,direct buffer 在Java 堆記憶體之外。
java.nio.channels中有Channel和Selector兩個比較重要的類。Channel代表了一個和能夠讀寫的目標的通道,實作類別有FileChannel、ServerSocketChannel、SocketChannel等,Selector用於注冊Channel感興趣的事件。這樣我們就能夠實現asynchronous event-driven了,實現一個線程處理多個請求,多工(multiplexing)
ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.bind(new InetSocketAddress(port));serverChannel.configureBlocking(false);Selector selector = Selector.open();serverChannel.register(selector, SelectionKey.OP_ACCEPT);while(true){ selector.select(); Set<SelectionKey> selectionKeySet = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeySet.iterator(); while(iterator.hasNext()){ SelectionKey selectionKey = iterator.next(); iterator.remove(); if(selectionKey.isAcceptable()){ ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel(); SocketChannel client = server.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE, ByteBuffer.allocate(BUFFER_SIZE)); } if(selectionKey.isReadable()){ SocketChannel client = (SocketChannel) selectionKey.channel(); ByteBuffer buf = (ByteBuffer) selectionKey.attachment(); client.read(buf); } if(selectionKey.isWritable()){ SocketChannel client = (SocketChannel) selectionKey.channel(); ByteBuffer buf = (ByteBuffer) selectionKey.attachment(); buf.flip(); client.write(buf); buf.compact(); } }}
這個CPU佔用比較嚴重
5. netty nio
為了示範把功能放到了一個塊裡。netty中我們的byte解析業務實現都能夠用ChannelHandler來實現,ChannelHandler串聯在ChannelPipeline形成了一種類外掛程式的形式。通過Filter chain使各個邏輯相互獨立可複用。
int port = 8090;EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap();try{ serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<io.netty.channel.socket.SocketChannel>() { @Override protected void initChannel(io.netty.channel.socket.SocketChannel ch) throws Exception { ch.pipeline().addLast("echoHandler", new ChannelHandlerAdapter() { @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.write(msg); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }); } }); ChannelFuture f = serverBootstrap.bind(new InetSocketAddress(port)).sync(); f.channel().closeFuture().sync();} catch (InterruptedException e) { e.printStackTrace();} finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully();}
未完待續。。
。
continuning...
很多其它推薦資料
netty in action
http://g.oswego.edu/
netty開發教程(一)