Netty进阶之路:跟着案例学Netty - (EPUB全文下载)
文件大小:1.09 mb。
文件格式:epub 格式。
书籍内容:
Netty进阶之路:跟着案例学Netty
第1章 Netty服务端意外退出案例
第2章 Netty客户端连接池资源泄漏案例
第3章 Netty内存池泄漏疑云案例
第4章 ByteBuf故障排查案例
第5章 Netty发送队列积压导致内存泄漏案例
第6章 API网关高并发压测性能波动案例
第7章 Netty ChannelHandler并发安全案例
第8章 车联网服务端接收不到车载终端消息案例
第9章 Netty 3.X版本升级案例
第10章 Netty并发失效导致性能下降案例
第11章 IoT百万长连接性能调优案例
第12章 静态检查修改不当引起性能下降案例
第13章 Netty性能统计误区案例
第14章 gRPC的Netty HTTP/2实践案例
第15章 Netty事件触发策略使用不当案例
第16章 Netty流量整形应用案例
第17章 Netty SSL应用案例
第18章 Netty HTTPS服务端高并发宕机案例
第19章 MQTT服务接入超时案例
第20章 Netty实践总结
第1章 Netty服务端意外退出案例
在使用 Netty 进行服务端程序开发时,主要涉及端口监听、EventLoop 线程池创建、NioServerSocketChannel 和 ChannelPipeline 初始化等。初学者如果对服务端相关类库的工作原理和用法不熟悉,则会导致程序启动或者退出发生问题。本章从一个初学者容易犯错的案例展开分析,抽丝剥茧,让大家更好地掌握 Netty服务端启停的原理和技巧,避免在工作中犯类似的错误。
1.1 Netty服务端意外退出问题
案例1 通过阻塞方式绑定监听端口,启动服务端之后,没发生任何异常,程序退出,代码示例如下:
案例2 对案例1进行排查时,发现没有监听Close Future,于是对代码进行修改,还是会发生服务器套接字直接关闭、进程退出的问题,代码示例如下:
1.1.1 Java Daemon线程简介
在分析上面两个案例之前,需要弄清楚 Java 进程退出的原理,首先了解下 Java 的Daemon线程。所谓守护线程(Daemon)就是运行在程序后台的线程,通常守护线程是由JVM 创建的,用于辅助用户线程或者 JVM工作,比较典型的如 GC线程。用户创建的线程也可以设置成 Daemon 线程(通常需要谨慎设置),程序的主线程(main 线程)不是守护线程。Daemon线程在Java里面的定义是,如果虚拟机中只有Daemon线程运行,则虚拟机退出。
(1)虚拟机中可能同时有多个线程运行,只有当所有的非守护线程(通常都是用户线程)都结束的时候,虚拟机的进程才会结束,不管当前运行的线程是不是main线程。
(2)main 线程运行结束,如果此时运行的其他线程全部是 Daemon 线程,JVM 会使这些线程停止,同时退出。但是如果此时正在运行的其他线程有非守护线程,那么必须等所有的非守护线程结束,JVM才会退出。
看一下Daemon线程工作示例,主线程执行完,只有 Daemon线程,进程退出,代码如下:
程序运行15s之后,进程正常退出,如图1-1所示。
图1-1 Daemon线程退出执行结果
启动非Daemon线程,即使main线程执行完成,进程也不会退出,代码示例如下:
程序执行结果如图1-2所示,尽管main线程已经执行完成,但是JVM进程并没有退出。
图1-2 非Daemon线程退出执行结果
1.1.2 Netty服务端启动原理
在Netty中,通过bootstrap.bind(PORT).sync().channel()方法绑定服务端端口,并不是在调用方的线程(示例为main线程)中执行,而是通过NioEventLoop线程执行,它的启动堆栈如图1-3所示。
图1-3 Netty服务端端口绑定启动堆栈
最终的执行结果其实就是调用了Java NIO Socket的端口绑定操作:
端口绑定操作执行完成之后,main 函数就不会阻塞,如果后续没有同步代码,main线程就会退出。main线程退出是否意味着 JVM进程一定退出?并非如此,只有所有非守护线程全部执行完成,进程才会退出。此时系统中还存在其他非守护线程在运行吗?通过线程堆栈可以直观地查询各线程的运行状态,如图1-4所示。
图1-4 Netty服务端线程堆栈
main线程已经运行结束,但是Netty的NioEventLoop还处于运行状态,因此JVM进程并没有退出。
通过对NioEventLoop源码进行分析,可以明确如下几点。
(1)NioEventLoop是非守护线程。
(2)NioEventLoop运行之后,不会主动退出。
(3)只有调用shutdown系列方法,NioEventLoop才会退出。
按照上面的分析,即使main函数执行结束,Netty服务端启动之后进程也不应该退出,但为什么又退出了呢?仔细查看案例的代码,发现退出的原因有两点。
(1)调用b.bind(18080).sync()之后,尽管它会同步阻塞,等待端口绑定结果,但是端口绑定执行得非常快,完成后程序就继续向下执行。
(2)程序在finally里面执行了bossGroup.shutdownGracefully()和workerGroup.shutdown-Gracefully(),它同时会关闭服务端的 TCP 连接接入线程池(bossGroup)和处理客户端网络I/O读写的工作线程池(workerGroup),关闭之后,NioEventLoop线程退出,整个系统的非守护线程就全部执行完成了,此时main函数主线程也早已执行完,因此JVM就会退出。因为调用的是 Netty 的优雅退出接口(shutdownGracefully),所以整个退出过程并没有发生异常。
出现案例2的问题,主要原因是使用者并没有掌握Netty的ChannelFuture机制,Netty是一个异步非阻塞的通信框架,所有的I/O操作都是异步的,但是为了方便使用,例如在有些场景下应用需要 ............
以上为书籍内容预览,如需阅读全文内容请下载EPUB源文件,祝您阅读愉快。
书云 Open E-Library » Netty进阶之路:跟着案例学Netty - (EPUB全文下载)