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
目录
相关文章
|
4天前
|
缓存 网络协议 算法
Netty的基础入门(上)
Netty的基础入门(上)
15 0
|
2月前
|
Java API 容器
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf
78 0
|
2月前
|
缓存 网络协议 算法
《跟闪电侠学Netty》阅读笔记 - Netty入门程序解析
《跟闪电侠学Netty》阅读笔记 - Netty入门程序解析
133 0
|
2月前
|
Java Unix Linux
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
当涉及到网络通信和高性能的Java应用程序时,Netty是一个强大的框架。它提供了许多功能和组件,其中之一是JNI传输。JNI传输是Netty的一个特性,它为特定平台提供了高效的网络传输。 在本文中,我们将深入探讨Netty提供的特定平台的JNI传输功能,分析其优势和适用场景。我们将介绍每个特定平台的JNI传输,并讨论其性能、可靠性和可扩展性。通过了解这些特定平台的JNI传输,您将能够更好地选择和配置适合您应用程序需求的网络传输方式,以实现最佳的性能和可靠性。
51 7
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
|
19天前
|
NoSQL Redis
Netty实战:模拟Redis的客户端
Netty实战:模拟Redis的客户端
11 0
|
2月前
|
消息中间件 缓存 Java
《跟闪电侠学Netty》阅读笔记 - 开篇入门Netty
《跟闪电侠学Netty》阅读笔记 - 开篇入门Netty
86 0
|
3月前
|
分布式计算 前端开发 网络协议
13W字!腾讯高工手写“Netty速成手册”,3天能走向实战
在java界,netty无疑是开发网络应用的拿手菜。你不需要太多关注复杂的nio模型和底层网络的细节,使用其丰富的接口,可以很容易的实现复杂的通讯功能。
|
3月前
|
监控 网络协议 调度
Netty Review - 深入探讨Netty的心跳检测机制:原理、实战、IdleStateHandler源码分析
Netty Review - 深入探讨Netty的心跳检测机制:原理、实战、IdleStateHandler源码分析
100 0
|
4月前
|
网络协议 Java 容器
《跟闪电侠学Netty》阅读笔记 - ChannelHandler 生命周期
《跟闪电侠学Netty》阅读笔记 - ChannelHandler 生命周期
40 0
《跟闪电侠学Netty》阅读笔记 - ChannelHandler 生命周期
|
4月前
|
Java API
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf(二)
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf
30 0