写点什么

源码分析 -Netty:开篇

发布于: 2021 年 03 月 11 日
源码分析-Netty:开篇

一 开篇,再谈架构

这里提出关于架构的几个问题,但不会给出答案,毕竟本人也是在不断探索中,并非权威。旨在引起思考,自己也会每日自省。

1、架构,是创造,还是选择?

2、架构的目的,到底是什么?

3、有哪些制约条件?

4、影响、决定架构的因素?

二 关于 Netty

2.1 一些基础知识

IO 相关:

Java NIO浅析

Linux IO模式及 select、poll、epoll详解

网络 IO 演变过程

一文读懂高性能网络编程中的I/O模型

这里只列一张图,用于简要说明常用的 I/O 方法和对比:


2.2 Netty 定义

Netty官网,醒目位置描述:

Netty is an asynchronous event-driven network application frameworkfor rapid development of maintainable high performance protocol servers & clients.
Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.
复制代码

翻译过来:

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

总结起来关键包括两点:

  • NIO 异步编程模式,事件驱动的高性能客户端/服务端网络开发框架

  • 显著简化了诸如 TCP 和 UDP socket server 的网络编程

2.3 特性

  • 为不同的传输类型提供了统一的 API——阻塞和非阻塞的 Socket

  • 基于灵活和可扩展的事件模型,可以清晰地分离关注点

  • 高度可定制的线程模型——单线程、一个或多个线程池

  • 真正的无连接数据报套接字支持(自 3.1 版本 起)


除此之外,大家更了解的是 Netty:

1、易用:详细记录的 Javadoc,用户指南和示例;只依赖 JDK,没有其他依赖。

2.高性能:吞吐量更高、延迟更低、减少资源消耗、最小化不必要的内存复制。

3、安全性:完整的 SSL/TLS 和 Start TLS 支持;

4、以及较高的社区活跃度。

2.4 架构

下图是 Netty 官网的最新架构图:


从架构图可见,Netty 可以分为 Core、Transport Services、Protocol Support 三大模块。

2.4.1 Core

核心模块,支持零拷贝的富字节缓冲区、通用的通信 API、可扩展事件模型。

零拷贝(Zero-Copy)是一个比较重要的概念,解决了网络传输时多次数据拷贝的问题。Wiki 中对零拷贝的定义如下:

"Zero-copy" describes computer operations in which the CPU does not perform the task of copying data from one memory area to another. This is frequently used to save CPU cycles and memory bandwidth when transmitting a file over a network.

翻译过来:

零拷贝技术是指计算机执行操作时,CPU 不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省 CPU 周期和内存带宽。


零拷贝解决什么问题:

  • 减少甚至完全避免操作系统内核和用户应用程序地址空间这两者之间进行数据拷贝操作,从而减少用户态 -- 内核态上下文切换带来的系统开销。

  • 减少甚至完全避免操作系统内核缓冲区之间进行数据拷贝操作。

  • 帮助用户进程绕开操作系统内核空间直接访问硬件存储接口操作数据。

  • 利用 DMA 而非 CPU 来完成硬件接口和内核缓冲区之间的数据拷贝,从而解放 CPU,使之能去执行其他的任务,提升系统性能。

想要更详细地了解 Linux I/O 和零拷贝相关内容,可以看这边腾讯的文章:Linux I/O 原理和 Zero-copy 技术全面揭秘

2.4.2 Transport Service

传输服务,

  • Socket & DatagramSocket

  • Http Tunnel(http 隧道)

  • In-VM pipe(虚拟机内的管道)

这一块稍有些难以理解,对最上层的 Socket 大家都有使用,但对 Http 隧道 和 虚拟机内管道了解不多。简单来说,HTTP Tunnel 是 HTTP1.1 引入的一个功能,用以解决明文的 HTTP Proxy 无法代理跑在 TLS 中的流量(即 https)的问题,同时提供了作为任意流量的 TCP 通道的能力。

