Netty 源码阅读入门实战(四)-NioEventLoop

简介: 1 NioEventLoop概述总述2 NioEventLoop创建概述...

1 NioEventLoop概述

img_3e4785299a22452f236c5bd807c8ba8d.png
  • 总述


    img_894ae143336480cafb294fb7b7eb754c.png

2 NioEventLoop创建概述

img_53fb576085d067dd6b85a64fa752e202.png

img_4fd551a1189d5ac095ed889678dd1b67.png

img_5e5d043ebe0111676b4f2860d25261cf.png

img_923eb37fc5c4bb2224baa47dcf058ee3.png

img_6be0b71801960103d81bbe47127294a9.png

img_db4a8bbe9a6ebfb30cfb3a510aef3ca0.png

img_8ef94f14216d84311f57149372048afd.png

img_c7a73c17629efc66508bd362624893b0.png

img_0627868028fcfe3152c953910394f9bc.png

img_9e7f882f0332b40e8387d1514672a39e.png

对应


img_56ca0ac8e30e014d84b36af1984d58ad.png

img_d4557d5ffc8691d0d3292e672422afe8.png

对应
img_1b5faa6d6a8d3e524ab9da0bd97909c1.png

img_8e7efd6855fbe93cb9cc09d3bbb7842f.png

对应
img_216ffbe3c7f58f01e31921a4bf9c1600.png

img_d3f37a76e9ccef688431c71d06570323.png

对应
img_e70c942dfd72b8ce1c724db50533bd72.png

3 ThreadPerTaskThread

2 服务端Channel的创建

img_d90f7ad5065ed6dcfdf00386f55d2b5a.png

img_1623de9d6ac7bd6458269b7de174270e.png

img_8d2048306cf000a168b99de798195cbd.png

img_97516cbde3eca1b3408382d727d5ecba.png

bind 对应样例的


img_0a486ac537cbfbc776082274e8dbaa1d.png
跟进调试

img_00a649bb1a1159786692b05ad0893317.png

img_a5e4e8927e31bb0ae9468cec0715c2df.png

img_bbb42f0d6b2c6dbd8ced76e111baf958.png

img_24a3ee1159a8440cf8214f8951cec913.png

img_a502e1e10677215724526a1d1d68fdd9.png
通过反射创建的 channel

看看 channelFactory


img_5cd17ac276cc3e7558e54cf3ace25860.png

img_b778f680d274e1abea3cf7076b235924.png
  • 反射创建服务端 Channel


    img_50c088795c1708bcc39ba8194a2b4f4b.png

    首先


    img_9296bb35cd2e94366cb132a3d4c27e81.png

    img_468901ac926279cdabaa6820e94e511a.png

    img_323f4fca1c5e6a242346b5443c590581.png
    创建完毕了

    img_2482e50e588146334404aeffdec67718.png

    img_a01a99a9ad2f4af7cb2cf40625a859a2.png

    img_049b55ed9cb8268f217e94c5ba71220d.png
  • ANC


    img_4a5d2de4d095cf6e73583ce2b0de9279.png

    img_e187867d5261ed0e2c974694e90027bc.png

    img_4c49db79e4b43fc7089cdb4cdc0519ab.png

    img_6f1bf73adb85d5248fdec448df542c7c.png

    img_dd0eea4afcaad6de1b301c39e9d2d728.png

    img_425cdab272babe3736b3e0cb6a643a7c.png

    img_07ba31e5e82cf5669ce171063ceac8cb.png

4 创建NioEventLoop线程

img_2da0e7afef0ef694035d6f9d6ed1b771.png

img_f2f31c12374dc22a11a6853c2cce518d.png

img_c7e16a985607241f2c23a1313fb17506.png

img_bfd458e96d7ab387532b511092771beb.png

img_54cba9ccb044d443e78dc09731a69269.png

img_d8a349681821446f8338162ebab2d548.png

img_fdab4fd5755fe08eb4d488053fea02e7.png

img_e153b220ee55deeb3838db5afd03abce.png

img_a517b472b16f5ceb9e6c90c78fd1c250.png

5 创建线程选择器

img_0b8f0b9fd0eba85c6e62d6162936ec6e.png

img_47295f9db325de2cebf12fe07a33aa15.png

img_9c87a458914e9d253c3ed305f6f2f838.png

img_a91b415259c9a060a2d94bec2dddfeed.png
  • 先看看普通的


    img_204ee1739ca0b0401df1e18c989ae7a0.png

    img_440fe0a42d45d4d307fa1c0d6c2b03b5.png
  • 再看幂2的


    img_342285778753a6bfe4319294db34055d.png

    img_4aa32b95ceb87ae95fea5f038ecaeaa6.png
    循环取数组索引下标,& 比取模性能更高

6 NioEventLoop的启动

img_65060a73b49b134941a62a72a0e41b67.png

img_c7d6e34acce07a894aa906902c672d2a.png

img_498762120ee101e3e97716e0644be1bb.png

对应是


