【通信】Java NIO模型

目錄

1.可伸縮的網絡服務

1.1 可伸縮的目標

1.2 解決方案

2.事件驅動設計

3.Reactor模式

3.1 單線程版本

3.2 多線程版本

3.2.1 工作線程多線程(並行工作者)

3.2.2 Reactor多線程

4.NIO API

4.1 Buffer

4.2 Channel通道

4.2.1 SelectableChannel

4.2.2 SocketChannel

4.2.3 ServerSocketChannel

4.2.4 FileChannel

4.3 Selector

4.3.1 SelectionKey


1.可伸縮的網絡服務

經典BIO網絡服務端代碼設計 thread-per-request,每個處理都可以在獨立線程中執行。

存在着很多問題,爲了更好的可伸縮對其進行優化。

1.1 可伸縮的目標

  1. 負載增加時(更多客戶端連接)的優雅退化
  2. 性能隨着資源(CPU、內存、磁盤、帶寬)不斷提高
  3. 同時滿足可用性和性能目標:低時延、滿足高峯需求、服務質量可調控

1.2 解決方案

分而治之,總體服務分爲以上5個處理階段,網絡服務基礎處理結構

  1. 讀取請求read
  2. 解碼請求decode
  3. 業務處理process
  4. 響應編碼encode
  5. 寫入響應write

分:將整個處理過程分成幾個子任務,每個任務執行一個非阻塞的操作

治: 藉助JavaNIO機制,IO事件(select)觸發分發給自任務handler非阻塞地讀寫數據。NIO中select方法是阻塞的,而read、write讀寫是非阻塞的,由於多路複用,多個通道多種事件均可觸發select返回,大大減少了阻塞的事件,充分利用了CPU資源。

2.事件驅動設計

事件驅動設計依賴Java NIO機制

更高效

資源少(不需要每個客戶端都創建線程)

低負載 更少的線程切換

難實現

劃分非阻塞操作

需跟蹤服務邏輯狀態

3.Reactor模式

Reactor顧名思義,反應,當IO事件發生時程序做出反應,包含兩種角色:Reactor、handler(包括acceptor和IOhandler)

1.Reactor響應IO事件,主要調用select阻塞方法查找事件,分發事件給對應handler處理

2.handler執行非阻塞操作(類似於事件監聽器),通常根據事件類型分爲Acceptor和IOHandler,Acceptor調用accept()非阻塞方法接收連接、IOHandler調用read()和write()讀寫數據

兩個角色的協作:註冊監聽,需要將handler與具體的事件聯繫起來,如accept事件、read事件、write事件

3.1 單線程版本

單線程版本是最簡易基礎版本,ReactorAcceptorIOHandler在一個線程中處理,在事件觸發時,Reactor根據事件的類型調用給不同的handler的處理方法,如Accept事件則調用Acceptor.runt(),read事件則調用IOHandler.run()。

3.2 多線程版本

戰略性地添加線程以實現可伸縮性,主要適用於多核機器。哪些步驟可以添加線程呢?主要又兩個方案:

增加worker工作線程 業務處理handler  
增加Rector線程 響應事件Reactor  
  1. 增加worker工作線程進行handler處理
  2. 增加Rector線程響應IO事件

3.2.1 工作線程多線程(並行工作者)

工作線程只處理非阻塞的操作,不涉及IO事件的阻塞監聽。如下圖所示,還是只有一個Reactor(只有一個selector其上綁定了多種事件類型,如Accept、Read、Write)。當IO事件觸發其selector的select方法返回後,分發給工作線程處理。

Accept事件:工作線程處理Acceptor中的處理邏輯,接收請求建立新連接,並將新連接的讀寫事件註冊進Reactor的selector選擇器上!

Read事件:工作線程Handler依次處理read讀取字節流、decode字節流解碼、compute業務計算、encode編碼成字節流

Write事件:工作線程將準備好的字節流發送給對端

3.2.2 Reactor多線程

