目录
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();
}