定义可查看:rfc2817rfc7540。应用实例:HTTP Tunnel的应用实例

关于管道,目前没有查到特别明确的资料。不过初步分析是 JVM 的管道,用于处理进程间通讯。进程间常用的通讯方式可以初步划分为管道、共享内存、Socket 三种。

2.4.3 协议支持

  • Http&WebSocket

  • SSL&StartTLS:加密协议

  • Google Protobuf:google 开源的序列化协议

  • zlib/gzip Compression:zlib 和 gzip 压缩

  • LargeFile Transfer:支持大文件传输

  • RTSP:位于应用层的多媒体实时流传输协议

  • Legacy Text.Binary Protocols with Unit Testability:传统的文本。具有单元可测试性的二进制协议

2.4.4 Netty 的逻辑架构


2.5 版本说明及代码结构

2.5.1 版本选择

目前从官网可下载的最新版本是 4.1.60(发布于 2021-03-09)。不过其实 netty5 在 2016 年就已经发布,但被官方舍弃,相关说明可以看作者的这个 issue: Remove master branch #4466,原因如下:

  1. netty5 中使用了 ForkJoinPool,增加了代码的复杂度,但是对性能的改善却不明显

  2. 多个分支的代码同步工作量很大

  3. 作者觉得当下还不到发布一个新版本的时候

  4. 在发布版本之前,还有更多问题需要调查一下,比如是否应该废弃 exceptionCaught, 是否暴露 EventExecutorChooser 等等。

而 3.x 和 4.x 中,4.x 是官方推荐版本,也可以看到一直在维护更新,所以以 4.x 版本作为分析目标。

2.5.2 工程结构

目前项目中使用的实际上是 4.1.25 版本,但这里会选择相对新一点的 4.1.50 版本进行分析。Maven 引入方式如下:


我们对比一下两个版本之间的结构差异:

从结构上看,增加了 native-image.io.netty 包,并且在 native 下增加了 libnetty_resolver_dns_native_macos_x86_64.jnilib 和 libnetty_transport_native_epoll_aarch_64.so 两个库文件。可以看到是对 macos 和 aarch_64 架构的支持。

2.5.3 源码结构

从上面也可以看到,源码结构并没有发生变化。按照包结构:

bootstrap

启动类所在包,Netty 中服务端和客户端的启动类不同,这点切记!bootstrap 中主要包括两类:bootstrap 和 config。channelFactory 接口已标记为废弃,乱入了一个 FailedChannel。

buffer

涉及底层的缓冲处理。上面 Netty 的特性和零拷贝概念,以及 buffer 包下的代码量都可以看到,这是很重的一块内容。

channel

管道,用于连接字节缓冲区 Buf 和另一端的实体,这个实例可以是 Socket,也可以是 File, 在 Nio 网络编程模型中, 服务端和客户端进行 IO 数据交互(得到彼此推送的信息)的媒介。

Netty 对 Jdk 原生的ServerSocketChannel进行了封装和增强,成了NioXXXChannel, 相对于原生的 JdkChannel, Netty 的 Channel 增加了如下的组件:

  • id 标识唯一身份信息

  • 可能存在的 parent Channel

  • 管道 pepiline

  • 用于数据读写的 unsafe 内部类

  • NioEventLoop

handler

处理器,是 Reactor 模型中的重要角色。再引用一下这张图:

在 Reactor 经典模型中,Reactor 查询到 NIO 就绪的事件后,分发到 Handler,由 Handler 完成 NIO 操作和计算的操作。

Handler 主要的操作为 Channel 缓存读、数据解码、业务处理、写 Channel 缓存,然后由 Channel(代表 client)发送到最终的连接终端。

resolver

分解器,针对 Host、Addres、dns 进行处理。

三 总结

本篇介绍 Netty 的架构和代码结构,下一篇将通过一个 demo 来分析 Netty 运行的主流程,并结合 reactor 模型进行解析。

发布于: 2021 年 03 月 11 日阅读数: 45
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
源码分析-Netty:开篇