背景作者:大招
本文为原创文章,转载请注明作者及出
为了支持 CCtalk 在 Web 端观看视频直播,以及实时聊天等功能,传统的短连接无法实现实时推送的目的,需要建立长连接,而 Web 端用户建立连接的成本很低,长连接的资源消耗较大,这里就需要框架对大并发有足够的支持。满足大并发,又支持长连接, Netty + Websocket 是一个不错的解决方案,所以接下来会通过三篇文章,详细介绍一下这块内容。
-
原理篇
-
应用篇
-
WebSocket
导语
netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.
Netty简介
上面的导语是 Netty 官方的一个介绍,Netty 其实就是基于事件驱动,快速开发高并发,高可靠性的服务和客户端的一个开源框架。主要特性有以下几点。
设计
-
统一的 API,适用于不同的协议(阻塞和非阻塞)
-
基于灵活、可扩展的事件驱动模型
-
高度可定制的线程模型
-
可靠的无连接数据 Socket 支持(UDP)
性能
-
更好的吞吐量,低延迟
-
更省资源
-
尽量减少不必要的内存拷贝
安全
-
完整的 SSL/TLS 和 STARTTLS 的支持
易用
-
完善的 Java doc,用户指南和样例,社区很活跃
-
简洁简单
-
仅依赖于 JDK1.5
Netty框架

核心部分
-
零拷贝
“Zero-copy” describes computer operations in which the CPU does not perform the task of copying data from one memory area to another.
上面是 wiki 的一描述,它通常是指计算机在网络上发送文件时,不需要将文件内容拷贝到用户空间(User Space)而直接在内核空间(Kernel Space)中传输到网络的方式,所谓的两个空间只是说明两个不一样的内存区域,通过减少不同内存区域的拷贝,减低 CPU 的消耗。下面有两张对比图:
1、非零拷贝模式

2、零拷贝模式

Netty 的零拷贝与实际定义还是有点出入,Java 是基于虚拟机的,其实都是用户空间,Netty 中的零拷贝,更多的是一种数据的优化操作,比如多包合并处理上,Netty是将各个包的地址记录下来,在逻辑上合成一个整体,实际存储还是独立的,这样减少内存拷贝,降低 CPU 消耗。

-
统一通讯 API
Netty 提供了命名为 channel 统一异步 IO 接口,主要是为了解决 Java OIO , NIO API 不兼容,简化业务层的工作。
-
可扩展的事件模型
Netty has a well-defined event model focused on I/O. It also allows you to implement your own event type without breaking the existing code because each event type is distinguished from another by a strict type hierarchy. This is another differentiator against other frameworks.
Netty 是通过 ChannelEvent 作为事件流载体,通过 ChannelHander 来做事件逻辑处理,channelHander 又可分为 INBoundHandler 和 OUTBoundHandler 分别处理流入数据和流出数据,Event 则通过 sendDownStream 和 sendUpStream 在每个 handler 中流转,ChannelPipeline 作为 handler 的容器,用户自定义的 handler 只要添加到 pipe,就可以截取数据流做业务处理。

所有的数据流转,和执行过程都是在一个线程(EventLoop)上执行的,这种串行化的处理方式,让 Netty 无锁化,无需处理数据竞争问题,提高了执行效率。
高级组件
-
编解码框架
Netty 提供里提供一套 EncodeHandler 和 DecodeHandler,将业务逻辑从编解码分离,大家可以了解一下,有时间会对这块仔细说明
-
SSL/TLS Support
在 Netty 中使用 SSL 也是很方便的,使用 SSLEngine,SslHandler 就可以

-
Http/WebSocket 支持
Netty线程模型
Netty 支持三种线程模型,分别是单线程模型,多线程模型,以及主从线程模型,重点会介绍主从多线程模型
-
单线程模型

从 accpet 连接到分发到 handler 处理业务,都在单线程中完成,模型简单,适合简单场景,不适合大并发场景。
-
多线程模型

-
Acceptor 单独线程接受 accpet 连接请求,创建 Channel,并移交给 IO 线程池
-
IO 线程池分配线程读取 Channel 数据,并分发 handler 处理相关业务
-
Accpetor 是单线程,如果期间执行鉴权,登陆等操作,出现拥堵,会有单点问题。
-
主从多线程模型

-
Acceptor 线程池(NioEventLoopGroup)分配一个 NioEventLoop 接受连接请求,并创建 Channel,并将 Channel 移交给 IO 线程池
-
I/O 线程池((NioEventLoopGroup)分配一个 NioEventLoop 处理 Channel 数据,从 Channel 读数据,并将数据交给 handler 处理,handler 处理完后,向 Channel 写数据
-
I/O 线程池还可以处理定时任务,和系统任务。
这边多次提到 NioEventLoop,许多个 NioEventLoop 构成 NioEventLoopGroup,其主要的职能如下:
作为 Acceptor 线程,负责处理客户端的请求接入
作为 Connecor 线程,负责注册监听连接操作位,用于判断异步连接结果
作为 IO 线程,监听网络读操作位,负责从 SocketChannel 中读取写报文

这张图很好的说明 NioEventLoop 的作用,以及 Netty 串行化的处理链。
-
一个客户端 Channel 只能由一个 NioEventLoop 处理,避免并发资源竞争问题。
-
NioEventLoop 的事件是分发给 Netty 的事件模型,这个模型可以参考上面的说明。
总结
本文主要介绍了 Netty 的原理,重点对 Netty 的串行化处理链,线程模型,数据模型做了说明,绕过了细节,希望对大家在大层面去理解 Netty 有帮助,更多的实践,以及细节,留在后续文章再说。
资料
-
Netty 零拷贝知识(http://www.cnblogs.com/xys1228/p/6088805.html)
-
Netty user guide(http://netty.io/3.5/guide/)
-
Netty 教程 (https://www.gitbook.com/book/waylau/essential-netty-in-action/details)


