Netty源码分析(一) backlog 参数

 2023-01-14
原文作者:宁轩 原文地址:https://juejin.cn/post/7172450784041762830

前言

身为标准的 Java菜鸟, Netty 肯定是不熟悉的了, 本来就有计划去专门的学习, 但是碍于游戏的魅力, 草草开始草草结束, 借着本次活动, 开始进行一下相关的学习吧

关于 Netty, 我之前写过专门的文章对其进行了简单的介绍和应用: Netty之初识 - 掘金 (juejin.cn)

在本文章中, 主要分为找 bug 阶段和源码分析阶段, bug是 学习专用idea 的原因.....

看不到源码就很迷

关于本次的源码阅读活动, 差不多可以说是饭喂到嘴边了, 找到一个放自己 project 的地方, 使用 git 输入以下命令把代码拉下来就就可以了

    git clone https://github.com/arthur-zhang/netty-study.git

代码拉下来之后可以看到, 文件结构非常简单, 都是一些配置相关的, 具体是什么, 等我研究明白之后在安排一下....

202212302136344651.png

根据任务提示, 我们直接去 ServerSocketChannelImpl 类去打断点

202212302136354002.png

双击 Shift 输入 ServerSocketChannelImpl , 稍等一会然后进入了这个类

202212302136362243.png

就很迷, 完全没有按照我们以往的规律去显示 java 源码, 之后我怀疑了是 jdk 的原因 , 重新导入也不行, 那么基本可以确定是 idea 的原因了, 我用的 idea 是下面这个版本, 不知道有没有一样的

202212302136369224.png

这个 个人学习版的idea 之前就存在插件市场看不到插件的情况, 这次就直接给卸载掉了, 重新在 idea 官方进行了下载, 这次的学习过程来自于二哥的分享 Java程序员进阶之路

但是这个也很迷, 我是 22.12.1 安装的, 到期时间显示是 23.1.24, 可能是什么回退版本吧

202212302136374285.png

事实也证明确实是 idea 引起的问题, 这次能够正常查看源码了

202212302136380396.png

细心的同学会发现我这个 bind() 方法内部的参数都是 var1 ~ 5, 这个据 宁在春 大佬的文章Netty 源码共读(一) 所说, 我因为我们下载的 jdk 中本身是没有这部分源码的, 这个我也不太懂, 变量名改变也没有影响到我, 所以就无视掉了, 细致的小伙伴们可以去根据大佬的文章去进行修改

源码分析

根据任务说明, 我们在 bind() 方法的第一行 synchronized(this.lock) 打个断点, 然后以 Debug 方式启动 MyServer

202212302136388907.png

在这个过程中, 我们看我们的堆栈, var2 就是 backlog, 这个值一共变换了3次, 值分别是: 50511

202212302136397308.png

通过调用 堆栈信息, 我们可以看到这个 50 是在源码中写死的, 具体原因我们后续分析

202212302136403729.png

接下来狂按 F9 进行跳过, 我帮你们看过了, 除了最后一次都是写死的, 在抵达最后一次的时候会有一下卡顿, 注意别直接 F9 过去了, 可以看到, 这个时候 var2 变成了 511, 我们接着看堆栈信息

2022123021364105810.png

先点到上一个调用的地方可以看到, 我们的 var2 的值是通过参数 config 传进来的, 他是一个固定的值: 511, 同时我们可以看到 localAddress 是设置的端口, 所以可以证明我们的 backlog 是在设置端口的时候进行设置的

我猜的, 不对的话评论区提醒, 我改....

2022123021364184011.png

开篇咱就说过, MyServer 就是对 Netty 进行配置的类, 511 也有些熟悉, 果不其然, 看我发现了什么

2022123021364279212.png

backlog 到底是什么

【Netty】Netty 核心组件 一文中有说: ChannelOption option 参数是设置的操作类型 , T value 参数设置参数值 ; 如 bootstrap.option(ChannelOption.SO_BACKLOG, 128) 就是设置线程队列维护的连接个数 ;

2022123021364353113.png

但是在Java NIO ServerSocketChannel backlog原理、源码解读与默认值一文中, 又说 backlog影响的accept队列大小, 客户端把数据放到accept队列,JVM再从accept队列取。如果accept队列太小,JVM取数据不够快,那么accept队列就会溢出.....

我暂时迷得很, 后续我会对 Netty 进行系统性的学习, 网上的博客内容丰富的同时可能也会有一些不明了的地方, 这个时候书籍的作用性真的就体现出来了

结论

虽然最后也不知道 backlog 是指的什么, 这次算是烂尾了, 但是希望这两天能够修改本篇文章, 更改正确, 毕竟今天周五了

22.12.5更新

不好意思, 鸽了两天

我们从另外一个角度考虑一下, backlog 的配置是通过 ServerBootstrap.option()方法来进行配置的

2022123021364408414.png

那么, NioChannelOption.SO_BACKLOG 参数的作用是什么?

ChannelOption.SO_BACKLOG 对应的是tcp/ip协议listen函数中的 backlog 参数。函数listen(int socketfd, int backlog)用来初始化服务端可连接队列。

服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接,多个客户端来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小。

那么继续结合之前的 两个答案 , 是不是就通顺了, backlog 确实是设置了线程队列的连接个数, 同时, 如果这个队列个数设置的太小的话, JVM取数据的速度不够快, 那么这个队列就会溢出, over

本文内容到此结束了

如有收获欢迎点赞?收藏?关注✔️,您的鼓励是我最大的动力。

如有错误❌疑问?欢迎各位大佬指出。

我是 宁轩 , 我们下次再见