主Reactor響應IO事件後,如果是ACCEPT事件則分發給Acceptor處理,如果是讀寫事件則分發給subReactor進行處理。

Acceptor處理邏輯:接受請求,建立讀寫通道,註冊該通道的讀寫事件到mainReactor

subReactor邏輯:提交讀任務到線程池,寫數據到通道

worker線程邏輯:處理線程池中的讀任務

4.NIO API

4.1 Buffer

類似與數組,用於存儲讀寫數據


子類有ByteBuffer(CharBuffer, LongBuffer, etc not shown.)

4.2 Channel通道

4.2.1 SelectableChannel

常用的都是這個類的子類

abstract class SelectableChannel implements Channel {
	int validOps();
	boolean isRegistered();
	SelectionKey keyFor(Selector sel);
	SelectionKey register(Selector sel, int ops)
	throws ClosedChannelException;
	void configureBlocking(boolean block)
	throws IOException;
	boolean isBlocking();
	Object blockingLock();
}

4.2.2 SocketChannel

主要是可以讀寫

abstract class SocketChannel implements ByteChannel ... {
	static SocketChannel open() throws IOException;
	Socket socket();
	int validOps();
	boolean isConnected();
	boolean isConnectionPending();
	boolean isInputOpen();
	boolean isOutputOpen();
	boolean connect(SocketAddress remote) throws IOException;
	boolean finishConnect() throws IOException;
	void shutdownInput() throws IOException;
	void shutdownOutput() throws IOException;
	int read(ByteBuffer dst) throws IOException;
	int read(ByteBuffer[] dsts, int offset, int length)
	throws IOException;
	int read(ByteBuffer[] dsts) throws IOException;
	int write(ByteBuffer src) throws IOException;
	int write(ByteBuffer[] srcs, int offset, int length)
	throws IOException;
	int write(ByteBuffer[] srcs) throws IOException;
}

4.2.3 ServerSocketChannel

響應accept事件

abstract class ServerSocketChannel extends ... {
	static ServerSocketChannel open() throws IOException;
	int validOps();
	ServerSocket socket();
	SocketChannel accept() throws IOException;
}

4.2.4 FileChannel

abstract class FileChannel implements ... {
	int read(ByteBuffer dst);
	int read(ByteBuffer dst, long position);
	int read(ByteBuffer[] dsts, int offset, int length);
	int read(ByteBuffer[] dsts);
	int write(ByteBuffer src);
	int write(ByteBuffer src, long position);
	int write(ByteBuffer[] srcs, int offset, int length);
	int write(ByteBuffer[] srcs);
	long position();
	void position(long newPosition);
	long size();
	void truncate(long size);
	void force(boolean flushMetaDataToo);
	int transferTo(long position, int count,
	WritableByteChannel dst);
	int transferFrom(ReadableByteChannel src,
	long position, int count);
	FileLock lock(long position, long size, boolean shared);
	FileLock lock();
	FileLock tryLock(long pos, long size, boolean shared);
	FileLock tryLock();
	static final int MAP_RO, MAP_RW, MAP_COW;
	MappedByteBuffer map(int mode, long position, int size);
}

4.3 Selector

選擇器,選擇ready的事件響應

abstract class Selector {
	static Selector open() throws IOException;
	Set keys();
	Set selectedKeys();
	int selectNow() throws IOException;
	int select(long timeout) throws IOException;
	int select() throws IOException;
	void wakeup();
	void close() throws IOException;
}

4.3.1 SelectionKey

事件key,綁定事件類型和通道

abstract class SelectionKey {
	static final int OP_READ, OP_WRITE,
	OP_CONNECT, OP_ACCEPT;
	SelectableChannel channel();
	Selector selector();
	boolean isValid();
	void cancel();
	int interestOps();
	void interestOps(int ops);
	int readyOps();
	boolean isReadable();
	boolean isWritable();
	boolean isConnectable();
	boolean isAcceptable();
	Object attach(Object ob);
	Object attachment();
}

具體用法請戳

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章