JAVA NIO 复习
请先参考我之前的博文JAVA学习笔记–3.Network IO的 NIO(NonBlocking IO) SOCKET 章节。这里主要讲下JAVA NIO其中几个比较被忽略的细节,不求全,欢迎补充。
API
Select
当调用ServerSocketChannel.accept();
时,如果该channel处于非阻塞状态而且没有等 待(pending)的连接,那么该方法会返回null;否则该方法会阻塞直到连接可用或者发生I/O错误。此时实际上Client发送了connect 请求并且服务端是处于non-blocking模式下,那么这个accept()会返回一个不为null的channel。
当调用SocketChannel.connect()
时,如果该channel出于non-blocking模式,只有在本地连接下才可能立即完成连接,并返回true;在其他情况下,该方法返回false,并且必须在后面调用 SocketChannel.finishConnect
方法。如果SocketChannel.finishConnect
的执行结果为true,才意味着连接真正建立。
SocketChannel.write()
方法内部不涉及缓冲,它直接把数据写到socket的send buffer中。
坑
每次迭代selector.keys()完时,记得remove该SelectionKey,防止发生CPU100%的问题。
通常不该register OP_WRITE,一般来说socket 缓冲区总是可写的,仅在write()方法返回0时或者未完全写完数据才需要register OP_WRITE操作。当数据写完的时候,需要deregister OP_WRITE。 socket空闲时,即为可写.有数据来时,可读。对于nio的写事件,只在发送数据时,如果因为通道的阻塞,暂时不能全部发送,才注册写事件key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
。等通道可写时,再写入。同时判断是否写完,如果写完,就取消写事件即可key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
。
空 闲状态下,所有的通道都是可写的,如果你给每个通道注册了写事件,那么肯定是死循环了,导致发生CPU100%的问题。详见Netty的 NioSocketChannel的父类方法setOpWrite()和clearOpWrite()方法。这个在iteye里面的帖子Java nio网络编程的一点心得也有说明。
在register OP_CONNECT后,并且触发OP_CONNECT后,需要再deregister OP_CONNECT。详见Netty的NioEventLoop.processSelectedKey()方法后半部分。
另外,需要注意到Selector.wakeup()是一个昂贵的操作,一般需要减少是用。详见NioEventLoop.run()方法内的处理方式。
还有各种各样的坑,实在太多了。详见Java NIO框架的实现技巧和陷阱
NIO操作在Netty里面的体现
虽然笔者阅读完几个重要的交互过程,但是代码细节较多,无法体现NETTY对NIO的使用。于是画了两幅图,与读者共享。
事先说明下,下图图片上的标记2表示是一个新的EventLoop线程,非main线程。
另外,虽然Netty中大量使用了ChannelFuture异步,但是换种方式理解的话,可以理解为同步执行。
服务端启动
客户端启动
服务端处理请求
这里有个细节,就是boss线程注册了OP_ACCEPT线程,然后当接收到客户端的请求时,会使用work线程池里面的线程来处理客户端请求。代码细节在NioServerSocketChannel.doReadMessages
的tag1.1.2处以及child.unsafe().register(child.newPromise());
处。
Netty整体架构
模块结构
从Netty的Maven仓库可以看
到,大致分为如下模块:
- netty-transport:框架核心类Channel,ChannelPipeline,ChannelHandler都是在这个模块里面定义的,提供了对不同协议支持框架。
- netty-buffer:对ByteBuffer的抽象,可以理解为网络中的数据。
- netty-codec:对不同格式的数据进行编码,解码。
- netty-handler:对数据进行处理的handler
- netty-common:公共处理类。
综上,可以看出,首先对框架机制和传输的数据进行了抽象,然后又对数据如何在框架中传输进行了抽象。
他山之石
下面的介绍的思想比较零散,不成系统,主要是阅读代码过程中产生的碰撞,供读者参考。
好的设计
Netty 同样也采用了多个Selector并存的结构,主要原因是单个Selector的结构在支撑大量连接事件的管理和触发已经遇到瓶颈。
Bootstrap.channel()方法通过传递class对象,然后通过反射来实例化具体的Channel实例,一定程度上避免了写死类名字符串导致未来版本变动时发生错误的可能性。
框架必备的类,大家还可以看下common工程,里面真是一个宝藏。
-
InternalLogger
用来避免对第三方日志框架的依赖,如slf,log4j等等。 -
ChannelOption
灵活地使用泛型机制,避免用户设置参数发生低级错误。 -
SystemPropertyUtil
提供对xt属性的访问方法 -
DefaultThreadFactory
提供自定义线程工程类,方便定位问题。 -
PlatformDependent
如果需要支持不同平台的话,可以把平台相关的操作都放在一起进行管理。
打印日志时,可以参考这样来拼接参数,String.format("nThreads: %d (expected: > 0)", nThreads)
@Sharable表示该类是无状态的,仅仅起“文档”标记作用。
在子接口里仅仅把父接口方法返回值覆写了,然后什么都不做。这样一定程度上避免了强制转型的尴尬。
把前一个future作为下一个调用方法的参数,这样可以异步执行。然后后面的逻辑可以先判断future结果后再进行处理,从而提升性能。
中立
addLast0 等以0为结尾的方法表示私有的含义。
有些方法的getter、setter前缀省略,有点类似jQuery里面命名风格。不过不太建议在自己的产品中使用这种风格,尽量使用和和产品内的一样的命名风格。
疑惑
心中存疑,请大家不吝赐教。
在NioEventLoop.run()方法中,好像每次用完SelectionKey没有remove 掉它,可能和SelectedSelectionKeySet实现机制有关。但是没直接看出来具体之间的联系,
为什么boss也要是个线程池?目前来看,服务端2个线程保持不变,main线程出于wait状态,boss线程池其中的一个线程进行接收客户端连接请求,然后把请求转发给worker线程池。
javaChannel().register(eventLoop().selector, 0, this);
,为什么ops参数默认是0?
socketChannel.register() and key.interestOps()
还是有点不太明白,估计我的思路钻进死胡同了。
瑕疵
b.bind(port)这个里面的内容非常复杂,不仅仅是bind一个port那么简单。所以该方法命名不是很好。
父接口依赖子接口,也不是很好。
DefaultChannelPipeline.addLast 这个方法太坑了,并不是把handler加到最后一个上面,而是加到tail前一个。
无一类外的是,继承体系相对复杂。父类,子类的命名通常不能体现出谁是父类,谁是子类,除了一个Abstract能够直接看出来。
注意事项
客户端单实例,防止消耗过多线程。这个在http://hellojava.info/中多次提到。
其他
目前网上的NIO例子都基本都不太靠谱,BUG多多。建议可以参考下《JAVA 分布式JAVA应用 基础与实践》。
JAVA NIO不一定就比OIO快,重点是更加Scalable。
框架帮趟坑,不要轻易制造轮子,除非现有轮子很差劲。JAVA NIO里面的坑太多了,Netty里面的大量的issue充分说明了问题。技术某种程度上不是最重要的,如果大家努力程度差不多的话,技术上不会差到哪里去。开源产品主要是生态圈的建设。
接收对端数据时,数据通过netty从网络中读取,进行其他各种处理,然后供应用程序使用。发送本地数据时,应用程序首先完成数据处理, 然后通过netty进行各种处理,最终把数据发出。但是为什么要区分inbound,outbound,或者说提供了head->tail以及 tail->head的遍历?
当我们跳出里面的细节时,考虑一下,如果你是作者的话,会如何考虑。整体的一个算法 。不同的通讯模型,nio,sun jdk bug, option(默认和用户设置),异步future、executor,pipeline、context、handler, 设计模式 。
我想象中操作应该是这样的,handler链管理不需要走pipeline,event链也不需要走pipiline,仅仅对数据的发送,接收和操 作才走pipeline。事件机制应该起一些增强型、辅助型作用,不应该影响到核心流程的执行或者起到什么关键作用,主要是应该给第三方扩展用。而 netty中,所有的一切都要走pipelne。
太多异步,怎么测试?
招式vs心法。招式,相当于api;心法,相当于api工作原理,利与弊。还是要理解底层,否则还是可能理解不清楚。cpu,内存,io,网络,而最终浮于招式。
看完了么?知道了Netty是什么,内部大概是怎么运作的,但是有些细节还不知道为什么。真的就理解精髓了么?NIO的坑.. 底层OS的坑.. Netty的精髓是在于对各种细节的处理,坑的处理,对性能的处理,而不是仅仅一个XX模式运用。JAVA NIO细节和坑实在太多,估计再给我一周的时间,也研究不完。有点小沮丧。
源于:http://my.oschina.net/geecoodeer/blog/193941
相关推荐
《深入剖析Nacos Server 1.1.0-SNAPSHOT:源码解析与核心功能探秘》 在当今数字化时代,分布式系统管理成为了IT领域的热门话题。Nacos,作为阿里巴巴开源的一款动态服务发现、配置管理和远程调用中间件,自发布以来...
### Netty源码解析——服务启动过程 #### 一、Netty概述 Netty是一个高性能、异步事件驱动的网络应用框架,它被广泛应用于快速开发高性能协议服务器和客户端。Netty通过高度优化的设计和实现提供了低延迟和高吞吐...
总结,Apache SkyWalking 是一个强大的 APM 工具,能够提供全面的微服务监控能力。通过在 CentOS 系统上安装和配置 9.7.0 版本,你可以更好地了解你的应用程序的健康状况,及时发现和解决问题,提升运维效率。记得...
《Netty源码深入分析》是由美团基础架构部的闪电侠老师所分享的一系列关于Netty源码解析的视频教程。以下将根据标题、描述、标签以及部分内容等信息,对Netty及其源码进行深入剖析。 ### Netty简介 Netty是基于...
这个"Netty源码分析总结.rar"压缩包文件,从其标题和描述来看,很可能是针对Netty的源码分析课程或者笔记的集合,其中包含了对Netty核心机制的深入探讨。尽管提供的子文件名是"课时34:Netty源码分析总结下期预告....
在《Netty进阶之路:跟着案例学Netty》中,作者将在过去几年实践中遇到的问题,以及Netty学习者咨询的相关问题,进行了归纳和总结,以问题案例做牵引,通过对案例进行剖析,讲解问题背后的原理,并结合Netty源码分析,...
通过对Netty源码的深入分析,我们不仅能够了解到其内部工作原理,还能学习到许多优秀的设计思想和技术实践,这对于提高个人的技术水平和解决实际问题有着非常重要的意义。希望本文能够帮助读者更好地理解和掌握Netty...
在《Netty进阶之路:跟着案例学Netty》中,作者将在过去几年实践中遇到的问题,以及Netty学习者咨询的相关问题,进行了归纳和总结,以问题案例做牵引,通过对案例进行剖析,讲解问题背后的原理,并结合Netty源码分析,...
#### 五、Netty源码分析实战案例 1. **ChannelHandlerContext与ChannelHandlerAdaptor详解**: - 分析`ChannelHandlerContext`的生命周期及其与`ChannelHandler`之间的交互方式。 - 深入理解`...
在深入探讨Netty源码依赖包的相关知识点之前,我们首先需要了解Netty的基本概念及其重要性。Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器与客户端。它提供了丰富的...
源码分析: 1. **协议解析**:JT808协议的解析通常包括消息头的解析、消息体的解析以及校验码的验证。消息头包含消息类型、序列号、发送方和接收方的ID等信息。源码会定义一个类来表示JT808的消息结构,并通过...
Netty对Channel总结的思维导图,包括功能梳理,源码分析。
《Netty权威指南》是异步非阻塞通信领域的经典之作,基于最新版本Netty 5.0编写,是国内首本深入介绍Netty原理和架构的技术书籍,也是作者多年实战经验的总结和浓缩。在理论方面,讲解了Netty的逻辑架构模型和核心...
源码分析: 1. **项目结构**:在mycodes-master这个项目中,我们可以看到典型的Maven工程结构,包括`src/main/java`、`src/test/java`等目录,分别存放源代码和测试代码。通过阅读这些代码,我们可以学习到Netty如何...
Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。在本文中,我们将深入浅出...结合源码分析和实践操作,我们可以更深入地理解 HTTP 协议及其在网络编程中的应用。
Spring源码分析.pdf Spring面试专题.docx Spring面试专题及答案.pdf Spring面试题(含答案).pdf Tomcat面试专题.docx vivo2021届春季招聘在线编程考试.docx 哔哩哔哩2021招聘后端笔试卷(一).docx 哔哩哔哩2021...
88_ReplayingDecoder源码分析与特性解读;89_Netty常见且重要编解码器详解;90_TCP粘包与拆包实例演示及分析;91_Netty自定义协议与TCP粘包拆包问题解决之道;92_精通并发与Netty课程总结与展望