一、知识准备

● 在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

客户端 : 192.168.17.171

服务端 : 192.168.17.173

三、打开nagle算法

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

  1. root@k8s-node2:/tmp# more nginx.conf
  2. user nginx;
  3. worker_processes 1;
  4. error_log /var/log/nginx/error.log warn;
  5. pid /var/run/nginx.pid;
  6. events {
  7. worker_connections 1024;
  8. }
  9. http {
  10. include /etc/nginx/mime.types;
  11. default_type application/octet-stream;
  12. log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  13. '$status $body_bytes_sent "$http_referer" '
  14. '"$http_user_agent" "$http_x_forwarded_for"';
  15. access_log /var/log/nginx/access.log main;
  16. sendfile on;
  17. tcp_nodelay off;
  18. keepalive_timeout 65;
  19. include /etc/nginx/conf.d/*.conf;
  20. }

启动容器

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

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

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

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

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

  1. root@k8s-node2:~# ab -n 1000 -c 100 -k http://127.0.0.1/
  2. This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
  3. Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
  4. Licensed to The Apache Software Foundation, http://www.apache.org/
  5. ...
  6. Time per request: 44.619 [ms] (mean)
  7. ...

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

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

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

选取一个片段来分析

● 在Linux中,默认打开了延迟确认,所谓延迟确认,即不是收到每个请求都发送一次ack,而是等待一段时间,如果这段时间正好有包需要发送,就坐着“顺风车”一起发出,否则超时后单独发送。所以客户端会等待40ms,再发送这个ack

● 由于nginx也设置了nagle算法,如果没有收到ack,它会等着包的到来,所以就会呈现这个样子

    (1)192.168.17.171首先发送一个http get请求(677号包)

    (2)192.167.17.173发送PSH,ACK(999号包)

    (3)此时由于Linux默认打开延迟确认,192.168.17.171会等待40ms,看看有没有“顺风车”;而192.168.17.173上的nginx由于关闭了tcp_nodelay,它也会等待着ack的到来再回应

    (4)40ms过后,192.168.17.171没有等到“顺风车”,此时发送ack(1109号包)

    (5)192.168.17.173收到ack后发送了http 200(1118号包)

    (6)192.168.17.171收到数据之后发送确认ack(1127号包)

  1. 192.168.17.171:47388 192.168.17.173:80
  2. +-------+ +--------+
  3. | | no.677 http get | |
  4. | +---------------------------------> |
  5. | | | |
  6. | | no.999 PSH,ACK | |
  7. | <---------------------------------+ |
  8. | | | |
  9. | | | |
  10. | | | |
  11. | | delay 40ms | |
  12. | | | |
  13. | | | |
  14. | | | |
  15. | | no.1109 ACK | |
  16. | +---------------------------------> |
  17. | | | |
  18. | | no.1118 http 200 | |
  19. | <---------------------------------+ |
  20. | | | |
  21. | | no.1127 ACK | |
  22. | +---------------------------------> |
  23. | | | |
  24. | | | |
  25. +-------+ +--------+

四、关闭nagle

只需要设置tcp_nodelay on;

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

再用ab测试:

  1. root@k8s-node2:~# ab -n 1000 -c 100 -k http://127.0.0.1/
  2. This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
  3. Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
  4. Licensed to The Apache Software Foundation, http://www.apache.org/
  5. ...
  6. Time per request: 14.285 [ms] (mean)
  7. ...

再来观察抓包的结果:

● 由于客户端依然打开了延迟确认,所以192.168.17.171收到数据包之后依然没有及时回应

● 但是nginx,tcp_nodelay on,所以192.168.17.173收到数据包后会立即响应ack

● 192.168.17.171收到之后,已经有2个没有确认的数据包了,所以会立即发送ack进行确认:

    (1)192.168.17.171首先发送一个http get请求(447号包)

    (2)192.168.17.173收到之后立即响应psh,ack(740号包)

    (3)192.168.17.173发送http 200(741号包)

    (4)192.168.17.171回应ack(742号包)

  1. 192.168.17.171:49718 192.168.17.173:80
  2. +-------+ +--------+
  3. | | no.447 http get | |
  4. | +---------------------------------> |
  5. | | | |
  6. | | no.740 PSH,ACK | |
  7. | <---------------------------------+ |
  8. | | | |
  9. | | no.741 http 200 | |
  10. | <---------------------------------+ |
  11. | | | |
  12. | | no.742 ACK | |
  13. | +---------------------------------> |
  14. | | | |
  15. | | | |
  16. +-------+ +--------+

五、小结

● 本文复现了经典的40ms问题

● 本文中提到了2个名词,nagle算法与延迟确认,它们看上去很相似,但是并不一样。nagle算法是需要等到对端ack来临,或者凑满一个mss之后才发送数据包;而延迟确认针对的是ack,ack会等待“顺风车”,如果有,就乘坐顺风车发送,否则等待超时之后单独发送

● 本文中延迟确认是Linux默认打开的功能,所以在实验中,客户端都会有延时确认的情况,要关闭客户端延迟确认,需要设置setsockopt中的TCP_QUICKACK

● 本文中主要讨论的是nginx的nagle算法,nagle算法完全由tcp协议的ack机制决定,如果对端ACK回复很快的话,nagle事实上不会拼接太多的数据包,虽然避免了网络拥塞,网络总体的利用率依然很低

● nagle算法在与延迟确认互相作用的情况下,会产生严重的延时效果,这是需要警惕的

● nginx中是否打开nagle算法,要取决于业务场景。比如在实验中看到:

    (1)tcp_nodelay off,会增加通信的延时,但是会提高带宽利用率。在高延时、数据量大的通信场景中应该会有不错的效果

    (2)tcp_nodelay on,会增加小包的数量,但是可以提高响应速度。在及时性高的通信场景中应该会有不错的效果


至此,本文结束

在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

仔细看参数--NGINX之tcp_nodelay的更多相关文章

  1. 防盗链Nginx设置图片防盗链,设置无效的请仔细看红字

    *******************************************************************切记,替换的图片地址要使用没有防盗链的网站图片,否则由于替换的图片 ...

  2. 写给Web开发人员看的Nginx介绍

    译者注:不知道其他开发者是否和我一样,参与或者写了很多Web项目,但是却没有真正的去完整的部署应用,很多时候都是交给ops即运维的同学帮忙来做.而作为一个有节操的开发者,我认为了解一些服务器方面的知识 ...

  3. Delphi Dll 动态调用例子(3)-仔细看一下

    http://blog.163.com/bxf_0011/blog/static/35420330200952075114318/ Delphi 动态链接库的动态和静态调用 为了让人能快速的理解 静态 ...

  4. 取得cxgrid的表格的值,仔细看下面的代码

    procedure TfrmMain.cxGridDBTableView_List_PSSJCustomDrawCell(Sender: TcxCustomGridTableView; ACanvas ...

  5. UniGui之锱铢积累(仔细看这个文件)

    http://www.doc88.com/p-4022977294324.html 这个是Word文档

  6. (转)nginx应用总结(1)--基础认识和应用参数优化配置

    在linux系统下使用nginx作为web应用服务,用来提升网站访问速度的经验已五年多了,今天在此对nginx的使用做一简单总结. 一.nginx服务简介Nginx是一个高性能的HTTP和反向代理服务 ...

  7. 根据参数优化nginx的服务性能

    一.优化nginx服务的worker进程数 在高并发.高访问量的Web服务场景,需要事先启动好更多的nginx进程,以保证快速响应并处理大量并发用户的请求. 1).优化nginx进程对应的配置 优化n ...

  8. 用OpenStack界面轻松创建虚拟机的你,看得懂虚拟机启动的这24个参数么?

    看这篇文章之前,保证看过以下文章: 我是虚拟机内核我困惑?! Qemu,KVM,Virsh傻傻的分不清 裸用KVM创建虚拟机,体验virtualbox为你做的10件事情 大家从OpenStack页面上 ...

  9. nginx参数优化

    大家好,分享即关爱,我们很乐意和你分享一些新的知识,我们准备了一个 Nginx 的教程,分为三个系列,如果你对 Nginx 有所耳闻,或者想增进 Nginx 方面的经验和理解,那么恭喜你来对地方了. ...

随机推荐

  1. 正确使用Java读写锁

    JDK8中引入了高性能的读写锁StampedLock,它的核心思想在于,在读的时候如果发生了写,应该通过重试的方式来获取新的值,而不应该阻塞写操作.这种模式也就是典型的无锁编程思想,和CAS自旋的思想 ...

  2. Luogu4294 【WC2008】游览计划

    斯坦纳树(我也不知道为什么叫这个名字)是一种状压dp的套路,求在无向带花连通图中,选取边使一些特殊点连通起来的最小花费. 具体到这题就是这样的,设\(f_{u,S}\)表示当前根是\(u\),与它连通 ...

  3. realloc()函数

    原型:extern void *realloc(void *mem_address, unsigned int newsize); 参数: mem_address: 要改变内存大小的指针名 newsi ...

  4. 模板 - 数学 - 数论 - 扩展Euler定理

    费马(Fermat)小定理 当 \(p\) 为质数,则 \(a^{p-1}\equiv 1 \mod p\) 反之,费马小定理的逆定理不成立,这样的数叫做伪质数,最小的伪质数是341. 欧拉(Eule ...

  5. Leetcode42. 接雨水

    42. 接雨水 做法 考虑单独一列能生产多少贡献:用左右最大值去接这列的水 \(O(n)\) Code class Solution { public: int mx[1000000],rx[1000 ...

  6. Linux 修改时区的办法

    Linux修改时区的正确方法 CentOS和Ubuntu的时区文件是/etc/localtime,但是在CentOS7以后localtime以及变成了一个链接文件 [root@centos7 ~]# ...

  7. 7、vueJs基础知识07

    UI组件库 element-ui和mint-ui 其实都是借鉴了bootstrap bootstrap: 由twitter 开源 简洁.大方 官网文档https://www.bootcss.com/ ...

  8. 【Vue.js游戏机实战】- Vue.js实现大转盘抽奖总结

    大家好!先上图看看本次案例的整体效果. 实现思路: Vue component实现大转盘组件,可以嵌套到任意要使用的页面. css3 transform控制大转盘抽奖过程的动画效果. 抽奖组件内使用钩 ...

  9. fmex挂单挖矿

    最近fmex上线挂单挖矿,针对挂单写了个程序,"跟随盘口,避免成交",0成本薅羊毛. 代码在 https://github.com/xiaoxiaoleo/fmexminer 使用 ...

  10. 【转】Python编程: 多个PDF文件合并以及网页上自动下载PDF文件

    1. 多个PDF文件合并1.1 需求描述有时候,我们下载了多个PDF文件, 但希望能把它们合并成一个PDF文件.例如:你下载的数个PDF文件资料或者电子发票,你可以使用python程序合并成一个PDF ...