网络40ms延迟问题

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

问题背景:
我 们一个企业用户准备把线上业务从共享的mysql服务迁移到独立型mysql rds上。企业用户那边先搞了一个test版本到我们rds环境,发现网站响应时间从3s变为40s。由于是php应用,故我们让用户应用开启  xhprof调试后,看一次请求有1200多次mysql查询,对mysql的查询量非常大,并且请求的时间90%以上都花在了mysql上。而用户使用 共享性mysql和使用rds的区别,是用户runtime到rds之间多了一个proxy服务,通过proxy服务把用户请求代理到了rds。

问题跟踪:
1,由于用户使用共享mysql和rds的区别,就是一个proxy服务。故就把问题定位在proxy这个服务上。
2,使用tcpdump在proxy机器(15.212)上抓runtime(21.102)到proxy,proxy到rds(144.139)的数据包,具体如下:

wKiom1b8kKHw5eZCAAKKET3TZf0213.png

proxy收到runtime发过来的查询数据包到proxy给runtime ack确认,花费了40ms,这个时间太长。并且,proxy把runtime发的查询数据包从一个截断为了2个数据包。  
1,id为22953:runtime102发送select语句到proxy 212。数据包长度为296byte 时间:23.877515
2,id为22954:proxy 212发送了一部分select语句128byte到rds 139。时间花销(秒):23.877611-23.877515=0.000096
3,id为22955:proxy 212回 runtime 103的ack这一步时间花销(秒):23.917294-23.877611=0.039683(这次时间花销过大,一千次请求就是39s
4,id为22956:rds 139回proxy  212的ack。这一步时间花销(秒):23.918398-23.917294=0.001104
5,id为22957:proxy 212发送剩余部分select语句168byte到rds  139。这一步时间花销(秒):23.918415-23.918398=0.000017

3,又在proxy机器上进行了strace跟踪,结果如下:

1
2
3
4
5
6
7
8
9
11:00:57.923865 epoll_wait(7, {{EPOLLIN, {u32=12025792, u64=12025792}}}, 1024, 500) = 1
11:00:57.923964 recvfrom(8,  "\237\0\0\0\3SELECT cat_id, cat_name, parent_id, is_show FROM `jiewang300`.`jw_category`WHERE parent_id = '628' AND is_show = 1 ORDER BY" , 128, 0, NULL, NULL) = 128
11:00:57.924041 recvfrom(8,  " sort_order ASC, cat_id ASC limit 8" , 128, 0, NULL, NULL) = 35
11:00:57.924102 recvfrom(8, 0xb7b0b3, 93, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
11:00:57.924214 epoll_wait(7, {{EPOLLOUT, {u32=12048160, u64=12048160}}}, 1024, 500) = 1
11:00:57.924340 sendto(9,  "\237\0\0\0\3SELECT cat_id, cat_name, parent_id, is_show FROM `jiewang300`.`jw_category`WHERE parent_id = '628' AND is_show = 1 ORDER BY" , 128, 0, NULL, 0) = 128
11:00:57.924487 sendto(9,  " sort_order ASC, cat_id ASC limit 8" , 35, 0, NULL, 0) = 35
11:00:57.924681 epoll_wait(7, {{EPOLLIN, {u32=12048160, u64=12048160}}}, 1024, 500) = 1
11:00:57.964162 recvfrom(9,  "\1\0\0\1\4B\0\0\2\3def\njiewang300\vjw_category\vjw_category\6cat_id\6cat_id\f?\0\5\0\0\0\2#B\0\0\0F\0\0\3\3def\njiewang300\vjw_category\vjw_category\10cat_name\10" , 128, 0, NULL, NULL) = 128

发现是proxy机器在write write read操作的时候,write write和read操作之间,epoll_wait了40ms才read到数据。

结论:
为什么延迟不高不低正好 40ms 呢?果断 Google 一下找到了答案。原来这是 TCP 协议中的 Nagle‘s Algorithm 和 TCP Delayed Acknoledgement 共同起作 用所造成的结果。
 
Nagle’s Algorithm 是为了提高带宽利用率设计的算法,其做法是合并小的TCP 包为一个,避免了过多的小报文的 TCP 头所浪费的带宽。如果开启了这个算法 (默认),则协议栈会累积数据直到以下两个条件之一满足的时候才真正发送出去:
1,积累的数据量到达最大的 TCP Segment Size
2,收到了一个 Ack
 
TCP Delayed Acknoledgement 也是为了类似的目的被设计出来的,它的作用就 是延迟 Ack 包的发送,使得协议栈有机会合并多个 Ack,提高网络性能。

如果一个 TCP 连接的一端启用了 Nagle‘s Algorithm,而另一端启用了 TCP Delayed Ack,而发送的数据包又比较小,则可能会出现这样的情况:发送端在等 待接收端对上一个packet 的 Ack 才发送当前的 packet,而接收端则正好延迟了 此 Ack 的发送,那么这个正要被发送的 packet 就会同样被延迟。当然 Delayed Ack 是有个超时机制的,而默认的超时正好就是 40ms。
 
现代的 TCP/IP 协议栈实现,默认几乎都启用了这两个功能,你可能会想,按我 上面的说法,当协议报文很小的时候,岂不每次都会触发这个延迟问题?事实不 是那样的。仅当协议的交互是发送端连续发送两个 packet,然后立刻 read 的 时候才会出现问题。
 
为什么只有 Write-Write-Read 时才会出问题,维基百科上的有一段伪代码来介绍 Nagle’s Algorithm:

1
2
3
4
5
6
7
8
9
10
11
if  there is  new  data to send
   if  the window size >= MSS and available data is >= MSS
     send complete MSS segment now
   else
     if  there is unconfirmed data still in the pipe
       enqueue data in the buffer until an acknowledge is received
     else
       send data immediately
     end  if
   end  if
end  if

可以看到,当待发送的数据比 MSS 小的时候(外层的 else 分支),还要再判断 时候还有未确认的数据。只有当管道里还有未确认数据的时候才会进入缓冲区, 等待 Ack。

所以发送端发送的第一个 write 是不会被缓冲起来,而是立刻发送的(进入内层 的else 分支),这时接收端收到对应的数据,但它还期待更多数据才进行处理, 所以不会往回发送数据,因此也没机会把 Ack 给带回去,根据Delayed Ack 机制, 这个 Ack 会被 Hold 住。这时发送端发送第二个包,而队列里还有未确认的数据 包,所以进入了内层 if 的 then 分支,这个 packet 会被缓冲起来。此时,发 送端在等待接收端的 Ack;接收端则在 Delay 这个 Ack,所以都在等待,直到接 收端 Deplayed Ack 超时(40ms),此 Ack 被发送回去,发送端缓冲的这个 packet 才会被真正送到接收端,从而继续下去。

再看我上面的 strace 记录也能发现端倪,因为设计的一些不足,我没能做到把 短小的 HTTP Body 连同 HTTP Headers 一起发送出去,而是分开成两次调用实 现的,之后进入 epoll_wait 等待下一个 Request 被发送过来(相当于阻塞模 型里直接 read)。正好是 write-write-read 的模式。

那么 write-read-write-read 会不会出问题呢?维基百科上的解释是不会:
    “The user-level solution is to avoid write-write-read sequences on sockets. write-read-write-read is fine. write-write-write is fine. But write-write-read is a killer. So, if you can, buffer up your little writes to TCP and send them all at once. Using the standard UNIX I/O package and flushing write before each read usually works.”
我的理解是这样的:因为第一个 write 不会被缓冲,会立刻到达接收端,如果是 write-read-write-read 模式,此时接收端应该已经得到所有需要的数据以进行 下一步处理。接收端此时处理完后发送结果,同时也就可以把上一个packet 的 Ack 可以和数据一起发送回去,不需要 delay,从而不会导致任何问题。


解决办法:
在proxy服务上开启 TCP_NODELAY选项,这个选项的作用就是禁用 Nagle’s Algorithm。


plus:

tcpdump和strace结果对比:

可以看到strace结果中是proxy机器先write write两次,然后等待大概40ms。而tcpdump看到的则是proxy机器先write了一次到rds,等待40ms收到rds的ack,再write了剩余的数据到rds。strace这个结果是正常的,因为strace只能看到的是系统调用,实际上第二次write被缓冲了(strace是看不到的),等待了40ms后rds的ack到来,这第二次write才被真正的发送出去。这样strace就和tcpdump的结果一致了。










本文转自 leejia1989 51CTO博客,原文链接:http://blog.51cto.com/leejia/1758560,如需转载请自行联系原作者
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
2月前
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
86 17
|
2月前
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。
|
2月前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们日常生活中不可或缺的一部分。本文将深入探讨网络安全漏洞、加密技术和安全意识等方面的问题,并提供一些实用的建议和解决方案。我们将通过分析网络攻击的常见形式,揭示网络安全的脆弱性,并介绍如何利用加密技术来保护数据。此外,我们还将强调提高个人和企业的安全意识的重要性,以应对日益复杂的网络威胁。无论你是普通用户还是IT专业人士,这篇文章都将为你提供有价值的见解和指导。
|
2月前
|
存储 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已经成为了我们生活中不可或缺的一部分。本文将介绍网络安全的基本概念,包括网络安全漏洞、加密技术以及如何提高个人和组织的安全意识。我们将通过一些实际案例来说明这些概念的重要性,并提供一些实用的建议来保护你的信息和数据。无论你是网络管理员还是普通用户,都可以从中获得有用的信息和技能。
37 0
|
2月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
63 10
|
2月前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为全球关注的焦点。本文将探讨网络安全漏洞、加密技术以及提升安全意识的重要性。通过深入浅出的解释和实际案例分析,我们将揭示网络攻击的常见手段,介绍加密技术如何保护数据安全,并强调个人和企业应如何提高安全防范意识。无论你是IT专业人士还是普通网民,这篇文章都将为你提供宝贵的信息和建议,帮助你在网络世界中更安全地航行。
|
2月前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:漏洞、加密与意识的艺术
在数字世界的迷宫中,网络安全和信息安全是守护者之剑。本文将揭示网络漏洞的面纱,探索加密技术的奥秘,并强调安全意识的重要性。通过深入浅出的方式,我们将一起走进这个充满挑战和机遇的领域,了解如何保护我们的数字身份不受威胁,以及如何在这个不断变化的环境中保持警惕和适应。
51 1
|
2月前
|
安全 算法 网络协议
网络安全与信息安全知识分享
本文深入探讨了网络安全漏洞、加密技术以及安全意识三个方面,旨在帮助读者更好地理解和应对网络安全威胁。通过分析常见的网络安全漏洞类型及其防范措施,详细介绍对称加密和非对称加密的原理和应用,并强调提高个人和企业安全意识的重要性,为构建更安全的网络环境提供指导。
70 2
|
2月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的内容,并提供一些实用的代码示例。通过阅读本文,您将了解到如何保护自己的网络安全,以及如何提高自己的信息安全意识。
72 10
|
2月前
|
存储 监控 安全
云计算与网络安全:云服务、网络安全、信息安全等技术领域的融合与挑战
本文将探讨云计算与网络安全之间的关系,以及它们在云服务、网络安全和信息安全等技术领域中的融合与挑战。我们将分析云计算的优势和风险,以及如何通过网络安全措施来保护数据和应用程序。我们还将讨论如何确保云服务的可用性和可靠性,以及如何处理网络攻击和数据泄露等问题。最后,我们将提供一些关于如何在云计算环境中实现网络安全的建议和最佳实践。

热门文章

最新文章