vlambda博客
学习文章列表

开篇:Netty源码学习系列

好久之前写了:


可惜很久没更新了,不少博客园的网友经常问,到底还写不写,后来连问都不问了,深表惭愧,从今天开始,重新开启这个系列文章——Netty源码学习笔记。

立意:不同于一些零散的个人博客文章,打算从头到尾,形成一个系列,也不想流于表面,只是复制黏贴注释甚至源码。。。也不想糊弄大家,糊弄自己,随便看看怎么写的就简单完事。。。希望能兼顾底层原理和一些外围的相关技术总结和深入“科普”,打引号是因为太深入的东西指望几篇文章也是不现实的。。。


先知道什么时候用,再说深入


什么时候使用Netty

用我个人的理解:狭隘的讲,Netty仅仅是网络通信层面的Java框架,和烂大街的SSH(M)是一样的,只不过它们的应用场景和定位不一样。

  • 应用场景上:只要项目中涉及到网络通讯,且有多连接(客户端)的数据读、写场景,都可以考虑基于Netty实现,但如果连接数不多,那么直接原生的实现方式又如何?能hold住即可。简单说如果项目的并发连接数不多,在我看来,低于1000-2000的都没必要用Netty,甚至NIO都不需要,为何这么说呢,因为我曾经用Java BIO API实现了一个聊天程序,记得是16G内存,4核的MacBook,跑到5000并发就卡死了。。。改成原生的NIO API实现(没用Netty)跑到5000轻轻松松。或者只是一些单纯的不涉及I/O操作的并发场景,Netty也是不适用的

  • 在定位上:可认为Netty是一个中间件,基于它可以实现Tomcat那种容器,所以它和SSM一样又不一样,做为Java程序员,写的项目没用到Spring(目前的Boot),MyBatis等都不好意思拿出去说,而Netty就不一样了,大部分的程序员可能根本接触不到,而且精通Netty的前置知识也是相对比较高级的,当然是相对的说,这也就是为什么培训机构不培训的原因。


如何深入掌握Netty

以下是我个人经历,如有误导,可以提出来讨论。

熟悉一个框架,一方面要掌握其常用API的功能和使用场景;另一方面应该熟悉框架的底层原理。

如果是一些中间件,那么深入其源码,并彻底掌握设计思想和实现细节,应该是这个框架学习的终点。

对于Netty,我觉得如果想不至于一脸懵逼的学习,应该掌握如下前置知识是最好的。搞定后写demo,熟悉API,然后后续遇到问题或者熟悉完了API就可以开始撸源码了,两相结合应该会事半功倍,如下列出一些前置技术点:

  • 理解传统的Java网络编程是怎么回事,熟悉Java的I/O流常用API,知道其原理

  • 知道BIO(也有说是OIO)和NIO都是什么玩意,最好是写过demo程序,没写过,也OK

  • 最好(可选)自己先动手实现一个能在你笔记本或者家用电脑上,轻松支撑5000并发的服务器(就基于TCP协议的网络聊天室就行),看看都会遇到哪些坑,哪些书,哪些资料需要查阅,性能瓶颈在哪儿,哪些地方是你感觉解决不了的,就知道还差多少了,如果你能很顺的实现出来且保证稳定,并消除所有的bug(不需要查阅资料,咨询任何人),我觉得Netty源码就没必要分析了,可以跳过看别的。否则带着这些问题再回过头看Netty源码,会轻松许多,融会贯通,豁然开朗

  • 熟悉Java多线程设计模式,重点的比如Future模式等,最好是读过<<Java并发编程实战>>,和《图解Java多线程设计模式》这两本书,知道JUC的原子类,线程安全的集合,volatile,threadlocal,CAS等是什么东西,Netty源码里会反复出现,当然不知道也行,反之都是要在分析源码是要学的

  • 熟悉常用设计模式,比如观察者、职责链、装饰、单例,模板方法,工厂等,这些模式在Netty源码里很常见

  • 理解操作系统的各种I/O模型,比如I/O多路复用,知道一些常见的系统函数,比如select,epoll等的原理,这对于理解Netty的设计有帮助,当然不知道也行,反之最后都会在分析源码时要学的

  • 最重要的还有熟悉TCP协议,这是基础的基础,最好是看过<<TCP/IP协议详解>>卷一的部分内容,比如TCP/IP章节

 

