1.Netty源码解析 -- FastThreadLocal与HashedWheelTimer
2.Netty源码-一分钟掌握4种tcp粘包解决方案
3.Nettyä¸çchannelReadåmessageReceivedçåºå«
4.Netty源码探究1:事件驱动原理
5.Nettyåç-ä»NIOå¼å§
Netty源码解析 -- FastThreadLocal与HashedWheelTimer
Netty源码分析系列文章接近尾声,本文深入解析FastThreadLocal与HashedWheelTimer。基于Netty 4.1.版本。 FastThreadLocal简介: FastThreadLocal与FastThreadLocalThread协同工作。FastThreadLocalThread继承自Thread类,内部封装一个InternalThreadLocalMap,微信转盘抽奖源码该map只能用于当前线程,存放了所有FastThreadLocal对应的值。每个FastThreadLocal拥有一个index,用于定位InternalThreadLocalMap中的值。获取值时,首先检查当前线程是否为FastThreadLocalThread,如果不是,则从UnpaddedInternalThreadLocalMap.slowThreadLocalMap获取InternalThreadLocalMap,这实际上回退到使用ThreadLocal。 FastThreadLocal获取值步骤: #1 获取当前线程的InternalThreadLocalMap,如果是FastThreadLocalThread则直接获取,否则通过UnpaddedInternalThreadLocalMap.slowThreadLocalMap获取。鲶鱼源码官网#2 通过每个FastThreadLocal的index,获取InternalThreadLocalMap中的值。
#3 若找不到值,则调用initialize方法构建新对象。
FastThreadLocal特点: FastThreadLocal无需使用hash算法,通过下标直接获取值,复杂度为log(1),性能非常高效。 HashedWheelTimer介绍: HashedWheelTimer是Netty提供的时间轮调度器,用于高效管理各种延时任务。时间轮是一种批量化任务调度模型,能够充分利用线程资源。简单说,就是将任务按照时间间隔存放在环形队列中,执行线程定时执行队列中的任务。 例如,环形队列有个格子,最新模式源码执行线程每秒移动一个格子,则每轮可存放1分钟内的任务。任务执行逻辑如下:给定两个任务task1(秒后执行)、task2(2分秒后执行),当前执行线程位于第6格子。那么,task1将放到+6=格,轮数为0;task2放到+6=格,轮数为2。执行线程将执行当前格子轮数为0的任务,并将其他任务轮数减1。 HashedWheelTimer的缺点: 时间轮调度器的时间精度受限于执行线程的移动速度。例如,每秒移动一个格子,则调度精度小于一秒的任务无法准时调用。 HashedWheelTimer关键字段: 添加延迟任务时,使用HashedWheelTimer#newTimeout方法,88微拍源码如果HashedWheelTimer未启动,则启动HashedWheelTimer。启动后,构建HashedWheelTimeout并添加到timeouts集合。 HashedWheelTimer运行流程: 启动后阻塞HashedWheelTimer线程,直到Worker线程启动完成。计算下一格子开始执行的时间,然后睡眠到下次格子开始执行时间。获取tick对应的格子索引,处理已到期任务,移动到下一个格子。当HashedWheelTimer停止时,取消任务并停止时间轮。 HashedWheelTimer性能比较: HashedWheelTimer新增任务复杂度为O(1),优于使用堆维护任务的ScheduledExecutorService,适合处理大量任务。然而,隐藏偷拍c源码当任务较少或无任务时,HashedWheelTimer的执行线程需要不断移动,造成性能消耗。另外,使用同一个线程调用和执行任务,某些任务执行时间过久会影响后续任务执行。为避免这种情况,可在任务中使用额外线程执行逻辑。如果任务过多,可能导致任务长期滞留在timeouts中而不能及时执行。 本文深入剖析FastThreadLocal与HashedWheelTimer的实现细节,旨在提供全面的技术洞察与实战经验。希望对您理解Netty源码与时间轮调度器有帮助。关注微信公众号,获取更多Netty源码解析与技术分享。Netty源码-一分钟掌握4种tcp粘包解决方案
TCP报文的传输过程涉及内核中recv缓冲区和send缓冲区。发送端,数据先至send缓冲区,经Nagle算法判断是否立即发送。接收端,数据先入recv缓冲区,再由内核拷贝至用户空间。
粘包现象源于无明确边界。解决此问题的关键在于界定报文的分界。Netty提供了四种方案来应对TCP粘包问题。
Netty粘包解决方案基于容器存储报文,待所有报文收集后进行拆包处理。容器与拆包处理分别在ByteToMessageDecoder类的cumulation与decode抽象方法中实现。
FixedLengthFrameDecoder是通过设置固定长度参数来识别报文,非报文长度,避免误判。
LineBasedFrameDecoder以换行符作为分界符,确保准确分割报文,避免将多个报文合并。
LengthFieldPrepender通过设置长度字段长度,实现简单编码,为后续解码提供依据。
LengthFieldBasedFrameDecoder则是一种万能解码器,能够解密任意格式的编码,灵活性高。
实现过程中涉及的参数包括:长度字段的起始位置offset、长度字段占的字节数lengthFieldLength、长度的调整lengthAdjustment以及解码后需跳过的字节数initialBytesToStrip。
在实际应用中,为自定义协议,需在服务器与客户端分别实现编码与解码逻辑。服务器端负责发送经过编码的协议数据,客户端则接收并解码,以还原协议信息。
Nettyä¸çchannelReadåmessageReceivedçåºå«
éè¦ç¼è§£ç çæä¼å»ç¨messageReceivedï¼ä¸è¬é½æ¯ä½¿ç¨ChannelReadæ¥è¯»åçã读ä¸ä¸SimpleChannelInboundHandlerçæºä»£ç ä½ å°±ç¥éäºï¼æ³åä¸å¹é ï¼ä¸ä¼è°ç¨messageReceivedçã
å¦ï¼å¦æä½ ç¹å«ç¹å«æ³ç¨SimpleChannelInboundHandlerï¼ä½ å¯ä»¥è¿æ ·æï¼ public classYouTCPServerHandler extends SimpleChannelInboundHandler<ByteBuf>{ ...}
å ä¸ºä½ æ²¡æåè¿ä»»ä½çç¼ç 解ç ï¼æä»¥ä½ çæ³åæ¯ByteBufï¼è¿æ ·ä½ è¯å®å¯ä»¥ä½¿ç¨messageReceivedæ¥æ¥æ¶å°æ¶æ¯äºãå¦æè¿ä¸æç½ï¼å»ºè®®ä½ å»
çä¸ä¸nettyèªå¸¦çsampleï¼éé¢æ个æ±é¶ä¹çä¾åï¼serveråclientä¼ éçBigInteger对象ï¼æ以就ç¨çæ¯SimpleChannelInboundHandler<BigInteger>ã没æç»è¿ä»»ä½ç¼ç 解ç çé£å°±è¯å®æ¯ByteBuf对象ã
Netty源码探究1:事件驱动原理
Netty源码探究1:事件驱动原理
Netty借鉴了Reactor设计模式,这是一种事件处理模式,用于管理并发服务请求。在模式中,服务处理器对请求进行I/O多路复用,并同步分发给相应的请求处理器。Netty的核心内容是Reactor,因此深入分析其在Netty中的应用至关重要。Netty吸收了前人优秀经验,构建出这款优秀的技术框架。
在Reactor设计模式中,Demultiplexer和Dispatcher是关键概念。Netty中的Demultiplexer是如何实现的?答案在于其Server端的架构设计。Netty通过Bootstrap(ServerBootstrap也适用)来构建Server,其中bind方法是启动Reactor运行的关键。在bind方法中,Netty创建并注册Channel到EventLoopGroup,从而实现Demultiplexer的功能。
Netty中的Channel与JDK中的Channel有何不同?Netty通过NioServerSocketChannel构建Server,其内部封装了Java NIO的Channel,但Netty的Channel与JDK中的Channel在注册到Selector时有所不同。Netty中的Channel注册到NioEventLoop中的Selector上,只关注OP_ACCEPT事件。当客户端连接时,事件被触发,Server响应客户端连接。这涉及NioServerSocketChannel的构造过程和Selector的创建。
Dispatcher在Java NIO中负责事件分发,Netty中如何实现这一功能?在NioEventLoop中,Selector.select()方法配合run()函数,共同实现事件监听循环。run函数中包含事件状态机和事件分派逻辑。当有事件到来时,状态机触发processSelectedKeys()方法,根据事件类型调用相应处理器进行处理。
Netty中的事件驱动原理最终如何与自定义handler关联?在NioEventLoop的processSelectedKey()方法中,事件处理逻辑与Channel.Unsafe接口相关联。Channel.Unsafe接口用于封装Socket的最终操作,Netty通过此接口与业务层Handler建立关联。通过调用handler的read方法,Netty将事件与业务处理逻辑关联起来。
总之,Netty通过Reactor设计模式实现了事件驱动原理,借助Demultiplexer和Dispatcher的机制,实现了对并发请求的高效处理。理解Netty的源码结构和事件驱动原理,对于深入掌握Netty技术框架至关重要。
Nettyåç-ä»NIOå¼å§
Nettyæ¯åºäºNIOçå¼æ¥éä¿¡æ¡æ¶ï¼æ¾ç»å¼å ¥è¿AIOï¼åæ¥æ¾å¼ï¼ï¼æ è¦è¯´Nettyåçæ们è¦å ä»NIOå¼å§ã
NIO æ¯JAVAå¨JDK4ä¸å¼å ¥çåæ¥éé»å¡é信模åï¼å¨NIOåºç°ä¹åï¼JDK4ä¹åï¼å¸åºä¸åªæä¸ä¸ªBIO模å顾åæä¹BLOCKING IO ï¼åæ¥é»å¡é信模åï¼
BIOï¼BLOCKING I/Oï¼ï¼
BIO 为ä¸ä¸ªè¿æ¥ ä¸ä¸ªçº¿ç¨ç模å¼ï¼å½æè¿æ¥æ¶æå¡å¨ä¼å¼å¯ä¸ä¸ªçº¿ç¨æ¥å¤ç请æ±
è¥æ¤è¯·æ±å¥é½ä¸æ³å¹²æ¤æ¶çº¿ç¨ä¼æä¹æ ·ï¼
æ¤çº¿ç¨ä¼è¿å ¥é»å¡æ¨¡å¼ï¼BLOCKINGï¼ï¼---å¥ä¹ä¸å¹²ï¼å¹²ççzzZZ~
è¿ç§ä¸è¿æ¥ï¼ä¸çº¿ç¨ç模å¼ä¼é ææå¡å¨èµæºä¸å¿ è¦çå¼é并ä¸å¨å¤§éè¿æ¥è®¿é®æ¶ æå¡å¨ä¼åçä»ä¹ï¼è½¦éï¼çº¿ç¨ï¼ä¸è¶³ï¼è½¦å¤ªå¤--æå µè½¦äº
ç±æ¤å°±åºç°äºNIO
â
NIOï¼new/NONBLOCKING I/Oï¼:
NIO为åæ¥éé»å¡é信模åï¼Selectï¼å¤è·¯å¤ç¨å¨ï¼ä¸ºæ¤æ¨¡åçæ ¸å¿ï¼å®ç°äºå¤ä¸ªè¿æ¥ä¸ä¸ªçº¿ç¨
å½æ客æ·ç«¯è¿æ¥è¯·æ±æ¶ æ¤è¿æ¥è¯·æ±ä¼è¢«æ³¨åè³selectä¸ï¼å½selectæ£æµå°æ¤è¿æ¥æI/O请æ±æ¶æä¼æå¼ä¸ä¸ªçº¿ç¨å»å¯¹æ¤I/O请æ±è¿è¡å¤ç-----å线ç¨æ¨¡å
è¿ä¸ªæ¶åæ人é®äºï¼è¿ä¹å¤æä½é½å¨ä¸ä¸ªçº¿ç¨éï¼çº¿ç¨å¿ä¸è¿æ¥æä¹åï¼
æ¤æ¶ ç±äºç½ç»è¯·æ±ãI/O读åãä¸å¡æä½é½å¨ä¸ä¸ªçº¿ç¨ä¸ï¼ä¼å¯¼è´å¨é«å¹¶åçæ åµä¸åå¨æ§è½ç¶é¢ äºæ¯ä¹æ人就æåºæ¥ å°ä¸å¡æä½ä¸¢å°å¦ä¸ä¸ªçº¿ç¨æä¹æ ·ï¼
äºæ¯åºç°äºç¬¬ä¸ç§reactor模å-使ç¨çº¿ç¨æ± è¿è¡æä½ç½ç»è¯·æ±ãIOå¨ä¸ä¸ªçº¿ç¨ï¼ä¸å¡æä½å¨å¦ä¸ªä¸ä¸ªçº¿ç¨ çä¸å¡å离----线ç¨æ± 模å
ä»æ¤å¾ä¸å¯ä»¥çåºæ¤æ¶ 模åä¸ä½¿ç¨ä¸ä¸ªçº¿ç¨æ± æ¥è¿è¡ç½ç»è¯·æ±ãIO读å
å½è¯»åå®æåå°ä¸å¡æä½ç»å®å¨çº¿ç¨æ± ä¸å¦å¤ç线ç¨ä¸-------ç½ç»IOä¸ä¸å¡æä½å¯ä»¥åæ¥è¿è¡äºï¼ä¸åé½å®ç¾äºèµ·æ¥ï¼
ä½æ¯ï¼äºæ è¿æ²¡å®ï¼ï¼è¿ä¸ªæ¶ååæ人æåºé®é¢ï¼å¨é«å¹¶åçæ¶åååï¼ä¼ä¸ä¼ææ§è½ç¶é¢
å 为ç½ç»IOæ¯é常æ¶èCPUçï¼å½ç½ç»è¯·æ±ä¸ç½ç»IOå¨å个线ç¨ä¸æ¶ï¼é CKçæ åµä¸å个线ç¨å¹¶ä¸è¶³ä»¥æ¯æèµ·ææçIOæä½ï¼å æ¤ä¹å½¢æäºå¨é«å¹¶åç¶æä¸çæ§è½ç¶é¢
äºæ¯å¤§ä½¬ä»¬å°±æ³çï¼å¦ææIOæåºæ¥è®©å个线ç¨æ± å»æ¥æ¶ç½ç»è¯·æ±ï¼ç¨å¦ä¸ä¸ªçº¿ç¨æ± æ¥è¿è¡IOä¸ä¸å¡æä½ä¼ä¸ä¼æ´å¥½
äºæ¯ç¬¬åç§Reactor模ååºè¿èç--主ä»Reactorå¤çº¿ç¨æ¨¡å
æ¤æ¨¡åä¸ mainReactoråªç¨äºæ¥æ¶ç½ç»è¯·æ±ï¼èsubReactorä¸ä¸ºä¸ä¸ªçº¿ç¨æ± ï¼çº¿ç¨æ± ä¸æ¯ä¸ªçº¿ç¨ä¸ç»å®ä¸ä¸ªselect
å½mainReactoræ¥æ¶å°è¯·æ±æ¶ï¼ä¸ä¸ªæè¿°ç¬¦ï¼ ç³»ç»ä¼çæä¸ä¸ªæ°çæ述符代表æ¤è¿æ¥çæï¼æ¤æ¶mainReactorä¼å°æ°çæ述符éè¿ä¸ä¸ªç®æ³å¨çº¿ç¨æ± ä¸éå®ä¸ä¸ªçº¿ç¨ å°æ¤æ述符ç»å®è³æ¤çº¿ç¨æ± ä¸çselectä¸ï¼ç±æ¤çº¿ç¨æ¥å¯¹è¯·æ±è¿è¡I/O ä¸ä¸å¡æä½
ä»æ¤ç¾ä¸è¿æ¥é«å¹¶åä¸æ¯é®é¢
åå°è¿ æ们æ¯ä¸æ¯æ³èµ·äºNettyçå¯å¨è¿ç¨
1ã声æ两个EventLoopGroupä¸ä¸ªä¸ºbossï¼mainReactorï¼ä¸ä¸ªä¸ºworkerï¼subReactorï¼
EventLoopGroupï¼çº¿ç¨æ± ï¼åå§åçæ¶åä¼çæï¼æå è½½ï¼æå®æ°éçEventLoopï¼çº¿ç¨ï¼è¥æ æå® åä¼çæCPUæ°X2ç线ç¨
2ã声æä¸ä¸ªå¯å¨è¾ å©ç±»Bootstrap并å°EventLoopGroup注åå°å¯å¨è¾ å©ç±»BootStrapä¸(bootStrap.group)
æ¥çåç»bootstrapæå®channel模åçå±æ§ï¼åæ·»å ä¸ä¸å¡æµæ°´çº¿ï¼channelpipelineï¼å¹¶ä¸å¨pipelineä¸æ·»å ä¸ä¸å¡æä½handlerï¼ï¼éè¿channelpipelineå¯ä»¥å¯¹ä¼ å ¥æ°æ®ä¸ºæ欲为ï¼
3ãç»å®ç«¯å£
Nettyå¯å¨å®æ
è¿æ¶åå¯è½æ人ä¼é®äºï¼è¿åä½ ä¸é¢è¯´çreactorï¼NIOæå¥å ³ç³»ï¼
è¿ä¸ªæ¶åæ们è¦è¿ä¹ç
â
è¥æ们å°bossä¸worker线ç¨æ± 设置为ç¸åçä¸ä¸ªçº¿ç¨æ± ï¼é£ä¹ä¼åçä»ä¹äºï¼
æ¤æ¶å ³æ³¨ä¸ä¸ç¬¬ä¸ä¸ªReactor模åæ¶å°±ä¼åç° å½BOSS=WORKERæ¶å nettyå®ç°çå°±æ¯ç¬¬ä¸ç§Reactor模å 使ç¨çº¿ç¨æ± 模å
èå½bossä¸çäºworkerçæ¶å使ç¨çå°±æ¯ç¬¬åç§ ä¸»ä»å¤çº¿ç¨æ¨¡å
Nettyå°±æ¯åºäºReactor模åæ¥å¯¹NIOè¿è¡äºæç¨åå°è£ ï¼ä»Nettyæºç ä¸å°±å¯ä»¥çåºæ¥å ¶å®åºå±è¿é½æ¯NIOçæ¥å£
æ¤æ¬¡å¤ä¸ºèªå·±è¯»æºç ä¹åçç解 å¦æ误请ææ£
ææ©
åææ¿ä¸ç¬¬ä¸ä¸ªèµ