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
  • 简单易用
  • 高性能
  • 健壮
  • 安全
  • 庞大的社区支持

架构

(图片来源:Netty™ 官网)

实战

String 与 ByteBuf 的互相转换

1
2
3
4
5
String s = "yuzhouwan.com";
final ByteBuf buf = Unpooled.wrappedBuffer(s.getBytes(StandardCharsets.UTF_8));
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);
Assert.assertEquals(s, new String(bytes, StandardCharsets.UTF_8));

提高 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 环境中。其主要优势是:

  • 使用的是边缘触发(ETedge-triggered),而非使用水位触发(LTlevel-triggered)
  • 提供了更多的配置参数,如 TCP_CORKSO_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_WAITTIME_WAIT 的问题
    • 缺点
      • 实现复杂,需要使用连接池来维护长连接
查看连接状态
1
$ netstat -ant

资料

Doc

Book

Blog

Github

欢迎加入我们的技术群,一起交流学习

群名称 群号
人工智能(高级)
人工智能(进阶)
大数据
算法
数据库