会收获什么?

我觉得Netty真的是个好东西,是它打开了我的源码分析之门,分析完毕让我不再惧怕任何一个陌生的框架,有如下的特点和收获:

  1. 代码不是很多,20多万行,最核心的就是有一半就不错了。。。容易入手建立信心!比起Spring(100多万行代码)这样的巨无霸,非常友好。而且也能学到很多黑科技,比其它一些框架,比如MyBatis(4万+行)要有意思,学习的东西相比之下也更实用,也不会上来就先涉及一些算法,比如Lucene,让人脱离代码和架构本身

  2. 一通百通,很多知名开源框架,其通信模块几乎都直接用的Netty,或者二次封装的,对理解,和使用其它框架大有帮助,比如Flink,thrift,ES,Hadoop等等,就算不是直接用的,但是掌握了NIO框架的开发模式,对理解其它框架和类似场景的网络模块会得心应手

  3. Netty是实践Socket编程,软件设计模式,高性能服务器设计理念,多线程设计模式,代码组织,以及写代码小技巧等等的不二之选

 

源码编译

git clone https://github.com/netty/netty.git
https://blog.csdn.net/weixin_34144848/article/details/92362888


Netty基本组件

先俯瞰Netty代码结构:

如上是Netty的几个核心的类或者机制。结合下面的官网的一个架构图(来源于http://netty.io

一句话——三个核心点:可扩展的事件驱动模型,通用的通信API,零拷贝以及ByteBuf,扩展开:

1、首先,要有编、解码器,这应该是一个网络框架最基本的组件了,基本原理涉及到TCP协议的本质(基于流的可靠协议),它在应用层会有粘包现象发生,需要开发者设计识别的约定,比如定长,分片等,这些Netty已经做好了,只不过Netty的可就复杂多了,它提供的编、解码器不仅种类多,而且细节更完善

2、其次,就是NIO线程池,Netty中叫NioEventLoopGroup,基于异步无锁化模式设计,而且封装了Netty自己的线程NioEventLoop,NioEventLoop表面上只是一个普通的类,但是其内部绑定了一个Netty的线程,叫FastThreadLocalThread,之所以这样设计,是因为Netty重写了JDK的ThreadLocal类,叫FastThreadLocal,重写的原因简单说就是因为Netty作者觉得JDK的ThreadLocal性能不行,自己就搞了更好的。而且Netty线程池还很好的同时处理了定时任务,异步任务等的分片执行和聚合逻辑,并为它实现了负载均衡。可以认为NioEventLoopGroup+NioEventLoop是Netty的心脏,因为最核心的新连接接入(select也叫I/O多路复用器)和I/O事件处理(processSelectedKey)逻辑,就是依靠的它俩完成的

3、基于2,Netty的服务端用法是实现两个线程池,一个是接入线程池,一个是I/O处理线程池,这个模式也叫Reactor模型

4、再次,Netty重新设计和封装了JDK底层的Socket/ServerSocket和ServerSocketChannel/SocketChannel等I/O相关的类,并设计了自己的Channel类,这样的设计灵活,方便业务代码使用。

5、再次,Netty设计了handler处理器,其基于责任链设计模式组装了一套业务逻辑链,底层是一个双向链表,这样设计的目的是为了方便业务代码的灵活扩展,可以让用户自己扩展实现不同的业务逻辑单元——Netty里叫ChannelHandler,将其加入handler链里(Netty里叫pipeline)被处理即可,并且该逻辑链底层是双向链表,可以让请求来回流动,可以看做是Netty的动脉。

6、再次,Netty更是重新设计了NIO的buffer,虽然NIO的buffer已经具备了I/O的常用API,但是还不够灵活和优秀,Netty对其进行了全方面的改造,消除了晦涩的设计,封装了自己的输入、输出流。

7、最后,Netty在自己封装的buffer的基础上,实现了自己的内存管理体系,不再强依赖Java的GC。而是大胆的使用了堆外内存管理技术,并设计了很多工具类,使其尽最大可能复用内存(内存池化技术),提高GC性能。

8、还有一点就是Netty修复了JDK NIO的所有已知bug!这是非常重要的,避免了开发人员直接使用NIO API而走弯路。

以上,当然只是基本的特性和组件,Netty还有很多优秀的闪光点和高级功能,后面细说。