Netty到底是什么

有了Netty,你可以实现自己的HTTP服务器,FTP服务器,UDP服务器,RPC服务器,WebSocket服务器,Redis的Proxy服务器,MySQL的Proxy服务器等等。

我们回顾一下传统的HTTP服务器的原理:

1、创建一个ServerSocket,监听并绑定一个端口

2、一系列客户端来请求这个端口

3、服务器使用Accept,获得一个来自客户端的Socket连接对象

4、启动一个新线程处理连接

4.1、读Socket,得到字节流

4.2、解码协议,得到Http请求对象

4.3、处理Http请求,得到一个结果,封装成一个HttpResponse对象

4.4、编码协议,将结果序列化字节流 写Socket,将字节流发给客户端

5、继续循环步骤3

HTTP服务器之所以称为HTTP服务器,是因为编码解码协议是HTTP协议,如果协议是Redis协议,那它就成了Redis服务器,如果协议是WebSocket,那它就成了WebSocket服务器,等等。 使用Netty你就可以定制编解码协议,实现自己的特定协议的服务器。

NIO 

上面是一个传统处理http的服务器,但是在高并发的环境下,线程数量会比较多,System load也会比较高,于是就有了NIO。

他并不是Java独有的概念,NIO代表的一个词汇叫着IO多路复用。它是由操作系统提供的系统调用,早期这个操作系统调用的名字是select,但是性能低下,后来渐渐演化成了Linux下的epoll和Mac里的kqueue。我们一般就说是epoll,因为没有人拿苹果电脑作为服务器使用对外提供服务。而Netty就是基于Java NIO技术封装的一套框架。为什么要封装,因为原生的Java NIO使用起来没那么方便,而且还有臭名昭著的bug,Netty把它封装之后,提供了一个易于操作的使用模式和接口,用户使用起来也就便捷多了。

说NIO之前先说一下BIO(Blocking IO),如何理解这个Blocking呢?

  • 客户端监听(Listen)时,Accept是阻塞的,只有新连接来了,Accept才会返回,主线程才能继;
  • 读写socket时,Read是阻塞的,只有请求消息来了,Read才能返回,子线程才能继续处理;
  • 读写socket时,Write是阻塞的,只有客户端把消息收了,Write才能返回,子线程才能继续读取下一个请求;

传统的BIO模式下,从头到尾的所有线程都是阻塞的,这些线程就干等着,占用系统的资源,什么事也不干。

那么NIO是怎么做到非阻塞的呢。它用的是事件机制。它可以用一个线程把Accept,读写操作,请求处理的逻辑全干了。如果什么事都没得做,它也不会死循环,它会将线程休眠起来,直到下一个事件来了再继续干活,这样的一个线程称之为NIO线程。用伪代码表示:

java应用 流媒体服务器的作用 netty流媒体服务器_java应用 流媒体服务器的作用

Reactor线程模型

1、Reactor单线程模型

一个NIO线程+一个accept线程:

java应用 流媒体服务器的作用 netty流媒体服务器_netty简介_02

 

2、Reactor多线程模型

java应用 流媒体服务器的作用 netty流媒体服务器_客户端_03

 3、Reactor主从模型

主从Reactor多线程:多个acceptor的NIO线程池用于接受客户端的连接

java应用 流媒体服务器的作用 netty流媒体服务器_客户端_04

Netty可以基于如上三种模型进行灵活的配置。

4、小结

Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象。

在Netty里面,Accept连接可以使用单独的线程池去处理,读写操作又是另外的线程池来处理。

Accept连接和读写操作也可以使用同一个线程池来进行处理。而请求处理逻辑既可以使用单独的线程池进行处理,也可以跟放在读写线程一块处理。线程池中的每一个线程都是NIO线程。用户可以根据实际情况进行组装,构造出满足系统需求的高性能并发模型。

为什么选择Netty

如果不用netty,使用原生JDK的话,有如下问题:

1、API复杂

2、要对多线程很熟悉:因为NIO涉及到Reactor模式

3、高可用的话:需要出路断连重连、半包读写、失败缓存等问题

4、JDK NIO的bug

而Netty来说,他的api简单、性能高而且社区活跃(dubbo、rocketmq等都使用了它)