目錄
4.2.4 FileChannel
1.可伸縮的網絡服務
經典BIO網絡服務端代碼設計 thread-per-request,每個處理都可以在獨立線程中執行。
存在着很多問題,爲了更好的可伸縮對其進行優化。
1.1 可伸縮的目標
- 負載增加時(更多客戶端連接)的優雅退化
- 性能隨着資源(CPU、內存、磁盤、帶寬)不斷提高
- 同時滿足可用性和性能目標:低時延、滿足高峯需求、服務質量可調控
1.2 解決方案
分而治之,總體服務分爲以上5個處理階段,網絡服務基礎處理結構
|
分:將整個處理過程分成幾個子任務,每個任務執行一個非阻塞的操作
治: 藉助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 單線程版本
單線程版本是最簡易基礎版本,Reactor和Acceptor、IOHandler在一個線程中處理,在事件觸發時,Reactor根據事件的類型調用給不同的handler的處理方法,如Accept事件則調用Acceptor.runt(),read事件則調用IOHandler.run()。
3.2 多線程版本
戰略性地添加線程以實現可伸縮性,主要適用於多核機器。哪些步驟可以添加線程呢?主要又兩個方案:
增加worker工作線程 | 業務處理handler | |
增加Rector線程 | 響應事件Reactor |
- 增加worker工作線程進行handler處理
- 增加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();
}