Netty pipeline

系列文章目录

1. Netty网络应用基础
2. Java I/O
3. IO/模型
4. 网络应用编解码
5. Netty Pipeline
6. Netty EventLoopGroup&EventLoop
7. Netty ThreadLocal&FastThreadLocal
8. Netty Future&Promise
9. Netty内存管理–(旧)PoolChunk&伙伴分配
10. Netty内存管理–内存池空间规格化SizeClasses
11. Netty内存管理–PoolChunk&PoolSubPage
12. Netty内存管理–内存池PoolArena
13. Netty内存管理–内存分配器PooledByteBufAllocator
14. Netty ObjectPool

写在前面

前面已经总结了Java基础IO, IO模型, 编解码等内容, 理论上我们把三者结合起来就可以完成消息收发。接下来, 结合Netty pipeline聊聊网络应用中对三者逻辑组织, 解决实际工程中链接创建, IO处理和消息处理。

1. 结构要求

首先, 逻辑上我们需要这么一种结构, 将基础IO, IO模型, 编解码组织为一个特定的序列;
其次, 此外实际应用在运维阶段需要支持日志输出, 消息统计, 消息审计等功能, 因此这个序列可以动态增加或者减少序列项;
最后, 部分序列项在客户端和服务端可以复用, 但是序列的顺序不同, 因此序列应该支持定制;
玩过设计模式的你肯定想到了责任链模式, 整过Java Servlet开发的估计想到了FilterChain, 搞过大数据的估计想到了数据处理中的Pipeline。以上如果都没玩过, 那你至少玩过Java 8的Lambda和Stream, 最后在Netty中叫pipeline。

以上过程完成了业务需要到技术需求的转化, 有了具体的技术需求, 你就可以挑选合理的技术架构。此处我不想强调架构的思想, 但是对有志于在技术领域继续前行的小伙伴, 成功技术需求转化是成功架构的一半, 因为你已经将问题讲清楚了。

2. Netty Pipeline

与FilterChain由Filter组装而成, Netty pipeline是由ChannelHandlerContext组成, 而且两者都有个类似的地方, 那就是顺序很关键且可以条件控制。比如Filter是通过url-pattern是否匹配决定是否通过Filter, 而ChannelHandler则根据数流向(ChannelInbound和ChannelOutbound)来处理。

FilterChain示意图FilterChain示意图
有了这么个骨架,接下来得用pipeline的方式来划分逻辑, 这些逻辑又分为连接处理和消息处理两类, 接下来分别讨论。

3. 连接处理

3.1 连接创建

想必你已知道Netty是基于Reactor模型的, 其中会有reactor线程和IO线程, 前者探测ready的channel, 后者去具体的channel上完成读写。但是Channel是怎么创建的呢?显然在探测channel ready之前, 首先需要创建Channel, 该过程对应咱们的连接创建。第一步是监听channel的创建, 这个是咱们代码明确声明创建的。其次, 当有新的连接接入时, 需要调用监听channel的accept来接收, 此时会创建对应的客户端连接channel。如果使用bossGroup+workerGroup的方式, bossGroup中会创建一个EventLoop作为reactor线程来处理监听channel中的ACCEPT事件, 而后创建对应的客户端连接channel, 最终注册到workerGroup的某个EventLoop中, 该EventLoop作为reactor线程获取ready的channel并读取数据。

基本的步骤如下:

  1. 启动Server端进程, 监听特定端口(NioServerSocketChannel#doBind)
  2. Client端发起TCP连接(NioSocketChannel#doConnect);
  3. Kernel TCP协议栈完成2次握手, 连接进入Kernel半连接队列, 链接状态SYN_RCVD;
  4. Client端发送第3次握手, Kernel将连接移动到全连接队列, 链接状态ESTABLISHED;
  5. Kernel通知应用有新连接接入;
  6. 应用调用accept, Kernel从全连接队列中返回最后的连接,应用创建关联对象与之绑定;

3.2 连接断开

  1. 调用channel.close();
  2. 应用层完成关联对象的释放, 通过系统调用关闭连接;
  3. Kernel通知网络协议栈执行TCP连接断开流程;
  4. Netty中由ServerBootstrapAcceptor完成Channel的创建, 如果创建失败则会强制关闭。

4. 消息处理

4.1 概要说明

消息处理至少包含消息编解码和消息的业务处理。由于消息编解码的通用性, 因此消息编解码一般独立为pipeline中的一环, 进而做到了消息编解码和消息本身的解耦。

Pipeline是由抽象的item组成, item统一了框架和业务逻辑对象, 使得业务逻辑也可以包装为item加入pipeline当中,从而完成框架逻辑和业务逻辑的衔接。在网络应用场景中, 我们既要考虑逻辑上下文(也就是现在应该执行什么逻辑), 也要考虑运行上下文(也就是当前的逻辑应该在哪个线程下运行), 毕竟消息的读取是典型的IO过程, 消息处理则可能是典型的计算过程, 两者特性不同, 分而治之是比较合理的。接下来我们聊聊Netty的实现异同。

4.2 差异补充

首先, Netty也使用的是Pipeline来组织整个处理过程。
其次, Netty的Pipeline item并不是ChannelHandler, 而是ChannelHandlerContext。在Context中包含了执行上下文EventLoop和逻辑上下文prevContext和nextContext的定义。
最后, Netty将ChannelHandler细化为ChannelInBoundHandler, ChannelOutBoundHandler和ChannelDuplexHandler三种类型。按照数据的流向, 寻找下一个支持的handler进行处理。这个是在使用中需要建立的全局观。

4.3 全局图示

请添加图片描述

小结

本文我们探讨了网路应用中开发中常用的主干结构pipeline, 内容涵盖结构特点, 抽象pipeline item的意义, 以及网络应用场景下逻辑和运行上下文对item设计时的影响。最后, 本文简要介绍了Netty pipeline的具体实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值