img_ba46d65e596d2e83bcfc8e031695e55a.png

img_aede86f3dd6ac70d8656d97e41b68f72.png

对应是
img_e4ca09089cd9d7ff88f40cfd481872d2.png

img_d32113cb801e680d37fb9ae4bd08e2d0.png

img_9d72563fb488cfbb4b56ba4bc964e77c.png

img_1eff0444dd6f1a1527bb7ba9dcc8404d.png

img_198dd93d64e992cbb8193e4a4a8a66b5.png

img_95138239a20556fd366a27942a8ded49.png

img_73d16fa11b66a419bff329ae4f9db4f0.png

img_7cc935722fac620d8b22f59f861b4dbc.png

img_0e1152fdd5ddc1bc63c2dbfa34664bd7.png

img_61fbde07e980812b8a5b698ee67220b6.png

img_e753b40e799240a0ec7c1babbc7a8763.png

img_8a497d398c55905cc7f02e6af37afec5.png

img_e94c77712cdcbe30ce6cabbec34541dc.png

7 NioEventLoop执行概述

8 检测IO事件

img_c1033feeeb1edaf9d3d4c012fb1263f5.png
img_e0891ff76d9b693a5713a01f81271f41.png

对应的源码为


img_5b85e3590552270665313b0a5879b61c.png

img_54a45e93cd117d0f2af79bc9f51ad383.png

img_c95e3d7f34a905627f0c77605087d822.png

img_61f78d919dfe4f8c9e34e6cc3277713c.png

img_35bc109c694ece683d4514ef98cc17d9.png

对应的源码为


img_382a3463ff1de840c1a1b159542c4305.png

img_4165a6fd9641ce3f326bf7263fd941d8.png

img_37994cc629904c85a98d2fa69e2b2576.png
执行至此,说明已进行了一次阻塞式的 select 操作

img_9401e624538e59d888c7894fbe3225ca.png
产生空轮询的判断

img_b5f8065ca29adc3151c9c0b3d141d95c.png
当空轮询次数大于阈值

img_1004360436bd9c6e23569c2bac4a8a42.png
阈值定义

img_1ee5c435ca80c6a58cd47348b084dbe4.png

img_0a688cd41c789b1004a6cf874909b51e.png
阈值

img_5005ab355dca47877c98ea528a369f31.png

避免空轮询的再次发生


img_3c644bc1ddcb4049162fa6383f3ea5cb.png
创建新选择器

img_eb2537762ad5ccad1148cdc379bd2670.png
获取旧选择器的所有 key 值

img_26106e9505a176f5a9f958fdae59511d.png
netty 包装的 channel

img_3f30ee3f507d41b5af0d6f2799b147d5.png
将之前的 key 事件解除,并绑定新的选择器和对应的事件

img_7372b6cd0cefd8d54cb1c63a348f7cfd.png
更新选择器的 key

img_bb65dd483c6f82727a1bc16a05f57309.png
至此,解决了空轮bug

9 处理IO事件

img_fd03c691501a0c25885550682ba1bd8d.png

img_0ba37ad091015deac5e31fd9221bfcba.png

img_39d052f3827a48a2e31d819087c1177e.png
原生JDK创建一个 selector

img_965ba11c640f31dc4125f70f1b862f40.png

img_5b9384b9e7e36d3c6b417ff49560fdf0.png
单线程处理,其实不需要两个数组,后续版本已经是一个数组

img_42e7771d45565c74346cdde91e26e9c7.png
只需关注

img_133774a2695959973277e72fc024a5db.png
根本不需要此三个方法

img_e469f54619c99f088934d5fcdf8ab0d1.png

img_77abc4ac64c6a4cc1e3a28660b094eb0.png
通过反射

img_907ddb46ff96367dc6d7982f0d588b72.png
即此类

img_be97f28158930993f578632ce87fa89c.png

img_b22b329da7f6c89b1a61accbd8266493.png
继续反射流程

img_889585a38aa465cedb558a8a830b67a5.png
替换为优化后的 set 集合

一句话总结:用数组替换HashSet 的实现,做到 add 时间复杂度为O(1)


img_c5ad660d7b871d50358198101c2f1845.png

img_ac98eef51b944d6f91a9e31eeed7afd1.png

img_0d7f77f74af1e826ab786f4792a0d9bc.png

img_395f97c37d7704f001f570a3e1da6516.png

