netstat 某连接的 Recv-Q(接收队列)达到500多万字节的内核参数排查


思路:

  1. cat proc文件系统下的 sys/net 目录下所有文件,根据结果降序排序(如果打印前xx,可能会漏掉关键信息,在定位问题时需要注意,慎用过滤),根据结果使用 grep -rn xxx 找到配置文件
  2. 查看配置文件含义,资料网站:https://www.kernel.org/doc/html/latest/networking/ip-sysctl.html
  3. 对结论进行测试

步骤一,进入 /proc/sys/net 目录,执行命令: find . -type f | xargs cat {} ; | sort -nr | head -20 ; 根据结果寻找配置文件

# 测试机器
[root@api net]# find . -type f | xargs cat {} /; | sort -nr | less
cat: {}: No such file or directory
cat: ;: No such file or directory
cat: ./ipv4/route/flush: Permission denied
cat: ./ipv6/conf/all/stable_secret: Input/output error
cat: ./ipv6/conf/default/stable_secret: Input/output error
cat: ./ipv6/conf/enp4s0/stable_secret: Input/output error
cat: ./ipv6/conf/lo/stable_secret: Input/output error
cat: ./ipv6/route/flush: Permission denied
2147483647
4194304
4194304
3145728
3145728
...
4096    87380   6291456
4096    16384   4194304
...

[root@api net]# grep -rn 6291456
grep: ipv4/route/flush: Permission denied
ipv4/tcp_rmem:1:4096	87380	6291456

步骤二:确认配置含义

# 网页搜索 tcp_rmem,得到两处结果
# 根据解释,linux 系统默认就是接收缓冲区自动调整,不大于tcp_rmem

tcp_moderate_rcvbuf - BOOLEAN
If set, TCP performs receive buffer auto-tuning, attempting to automatically size the buffer (no greater than tcp_rmem[2]) to match the size required by the path for full throughput. Enabled by default.
 # 如果设置,TCP将执行接收缓冲区自动调整,尝试自动调整缓冲区大小(不大于tcp_rmem[2]),以匹配路径所需的大小以实现全吞吐量。默认情况下启用。

tcp_rmem - vector of 3 INTEGERs: min, default, max
min: Minimal size of receive buffer used by TCP sockets. It is guaranteed to each TCP socket, even under moderate memory pressure.

Default: 4K

default: initial size of receive buffer used by TCP sockets. This value overrides net.core.rmem_default used by other protocols. Default: 131072 bytes. This value results in initial window of 65535.

max: maximal size of receive buffer allowed for automatically selected receiver buffers for TCP socket. This value does not override net.core.rmem_max. Calling setsockopt() with SO_RCVBUF disables automatic tuning of that socket’s receive buffer size, in which case this value is ignored. Default: between 131072 and 6MB, depending on RAM size.
# TCP套接字自动选择的接收器缓冲区允许的最大接收缓冲区大小。该值不会覆盖net.core.rmem_max。使用SO_RCVBUF调用setsockopt()将禁用该套接字接收缓冲区大小的自动调整,在这种情况下,该值将被忽略。默认值:介于131072和6MB之间,具体取决于RAM大小。

步骤三:验证
使用client 和 server 端代码

[root@api ~]# cat client.py
# coding: utf-8
import socket

print ('我是客户端!')

HOST = 'localhost'    # 服务器的ip
PORT = 60008              # 需要连接的服务器的端口
BUFSIZ = 10240000
ADDR = (HOST,PORT)

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(ADDR)


while 1:
    data=input("请输入:/n >>>")
    if not data:
        break
    c.sendall(data.encode())  # 发送‘Hello,world’给服务器
#    data = c.recv(BUFSIZ).decode()
#    if not data:
#        break
#    print ('接收到', repr(data))  # 打印从服务器接收回来的数据
c.close()

[root@api ~]# cat server.py
# coding: utf-8
#  服务器端代码
from socket import *
import time

print ('我是服务端!')

HOST = ''                 
PORT = 60008
BUFSIZ = 10240000
ADDR = (HOST,PORT) # 创建端口,规定缓冲区大小


s = socket(AF_INET, SOCK_STREAM)  # 创建TCP socket对象
s.bind(ADDR)  # 绑定地址
s.listen(4)  # 监听TCP,4代表:操作系统可以挂起(未处理请求时等待状态)的最大连接数量。该值至少为1

while 1:
   print("等待连接...")
   client, addr = s.accept()  # 开始被动接受TCP客户端的连接。
   print ('连接的地址', addr)

   while 1:
        time.sleep(10)
#   while 1:
#       data = client.recv(BUFSIZ).decode()  # 接受TCP数据 decode是由于此处接受bytes而不是 str类型
#       print("接收到数据:",data)
#       if not data: break
       
#       client.send(data.encode())  # 把从客户端接收来的数据完整的,发送给客户端
#   client.close()  
s.close()

通过手动修改服务端的相关配置,得到如下结果:

测试的结果,net.core.rmem_max = 1024 net.ipv4.tcp_rmem = 2000 4000 6000 最大的写队列是2936
测试的结果,net.core.rmem_max = 1024 net.ipv4.tcp_rmem = 1000 4000 6000 最大的写队列是2936
测试的结果,net.core.rmem_max = 1024 net.ipv4.tcp_rmem = 1000 4000 8000 最大的写队列是4136
测试的结果,net.core.rmem_max = 1024 net.ipv4.tcp_rmem = 1000 6000 8000 最大的写队列是4136

结论:linux 系统的TCP连接的接收缓冲区大小会自动调整,不大于tcp_rmem。(具体调整的算法未知)

原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/277212.html

(0)
上一篇 2022年7月27日
下一篇 2022年7月27日

相关推荐

发表回复

登录后才能评论