netty笔记

Netty是一个高性能NIO框架,其是对Reactor模型的一个实现

NIO模型

a56d867d6f64d6e784434374f768fce56e3.jpg

Acceptor注册Selector,监听accept事件
当客户端连接后,触发accept事件
服务器构建对应的Channel,并在其上注册Selector,监听读写事件
当发生读写事件后,进行相应的读写处理

Reactor中的组件

Reactor:Reactor是IO事件的派发者。 Acceptor:Acceptor接受client连接,建立对应client的Handler,并向Reactor注册此Handler。 Handler:和一个client通讯的实体,按这样的过程实现业务的处理。一般在基本的Handler基础上还会有更进一步的层次划分, 用来抽象诸如decode,process和encoder这些过程。比如对Web Server而言,decode通常是HTTP请求的解析, process的过程会进一步涉及到Listener和Servlet的调用。业务逻辑的处理在Reactor模式里被分散的IO事件所打破, 所以Handler需要有适当的机制在所需的信息还不全(读到一半)的时候保存上下文,并在下一次IO事件到来的时候(另一半可读了)能继续中断的处理。为了简化设计,Handler通常被设计成状态机,按GoF的state pattern来实现。

对应上面的NIO代码来看: Reactor:相当于有分发功能的Selector Acceptor:NIO中建立连接的那个判断分支 Handler:消息读写处理等操作类

Reactor单线程模型

5df8784b7ff192dfe3af70c6de04de05412.jpg这个模型和上面的NIO流程很类似,只是将消息相关处理独立到了Handler中去了! 虽然上面说到NIO一个线程就可以支持所有的IO处理。但是瓶颈也是显而易见的!我们看一个客户端的情况,如果这个客户端多次进行请求,如果在Handler中的处理速度较慢,那么后续的客户端请求都会被积压,导致响应变慢!所以引入了Reactor多线程模型!

Reactor多线程模型60752886db9915b406e36475c1dea05f505.jpg

90e7d53320b551f73bdcff29ef3a74af9ad.jpg

Reactor多线程模型就是将Handler中的IO操作和非IO操作分开,操作IO的线程称为IO线程,非IO操作的线程称为工作线程!这样的话,客户端的请求会直接被丢到线程池中,客户端发送请求就不会堵塞! 但是当用户进一步增加的时候,Reactor会出现瓶颈!因为Reactor既要处理IO操作请求,又要响应连接请求!为了分担Reactor的负担,所以引入了主从Reactor模型!

主从Reactor模型793a5983b7e24e38baa120ed748db52f784.jpg

8285d2ccef9dfa8c69825b46d1cd810ea44.jpg主Reactor用于响应连接请求,从Reactor用于处理IO操作请求

几种IO模型总结 BIO:同步阻塞式通信 伪异步I/O:为了解决同步阻塞 I/O 面临的一个链路需要一个线程处理的问题,后来有人 对它的线程模型进行了优化,后端通过一个线程池来处理多个客户端的请求接入, 形成客户端个数 M:线程池最大线程数 N 的比例关系,其中 M 可以远远大于 N, 通过线程池可以灵活的调配线程资源,设置线程的最大值,防止由于海量并发接 入导致线程耗尽。 如果通信对方返回应答时间过长,会引起的级联故障

NIO:它的官方叫法叫NewI/O。但是,由于之前老的 I/O 类库是阻塞 I/O,New I/O 类 库的目标就是要让 Java 支持非阻塞 I/O,所以,更多的人喜欢称之为非阻塞 I/ O(Non-block I/O) AIO:NIO2.0 引入了新的异步通道的概念,并提供了异步文件通道和异步套接字 通道的实现。 异步通道提供两种方式获取获取操作结果: • 通过java.util.concurrent.Future类来表示异步操作的结果; • 在执行异步操作的时候传入一个java.nio.channels; CompletionHandler接口的实现类作为操作完成的回调。 NIO2.0(AIO) 的异步套接字通道是真正的异步非阻塞 I/O,它对应UNIX网络编程 中的事件驱动 I/O(AIO asynchronous I/O),它不需要通过多路复用器(Selector)对注册的通 道进行轮询操作即可实现异步读写,从而简化了 NIO 的编程模型。fab35b7cb3ff53f84ce7e1135e2ecd338f2.jpg

epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们。此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1)) epoll提供了三个函数,epollcreate,epollctl和epollwait,epollcreate是创建一个epoll句柄;epollctl是注册要监听的事件类型;epollwait则是等待事件的产生6c4df7fc50e5d5b31284c16b6380e31cca1.jpg

elect,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。 但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

使用netty而不用原生NIO原因: 1,NIO的类库和API繁杂,使用麻烦 2,需要具备其他的额外技能做铺垫,例如熟悉Java多线程编程。这是因为 NIO编程涉及到Reactor模式,你必须对多线程和网路编程非常熟悉,才能 编写出高质量的NIO程序。 3,可靠性能力补齐,工作量和难度都非常大。例如客户端面临断连重连、网 络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等问题,NIO 编程的特点是功能开发相对容易,但是可靠性能力补齐的工作量和难度都 非常大。 4,JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询, 最终导致CPU 100%。官方声称在JDK1.6版本的update18修复了该问题,但 是直到JDK1.7版本该问题仍旧存在,只不过该BUG发生概率降低了一些而 已,它并没有被根本解决。

不依赖于web容器的http服务

首先设想一下我们目前的通信方式,使用netty mina等异步事件驱动的通信框架,将Channel中信息都分发到Handler中去处理了,Handler中的send方法只负责不断的发送消息,receive方法只负责不断接收消息,这时候就产生一个问题: 客户端如何对应同一个Channel的接收的消息和发送的消息之间的匹配呢? 这也很简单,就需要在发送消息的时候,必须要产生一个请求id,将调用的信息连同id一起发给服务器端,服务器端处理完毕后,再将响应信息和上述请求id一起发给客户端,这样的话客户端在接收到响应之后就可以根据id来判断是针对哪次请求的响应结果了。

转载于:https://my.oschina.net/u/3779841/blog/1831252

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值