NIO.2 前摄器模式 - WordPress.com

Download Report

Transcript NIO.2 前摄器模式 - WordPress.com

‹#›
<在此处插入图片>
实现轻型服务器的 JavaTM 方法
议题
•
•
•
•
背景
Java NIO 和 NIO.2
JSSE 和 SSLEngine
结论
<在此处插入图片>
‹#›
背景
•
•
•
•
C10K 问题
轻型 Web 服务器 (Nginx、Lighttpd)
NIO 架构 (Netty、Apache MINA)
Grizzly
‹#›
目标
•
•
•
•
•
改善延迟
提高可伸缩性
最大限度提高吞吐量
最大限度提高性能
可重用性
‹#›
议题
•
•
•
•
背景
Java NIO 和 NIO.2
JSSE 和 SSLEngine
结论
<在此处插入图片>
‹#›
Java I/O
• 阻塞 I/O (Java SE 1.4 之前)
– 调用者被阻塞
• 非阻塞 I/O (NIO) (Java SE 1.4)
– 调用者即时获得数据或错误代码
• 异步 I/O (NIO.2) (Java SE 1.7)
– 调用者获得通知
‹#›
传统服务模式
• ServerSocket/Socket
• InputStream/OutputStream
• 线程 (1:1)
读取/处理/写入
客户端
客户端
客户端
• 线程
服
务
器
读取/处理/写入
• 线程
读取/处理/写入
• 线程
‹#›
传统服务模式
•
•
•
•
ServerSocket/Socket
InputStream/OutputStream
ExecutorService (JDK 1.5)
线程池 (M:N)
读取/处理/写入
客户端
客户端
客户端
• 线程
服
务
器
读取/处理/写入
• 线程
读取/处理/写入
• 线程
客户端
线程池
‹#›
传统服务模式
• 操作系统的线程数限制
• 线程上下文切换是一种“高负载”操作
• 工作线程是 I/O 绑定的
读取/处理/写入
客户端
客户端
客户端
• 线程
服
务
器
读取/处理/写入
• 线程
读取/处理/写入
• 线程
客户端
线程池
‹#›
NIO 反应器模式
• Selector/SelectionKey
• Channel/Buffer
• 线程 (1:N)
客户端
客户端
客户端
反应器
接
收
器
分
派
器
. 线程
处理器
读取 | 写入
处理器
读取 | 写入
处理器
读取 | 写入
处理器
读取 | 写入
服
务
器
‹#›
NIO 反应器模式
•
•
•
•
Selector/SelectionKey
Channel/Buffer
工作线程池
线程 (1:X:N)
客户端
客户端
客户端
反应器
接
收
器
分
派
器
. 线程
处理器
读取 | 写入
处理器
读取 | 写入
处理器
读取 | 写入
处理器
读取 | 写入
服
务
器
‹#›
NIO 反应器模式
•
•
•
•
Selector/SelectionKey
Channel/Buffer
工作线程池/多个反应器
线程 (K:X:N)
客户端
客户端
客户端
反应器
接
收
器
分
派
器
处理器
读取 | 写入
处理器
读取 | 写入
处理器
读取 | 写入
处理器
读取 | 写入
服
务
器
‹#›
NIO.2 前摄器模式
‹#›
NIO.2 前摄器模式
‹#›
NIO.2 前摄器模式
•
•
•
•
AsynchronousChannel/Buffer
AsynchronousChannelGroup
CompletionHandler
线程 (M:N)
客户端
前摄器
处理器
接受
客户端
客户端
处
理
器
读取|写入
分
派
器
处理器
处理器
服
务
器
处理器
‹#›
NIO.2 前摄器模式
• 充分利用操作系统 I/O 功能
客户端
前摄器
处理器
接受
客户端
客户端
处
理
器
读取|写入
分
派
器
处理器
处理器
服
务
器
处理器
‹#›
NIO.2 概念
• 发起非阻塞 I/O 操作
• 在 I/O 完成时发出通知
‹#›
CompletionHandler
interface CompletionHandler<V,A> {
void completed(V result, A attachment);
void failed(Throwable exc, A attachment);
}
V = 结果值的类型
A = 附加到 I/O 操作中的对象的类型
用于传递上下文
通常封装连接上下文
若成功则会调用 completed 方法
若 I/O 操作失败则会调用 failed 方法
‹#›
CompletionHandler
class Connection { … }
class Handler implements CompletionHandler<Integer, Connection> {
public void completed(Integer result, Connection conn) {
// handle result
}
public void failed(Throwable exc, Connection conn) {
// error handling
}
}
AsynchronousSocketChannel ch = ...
ByteBuffer buf = ...
Connection conn = ...
Handler handler = ...
ch.read(buf, conn, handler);
‹#›
AsynchronousSocketChannel
•
•
•
•
异步连接
异步读取/写入
异步分散/集中(多个缓冲区)
读取/写入操作支持超时设置
– 出现超时异常时调用 failed 方法
• 实现 NetworkChannel
– 用于绑定、设置套接字选项等
‹#›
ChannelGroup
• 哪些线程调用 completion 处理器?
• 面向网络的通道与一个组绑定
– AsynchronousChannelGroup
•
•
•
•
•
组封装线程池和其他共享资源
创建含线程池的组
较为简单的应用程序的默认组
由池线程调用 Completion 处理器
AsynchronousFileChannel 可以使用自己的线程池
(单一组)来创建
‹#›
创建一个组
// custom thread pool
ExecutorService pool = ...
AsynchronousChannelGroup group =
AsynchronousChannelGroup
.withThreadPool(pool);
AsynchronousSocketChannel channel =
AsynchronousSocketChannel.open(group);
‹#›
Buffer 和 ByteBuffer
‹#›
Buffer 和 ByteBuffer
• 直接和非直接 Buffer
– ByteBuffer.allocateDirect()
– MappedByteBuffer
‹#›
ByteBuffer 的问题
• 问题:
– 假设接受了 10000 个连接
– 因此会创建 10000 个 ByteBuffer 并调用读取操作
– 现在,我们等待、等待、再等待,等待远程客户端向我们发送
字节(客户端/网络非常慢)
– 这时接收到另外 10000 个请求,我们再一次创建 10000 个
ByteBuffer 并调用 read()
operations.ByteBuffer.allocateDirect() MappedByteBuffer
• 系统不堪重负!
‹#›
使用 ByteBuffer 池和限制
• 我们不必过于消极。目前为止,我们对超过 20000 个客
户端进行了测试,均未出现任何问题
• 但您仍然需要谨记上面的问题!!
• 您可能希望对 read() 操作进行限制,以避免创建过多的
ByteBuffer
• 我们强烈建议使用 ByteBuffer 池,特别是在使用堆时。
在调用 read() 方法之前获取一个 ByteBuffer,并在读取
操作完成后立即将其返回给池。
‹#›
议题
•
•
•
•
背景
Java NIO and NIO.2
JSSE 和 SSLEngine
结论
<在此处插入图片>
‹#›
SSL/TLS 和 JSSE
•
•
•
•
TLS/SSL 协议
HTTPS 协议
JavaTM 安全套接字扩展
SSLEngine与非阻塞 I/O
‹#›
SSLEngine
‹#›
NIO 和 NIO.2 的 SSLEngine
ByteBuffer
‹#›
SSLEngine 操作
• SSLEngine.wrap(ByteBuffer src, ByteBuffer dst)
• SSLEngine.unwrap(ByteBuffer src, ByteBuffer dst)
• SSLEngine.getDelegatedTask()
‹#›
SSLEngineResult.HandshakeStatus
• NEED_UNWRAP
– SSLEngine 需要先从远端接收数据,然后才能继续握手。
• NEED_WRAP
– SSLEngine 必须先将数据发送给远端,然后才能继续握手,因
此应调用 SSLEngine.wrap()。
‹#›
SSLEngineResult.HandshakeStatus
• FINISHED
– SSLEngine 刚完成握手。
• NEED_TASK
– SSLEngine 需要一个(或多个)委托任务的结果,然后才能继
续握手。
• NOT_HANDSHAKING
– SSLEngine 当前未进行握手。
‹#›
SSLEngineResult.Status
• OK
– SSLEngine 已完成该操作。
‹#›
SSLEngineResult.Status
• BUFFER_OVERFLOW
– SSLEngine 无法处理操作,因为目标缓冲区中没有足够的空间
来保存结果。
• BUFFER_UNDERFLOW
– SSLEngine 无法解包传入数据,因为源空间没有足够的可用数
据来建立完整有效的协议包。
• CLOSED
– SSLEngine 已经关闭,操作无法完成。
‹#›
NIO.2 前摄器模式中的 SSLEngine
客户端
前摄器
处理器
接受
客户端
客户端
处
理
器
读取|写入
分
派
器
处理器
处理器
处理器
status handler
分 状
派 态
器
SSLENGINE
status handler
服
务
器
线程池
‹#›
议题
•
•
•
•
背景
Java NIO and NIO.2
JSSE 和 SSL 引擎
结论
<在此处插入图片>
‹#›
总结
• NIO.2 和 SSLEngine 非常适于构建安全轻型服务器。
• NIO.2 已在 JDK7 试用版中提供,赶快体验它吧!
‹#›
更多信息 — NIO.2
• OpenJDK NIO.2 页面:
– http://openjdk.java.net/projects/nio/
• NIO.2 文档
– http://openjdk.java.net/projects/nio/javadoc/
• NIO.2 邮件列表
– [email protected]
• Alan 的博客
– http://blogs.sun.com/alanb/
‹#›
更多信息 — JSSE
• JSSE 参考指南:
– http://download.oracle.com/javase/7/docs/technotes/guides/s
ecurity/jsse/JSSERefGuide.html
• 安全开发邮件列表
– [email protected]
‹#›
更多信息 — Grizzly
• Grizzly 项目:
– http://grizzly.dev.java.net
• Grizzly 的 Twitter
– http://twitter.com/project_grizzly
‹#›
问答
‹#›
‹#›