Netty:从入门到实践
Netty 是什么?
Netty™ is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.
基本概念
Channel
代表一个到实体(硬件设备、文件、网络 Socket 等)的开放连接,如读操作或写操作
Callback
代表一个在处理完某个事件之后,被调用的方法
Future
代表一个异步操作结果的占位符
Event
代表一个可能会触发相应动作的事件连接被激活、用户事件等
ChannelHandler
代表一个响应特定事件而被执行的回调
特性
- 统一的 API
- 简单易用
- 高性能
- 健壮
- 安全
- 庞大的社区支持
架构
实战
String 与 ByteBuf 的互相转换
1 | String s = "yuzhouwan.com"; |
提高 LEAK 检测的级别
1 | -Dio.netty.leakDetection.level=PARANOID |
1 | ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.PARANOID) |
技术内幕
Netty 和 TCP 的关系
本质上,Netty 仍然会调用 Java 的 Socket 库(如常见的 IO、NIO 和 NIO2 等),而 Java 自身也是对操作系统 Socket 接口的封装。到了操作系统层面,Socket 仍然会走 TCP 协议。所以,可以将 Netty 理解为,是对 TCP 协议的高度封装
IdleStateHandler 和 ReadTimeoutHandler / WriteTimeoutHandler 的异同
三者均是基于心跳机制来完成 socket 超时断开的,前者的功能实际上包含了后两者,IdleStateHandler 可以同时对 read / write 请求进行超时控制
DefaultFileRegion 和 HttpChunkedInput 的区别
场景
- 二者都是应用于大文件传输的
- 而 HttpChunkedInput 可应用于 SSL(Secure Sockets Layer)协议
用法
- DefaultFileRegion 需要在
ChannelHandlerContext
写入时指定文件的字节长度 - DefaultFileRegion 完成文件传输之后,需要再发送一个
LastHttpContent.EMPTY_LAST_CONTENT
标识位,以通知客户端断开连接 - HttpChunkedInput 只需要指定 chunk 块的大小
- HttpChunkedInput 需要在
ChannelHandlerContext
的 pipeline 中增加ChunkedWriteHandler
EpollEventLoopGroup 和 NioEventLoopGroup 的区别
Java 中的 NIO 会根据操作系统不同,选用不同的 Selector 实现,例如 Linux 对应 EPollSelectorProvider
(epoll 模式)和 PollSelectorProvider
(selector 模式)、MacOS 对应 KQueueSelectorProvider
、Windows 对应 WindowsSelectorProvider
。由此可见,EpollEventLoopGroup 只能被应用于 Linux 环境中。其主要优势是:
- 使用的是边缘触发(ET,edge-triggered),而非使用水位触发(LT,level-triggered)
- 提供了更多的配置参数,如
TCP_CORK
、SO_REUSEADDR
等 - 通过 JNI 调用 C 代码,可以减少 GC 压力
参考
踩过的坑
Connection reset by peer
描述
1 | io.netty.channel.unix.Errors$NativeIoException: readAddress(..) failed: Connection reset by peer |
分析
客户端和服务器未统一使用 TCP 短连接或者长连接导致的
补充
短连接 vs 长连接
短连接
每次请求都需要先建立 TCP 连接(三次握手),再执行业务逻辑,最后关闭连接(四次挥手)
- 优点
- 实现简单
- 缺点
- 性能较差,大量资源消耗在了 TCP 层面的交互上
- 出现大量
TIME_WAIT
状态的 TCP 连接。如果未设置SO_REUSEADDR
参数,则可能出现端口被占满的问题。因为连接被主动关闭后,TCP 连接的状态仍然会是TIME_WAIT
,只有等两个 MSL 后(Maximum Segment Lifetime,报文最大生存时间,RFC 793 规范中 MSL 取值为 2 分钟),才会回到 CLOSED 状态
- 优点
长连接
连接建立完,不释放连接
- 优点
- 性能较高,不需要重复建立或关闭 TCP 连接
- 不会出现
CLOSE_WAIT
和TIME_WAIT
的问题
- 缺点
- 实现复杂,需要使用连接池来维护长连接
- 优点
查看连接状态
1 | $ netstat -ant |
资料
Doc
Book
Blog
Github
- Fix a bug where HttpObjectAggregator doesn’t always produce FullHttpMessage
- PostgreSQLFrontendHandler - channelWritabilityChanged