Netty学习笔记

何为Netty


  Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。

何为事件驱动


事件处理的两道工序:

方法 说明
事件分离器(Event Demultiplexer) 将事件源(socket/file)的I/O时间分离出来(IO就绪事件,IO完成事件),并分传递到对应的I/O事件处理器。
事件处理器(Event Handler) 应用预先注册需要处理的事件及其事件处理器(回调函数)。

事件分离器的两种模式:

模式 说明
Reactor 事件分离器负责等待文件描述符或socket为读写操作准备就绪,然后将就绪事件传递给对应的处理器,最后由处理器负责完成实际的读写工作。I/O操作由应用完成,调用事件处理器时,表示I/O就绪。
Proactor demultiplexor事件处理器负责发起异步I/O操作,将用户定义的数据缓冲区地址和数据大小传递给操作系统,操作系统进行I/O操作,事件分离器捕获IO操作完成事件,然后将事件传递给对应处理器。I/O操作由系统完成,调用事件处理器时,表示I/O完成。

何为异步I/O


  常见的I/O模式有一下几种,Netty是多路复用模式。假设场景:用户想从水管管道取5000L水,但是这个水管的水流是断断续续的,那么他有以下几种方法:

模式 大白话 说明
阻塞 I/O(blocking IO) 他打开水龙头,在必须原地等待水量达到5000L,然后这个任务才完成。 阻塞,同步I/O
非阻塞 I/O(nonblocking IO) 他打开水龙头,然后去做别的事情,两分钟过来查看一次(轮询),直到水位达到500L,然后这个任务才完成。 非阻塞,同步I/O
I/O 多路复用( IO multiplexing)(事件驱动I/O) 他加装多个水龙头,然后在水龙头的前端安装水滴传感器(阻塞),他在后台轮询各个传感器的数据,一旦得到A水龙头的水滴传感器已经被触发时,他就打开水龙头A接水,有一下几种机制select,epoll,iocp,kqueue,poll。 非阻塞,同步I/O
信号驱动 I/O( signal driven IO) 他加装多个水龙头,然后在水龙头的前端安装水滴传感器,当水龙头A的水滴传感器触发时,主动通知他,他就打开水龙头A接水。 非阻塞,同步I/O
异步 I/O(asynchronous IO) 他加装多个水龙头,然后在水龙头的前端安装水量传感器,并且将水龙头打开,然后他就去做其他的事情了,当水来时,水量传感器统计已取的水量,达到5000L时,将多个水桶的水汇聚到一个桶里,让他直接使用 非阻塞,异步I/O

I/O多路复用模式


模式 方法 说明 最大连接数 效率 消息传递方式
select 轮询 同步非阻塞 FD_SETSIZE宏定义 FD的增加会造成线性遍历速度慢的“线性下降性能问题” 内核需要将消息传递到用户空间,都需要内核拷贝动作
kQueue 回调 同步非阻塞 与epoll相似 与epoll相似 与epoll相似
iocp 通知 异步 待了解 待了解 待了解
poll 轮询 同步非阻塞 基于链表来存储没有最大连接数的限制 与select一样 与select一样
ePoll 回调 同步非阻塞 连接数有上限,效率与连接数成反比 socket活跃大会有性能问题 通过内核和用户空间共享一块内存来实现

Netty示例解析


以下是一个经典示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.mqtt.MqttDecoder;
import io.netty.handler.codec.mqtt.MqttEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.yb.iot.mqtt.handler.ChannelPipelineHandler;
import org.yb.iot.mqtt.handler.InboundMessageHandler;

import java.util.concurrent.TimeUnit;

public class NettyServer {


    public static void main(String[] args) {
        /**
         * NioEventLoopGroup是处理I / O操作的多线程事件循环,多种实现可选。
         * 使用多少个线程以及如何将它们映射到创建的通道取决于EventLoopGroup实现,甚至可以通过构造函数进行配置。
         * 在上文中提到,I/O多路复用机制有多种,Netty中提供了多种实现,,以Group尾缀的为多线程实现。
         */
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        try {
            /**
             * 设置服务器的帮助程序类。
             */
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            /**
             * bossGroup通常称为“老板”,接受传入的连接。
             * workerGroup通常称为“工人”,一旦老板接受连接并将注册的连接注册给工人,便处理已接受连接的流量。
             */
            serverBootstrap.group(bossGroup, workerGroup)
                    /**
                     * 指定IO模型
                     */
                    .channel(NioServerSocketChannel.class)

                    /**
                     * 配置自定义的事件处理器。
                     */
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Autowired
                        private InboundMessageHandler inboundMessageHandler;

                        /**
                         * 初始化channel模型的上下文
                         * @param socketChannel
                         * @throws Exception
                         */
                        @Override
                        public void initChannel(SocketChannel socketChannel) {
                            /**
                             * 事件处理器责任链,可以动态增删
                             * 可以进行例如协议编码解码,心跳,内容长度,粘包分包处理,读写处理等,
                             * Netty已经默认提供了多种标准协议的解码编码实现,全都在io.netty.handler.codec.*下,如MQTT,HTTP等。
                             */
                            ChannelPipeline pipeline = socketChannel.pipeline();

                            /** 最大内容长度 */
                            pipeline.addLast(new HttpObjectAggregator(1024 * 1024 * 64));

                            /** 心跳时间 */
                            pipeline.addLast("idleStateHandler", new IdleStateHandler(120, 120, 120, TimeUnit.SECONDS));

                            /** 协议编码 */
                            pipeline.addLast(MqttEncoder.INSTANCE);

                            /** 协议解码 */
                            pipeline.addLast(new MqttDecoder(1024 * 1024 * 64));

                            /** 消息处理 */
                            pipeline.addLast(inboundMessageHandler);
                        }
                    })

                    /**
                     * 配置EventLoopGroup模型的参数
                     */
                    .option(ChannelOption.SO_BACKLOG, 128)

                    /**
                     * 配置Channel模型的参数
                     */
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            /**
             * 绑定并开始接受传入的连接,ChannelFuture支持I/O完成事件监听。
             */
            ChannelFuture channelFuture = serverBootstrap.bind(1883).sync();

            /**
             * 注册等待Socket服务器关闭。
             */
            channelFuture.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            /**
             * 优雅的关闭并退出服务
             */
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

EventLoopGroup与Channel的实现对应关系如下:

单线程模型 多线程模型/主从线程模型 通道模型 模式
EpollEventLoop.class EpollEventLoopGroup.class EpollServerSocketChannel.class epoll
KQueueEventLoop.class KQueueEventLoopGroup.class KQueueServerSocketChannel.class kQueue
NioEventLoop.class NioEventLoopGroup.class NioServerSocketChannel.class select
AioEventLoop.class AioEventLoopGroup.class AioServerSocketChannel.class iocp

Netty重要组件:

说明
Channel 管道对象
ChannelPipeline 管道事件处理器责任链
ChannelHandler 管道事件处理器的接口
ChannelHandlerContext 管道事件处理器的上下文
ChannelFuture 管道异步操作的结果
ByteBuf 管道一帧数据的对象,字节容器,通过引用计数的方式实现内存回收

参考文档

Netty Wiki
Netty 实战 中文版
Netty设计原理
并发编程网 Netty
linux下select/poll/epoll机制的比较
Linux IO模式及 select、poll、epoll详解
Netty 系列之 Netty 线程模型
深入研究Netty之线程模型详解
Netty学习之IO模型

今日诗词

作者信息