nginx优化之nagle算法tcp_nodelay需要设置的参数

2023年 7月 11日 33.4k 0

一、知识准备

● 在nginx优化中有个经常需要设置的参数,tcp_nodelay ● 该参数最核心的功能,就是把小包组成成大包,提高带宽利用率也就是著名的nagle算法 ● tcp协议中,有一个现象:应用层数据可能很低(比如1个字节),而传输层开销有40字节(20字节的IP头+20字节的TCP头)。这种情况下大部分都是控制包的传输,既加大了带宽的消耗,带宽利用率也不高 ● nagle算法就是为了解决这个问题。在发出去的数据还未被确认之前,或者说还没有收到对端的ack之前,新生成的小包是不允许被发送的,必须要凑满一个MSS或者等到收到确认后再发送,直至超时

二、环境准备

OS Ubuntu 18.04.1 LTS
docker 18.06.0-ce

客户端 : 服务端 :

三、打开nagle算法

,先准备一个nginx配置文件,并且打开nagle算法,设置tcp_nodelay off;

root@k8s-node2:/tmp# more nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nodelay off;

    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
}

启动容器

root@k8s-node2:/tmp# docker run -d --name nginx_delay -v /tmp/nginx.conf:/etc/nginx/nginx.conf -p 80:80 nginx:latest
6b7d5a5d3c3ed021fed6847d138837754c5732979d1c829ec62107ec80440db8
root@k8s-node2:/tmp# docker ps | grep nginx_delay
6b7d5a5d3c3e        nginx:latest                                                        "nginx -g 'daemon of…"   7 seconds ago       Up 6 seconds        0.0.0.0:80->80/tcp   nginx_delay

首先使用tcpdump抓取本机的80端口的流量:

root@k8s-node2:/tmp# tcpdump -i ens3 port 80 -afexnnvv -w nginx_ab.cap

在,使用ab压测工具对该端口进行放量

注意:必须使用 -k 参数,使用keepalived模式下才能模拟出nagle算法

root@k8s-node2:~# ab -n 1000 -c 100 -k http://127.0.0.1/
This is ApacheBench, Version 2.3 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

...
Time per request:       44.619 [ms] (mean)
...

过滤掉大量信息,我们来到这个指标Time per request,无论怎么测试,平均延时总是在40ms左右

我们来看下抓包信息,使用wireshark打开

在大量的数据包中,我们先处理一下数据包,随便选取一个syn,选取与该syn对应的tcp流

nginx优化之nagle算法tcp_nodelay需要设置的参数

选取一个片段来分析

nginx优化之nagle算法tcp_nodelay需要设置的参数

● 在Linux中,默认打开了延迟确认,所谓延迟确认,就是不是收到每个请求都发送一次ack,而是等待一段时间,如果这段时间正好有包需要发送,就坐着“顺风车”一起发出,否则超时后单独发送。所以客户端会等待40ms,再发送这个ack ● 由于nginx也设置了nagle算法,如果没有收到ack,它会等着包的到来,所以就会呈现这个样子 (1)首先发送一个http get请求(677号包) (2)发送PSH,ACK(999号包) (3)此时由于Linux默认打开延迟确认,会等待40ms,看看有没有“顺风车”;而上的nginx由于关闭了tcp_nodelay,它也会等待着ack的到来再回应 (4)40ms过后,没有等到“顺风车”,此时发送ack(1109号包) (5)收到ack后发送了http 200(1118号包) (6)收到数据之后发送确认ack(1127号包)

:47388                        :80
     +-------+                                 +--------+
     |       |       no.677  http get          |        |
     |       +--------------------------------->        |
     |       |                                 |        |
     |       |       no.999  PSH,ACK           |        |
     |               |
     |       |                                 |        |
     |       |       no.1118  http 200         |        |
     |               |
     |       |                                 |        |
     |       |                                 |        |
     +-------+                                 +--------+

四、关闭nagle

只需要设置tcp_nodelay on;

root@k8s-node2:/tmp# sed -i '/tcp_nodelay/s/off/on/g' nginx.conf
root@k8s-node2:/tmp# docker rm -f nginx_delay
nginx_delay
root@k8s-node2:/tmp# docker run -d --name nginx_delay -v /tmp/nginx.conf:/etc/nginx/nginx.conf -p 80:80 nginx:latest
bac9bcf7a6e392a7a07afae165c3d5b4e3fb2fc43d3470f35802e12d1e7ae70d

再用ab测试:

root@k8s-node2:~# ab -n 1000 -c 100 -k http://127.0.0.1/
This is ApacheBench, Version 2.3 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

...
Time per request:       14.285 [ms] (mean)
...

再来观察抓包的结果:

nginx优化之nagle算法tcp_nodelay需要设置的参数

● 由于客户端依然打开了延迟确认,所以收到数据包之后依然没有及时回应 ● 但是nginx,tcp_nodelay on,所以收到数据包后会立即响应ack ● 收到之后,已经有2个没有确认的数据包了,所以会立即发送ack进行确认: (1)首先发送一个http get请求(447号包) (2)收到之后立即响应psh,ack(740号包) (3)发送http 200(741号包) (4)回应ack(742号包)

:49718                        :80
+-------+ +--------+
| | no.447 http get | |
| +---------------------------------> |
| | | |
| | no.740 PSH,ACK | |
|

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论