千家信息网

listen函数中backlog字段的作用是什么

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,listen函数中backlog字段的作用是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。通过不断的调整client的个数,我发
千家信息网最后更新 2025年02月02日listen函数中backlog字段的作用是什么

listen函数中backlog字段的作用是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

通过不断的调整client的个数,我发现性能并没有明显随着client的数量降低而降低,而是在client个数到达某个值时突然降低的。

比如我自己测的数据是在491个client时,silly的性能与redis相差无几,但在492个client同时并发时,silly的性能锐降到redis 30%左右。

这也再次说明了应该不是malloc和memcpy造成的开销。

在此期间,我分别尝试加大epoll的缓冲区和增大socket预读缓冲区,都没有明显的效果。这也说明问题并不在IO的读取速度上和系统调用开销上。

万般无奈之下Download下来redis3.0的源码开始对着比,最终发现惟一不一样的地方就是redis的listen的backlog竟然是511,而我的只有5.

一下子豁然开朗了,由于backlog队列过小,导致所有的connect必须要串行执行,大部的时间都在等待建立连接上,在将backlog的值改为511后,性能已然直逼redis。

google了一下发现,除了redis连nginx竟然也是用511。但是记忆中backlog参数会影响未完成连请求队列的大小,似乎增加backlog会增加syn洪水攻击的风险。

查了好一会资料,最后发现man上早都指出在Linux 2.2之后listen中的backlog参数仅用于指定等待被accept的已完的socket队列的长度。未完成连接的队列长度则通过/proc/sys/net/ipv4/tcp_max_syn_backlog来指定。

至于为什么backlog是511而不是512, 是因为kernel中会对backlog做roundup_power_of_tow(backlog+1)处理,这里使用511实际上就是为了不浪费太多不必要的空间。

之前一直看资料上说backlog是个经验值,需要根据经验调节。然而并没有想到,当大批量连接涌入时,backlog参数会起到这个大的影响。那么这个经验看来就是要估算每秒的连接建立个数了。

比如web服务器由于http的特性,需要频繁建立断开链接,因此同一时刻必然会涌入大量连接,因此可能需要更高一些的backlog值,但是对于游戏服务器来讲,大多都是长连接,除了刚开服时会有大量连接涌入,大部分情况下连接的建立并不如web服务器那么频繁。当然即使如此依然需要对每秒有多少链接同时进入进行估算,来衡量backlog的大小。

虽然可以不用估算直接使用backlog的最大值,但却可能会造成'已完成未被Accept的socket的队列'过长,当accept出队列后面的连接时,其已经被远端关闭了。

经过测试,即使backlog为63,在局域网内同时并发2000客户端并无性能影响。


12月23日纠下补充:


1. listen的backlog值其实是会精确指定accept的队列的,只不过它除了控制accept队列的大小,实际上还会影响未完成的connect的队列的大小,因此
roundup_power_of_tow(backlog+1)增大的实际是未完成connect队列的大小。


2. /proc/sys/net/ipv4/tcp_max_syn_backlog 虽然字段名中有一个sync但其实限制的是accept队列的大小,而并非是未完成connect队列的大小

虽不欲写成kernel net源码解析的文件(实际上是怕误人子弟:D), 但还是走一下流程证明一下吧(只针对tcp和ipv4基于3.19)。

先看listen的整个流程:

listen系统调用 其实是通过sock->ops->listen(sock, backlog)来完成的。

那么sock->ops->listen函数是咋来的呢,再来看socket系统调用, 其实是通过socket_create间接调用__sock_create来完成的。

sock->ops->listen函数则是通过__socket_create函数中调用pf->create来完成的。而pf其实是通过inet_init函数调用socket_register注册进去的,至于什么时间调用了inet_init这里就不赘述了,毕竟这不是一篇kernel分析的文章:D.

由此我们找到pf->create实际上调用的就是inet_create函数.

啊哈!接着我们终于通过inetsw_array找到sock->ops->listen函数最终其实就是inet_listen函数。可以看到我们通过listen传入的backlog在经过限大最大值之后,直接被赋给了sk_max_ack_backlog字段。

OK,再来看一下kernel收到一个sync包之后是怎么做的。

好吧,先去看icsk->icsk_af_ops->conn_request这个函数是怎么来的。

回过头来看inetsw_array发现其中SOCK_STREAM中类型的prot字段其实是指向tcp_prot结构体的。

在前面看过的的inet_create函数中的最后部分会调用sk->sk_prot->init函数。而sk_prot字段其实是通过调用sk_alloc时将inetsw_array中的prof字段赋值过去的。

因此在inet_create函数的最后sk->sk_prot->init调用的实际上是tcp_v4_init_sock函数。而在tcp_v4_init_sock函数中会将icsk->icsk_af_ops的值赋值为ipv4_specific的地址。

由此终于找到了icsk->icsk_af_ops->conn_request其实就是tcp_v4_conn_request函数,此函数随即调用tcp_conn_request函数来完成之后的内容。

在tcp_conn_request中是通过sk_acceptq_is_full来判断的。


从sk_acceptq_is_full函数中看到他是通过sk_max_ack_backlog字段判断的,而这个字段在我们分析listen系统调用时已然看到其实就是listen传入的那个值。

另外需要额外说明的时,在reqsk_queue_alloc中为的listen_sock::syn_table分配的空间仅仅是一个hash表,并不是际的request_sock空间。

关于listen函数中backlog字段的作用是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

函数 队列 字段 大小 就是 实际 实际上 性能 系统 问题 影响 个数 参数 同时 服务器 空间 经验 分析 服务 作用 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 民政信息网络安全应急预案 请使用检查数据库功能 公共解析服务器2022 国际软件开发大会 生活中网络安全问题和对策 网络安全的核心什么安全 北京美圈时代网络技术 数据库怎么查找删除的文件 服务器xshell远程连接 合作企业网络安全责任追责制度 阿里云服务器上的数据如何恢复 日月精灵宝可梦我的世界服务器 网络安全七一讲话感想和心得体会 手机上应用服务器错误 德州服务器运维管理系统电话 互联网公司为何不进军高科技 山西网络服务器虚拟主机 波兰设置网络安全中心 网络安全竞答试题 2021年网络安全新闻 软件开发项目明细单 数据库应用系统的特点 章鱼联盟网络技术服务有限公司 网络安全区域划分建设 电子购物网站数据库ER图 金融网络安全宣传 软件开发师需要学习什么 服务器软件文件管理 软件开发类项目风险 永州景睿网络技术服务有限公司
0