img_1548846e57b6d47a7fc39059e812822d.png
 private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
        if (!k.isValid()) {
            final EventLoop eventLoop;
            try {
                eventLoop = ch.eventLoop();
            } catch (Throwable ignored) {
                // If the channel implementation throws an exception because there is no event loop, we ignore this
                // because we are only trying to determine if ch is registered to this event loop and thus has authority
                // to close ch.
                return;
            }
            // Only close ch if ch is still registerd to this EventLoop. ch could have deregistered from the event loop
            // and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is
            // still healthy and should not be closed.
            // See https://github.com/netty/netty/issues/5125
            if (eventLoop != this || eventLoop == null) {
                return;
            }
            // close the channel if the key is not valid anymore
            unsafe.close(unsafe.voidPromise());
            return;
        }

        try {
            int readyOps = k.readyOps();
            // We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
            // the NIO JDK channel implementation may throw a NotYetConnectedException.
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
                // See https://github.com/netty/netty/issues/924
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);

                unsafe.finishConnect();
            }

            // Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {
                // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
                ch.unsafe().forceFlush();
            }

            // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
            // to a spin loop
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();
                if (!ch.isOpen()) {
                    // Connection already closed - no need to handle write.
                    return;
                }
            }
        } catch (CancelledKeyException ignored) {
            unsafe.close(unsafe.voidPromise());
        }
    }

Netty 默认通过反射将selector 底层的 HashSet 实现转为数组优化
处理每个 ketSet 时都会取到对应的 attachment,即在向 selector注册 io 事件时绑定的经过 Netty 封装后的 channel

10 -reactor线程任务的执行

img_d23531f3224a2d31cdb3858e2aa42057.png

img_b5b4f34ff495d0656a9b1c0e65e1c9fd.png

img_8b21f0bd17294cf0dbbe103a9b9f8922.png

img_56bae058c9e2c790f753805a9706d7d4.png

img_e2c45258dd345a4692da4d5cec464516.png

img_a2d489961a756d9c5e719ab487df9374.png

img_963832f921026cba097fc6856b2aa3d0.png

img_265750faea00d304829ac7799c846428.png
定时任务

img_31c0c67984722ca5fabf0819840c362f.png

img_881fa2c9e3d74ad8076bcc3e3cb16e03.png

img_c095536dc17b1669781ee866e99884c1.png

img_dbc11182ff1f6ab5f9b55536a4293920.png

img_bbe94ed8f724dfe331369c0b6f94898a.png
从定时任务中拉取

img_b67416cae0726a23d44fa1ff16f7cb39.png

img_bb45580e58227f60a045c952d9e100d7.png
根据时间,时间相同根据名称

img_6684d628a9ba7408c147c2de6cdd07b1.png
取nanotime 截止时间前的定时任务

img_2e858d56ec5a823b00eb4f469244aa25.png

img_41bbfe21db0e70353a4b34f31905cde6.png

img_6d8e64f40916a99ea0663a7a851be9b9.png
从普通 taskqueue 中取任务

img_94c627eb719fd029af84268b0e814863.png
目录
相关文章
|
7月前
|
缓存 网络协议 算法
Netty的基础入门(上)
Netty的基础入门(上)
244 1
|
7月前
|
网络协议 Java 测试技术
阿里内部Netty实战小册,值得拥有
Netty 是一个高性能的 Java 网络通信框架,简化了网络编程并涵盖了最新的Web技术。它提供了一种抽象,降低了底层复杂性,使得更多开发者能接触网络编程。Netty 因其易用性、高效性和广泛的应用场景受到推崇,适合互联网行业从业者学习,有助于理解和开发基于Netty的系统。免费的《Netty实战小册》详细介绍了Netty的各个方面,包括概念、架构、编解码器、网络协议和实际案例,帮助读者深入理解和应用Netty。如需完整版小册,可点击链接获取。
阿里内部Netty实战小册,值得拥有
|
1月前
|
消息中间件 编解码 网络协议
Netty从入门到精通:高性能网络编程的进阶之路
【11月更文挑战第17天】Netty是一个基于Java NIO(Non-blocking I/O)的高性能、异步事件驱动的网络应用框架。使用Netty,开发者可以快速、高效地开发可扩展的网络服务器和客户端程序。本文将带您从Netty的背景、业务场景、功能点、解决问题的关键、底层原理实现,到编写一个详细的Java示例,全面了解Netty,帮助您从入门到精通。
146 0
|
4月前
|
编解码 NoSQL Redis
(十一)Netty实战篇:基于Netty框架打造一款高性能的IM即时通讯程序
关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的IM聊天程序。
109 3
|
4月前
|
前端开发 网络协议
Netty实战巅峰:从零构建高性能IM即时通讯系统,解锁并发通信新境界
【8月更文挑战第3天】Netty是一款高性能、异步事件驱动的网络框架,适用于开发高并发网络应用,如即时通讯(IM)系统。本文将指导你利用Netty从零构建高性能IM程序,介绍Netty基础及服务器/客户端设计。服务器端使用`ServerBootstrap`启动,客户端通过`Bootstrap`连接服务器。示例展示了简单的服务器启动过程。通过深入学习,可进一步实现用户认证等功能,打造出更完善的IM系统。
193 1
|
4月前
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
253 2
|
7月前
|
存储 消息中间件 缓存
Netty的基础入门(下)
Netty的基础入门(下)
132 0
|
7月前
|
前端开发 网络协议 Java
Netty入门指南:从零开始的异步网络通信
Netty入门指南:从零开始的异步网络通信
191 0
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13531 1