网络40ms延迟问题

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
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,如需转载请自行联系原作者
相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
分布式计算 监控 网络协议
Hadoop集群长时间运行网络延迟原因
【6月更文挑战第20天】
433 2
|
2月前
|
人工智能 监控 数据可视化
如何破解AI推理延迟难题:构建敏捷多云算力网络
本文探讨了AI企业在突破算力瓶颈后,如何构建高效、稳定的网络架构以支撑AI产品化落地。文章分析了典型AI IT架构的四个层次——流量接入层、调度决策层、推理服务层和训练算力层,并深入解析了AI架构对网络提出的三大核心挑战:跨云互联、逻辑隔离与业务识别、网络可视化与QoS控制。最终提出了一站式网络解决方案,助力AI企业实现多云调度、业务融合承载与精细化流量管理,推动AI服务高效、稳定交付。
|
11月前
|
域名解析 缓存 网络协议
优化Lua-cURL:减少网络请求延迟的实用方法
优化Lua-cURL:减少网络请求延迟的实用方法
|
网络协议 数据挖掘 5G
适用于金融和交易应用的低延迟网络:技术、架构与应用
适用于金融和交易应用的低延迟网络:技术、架构与应用
578 5
|
存储 网络协议 容灾
降低存储网络55% 延迟!阿里云存储论文入选计算机顶会
凭借在规模化部署和应用模型上的创新,阿里云存储团队发表的技术论文《Deploying User-space TCP at Cloud Scale with LUNA》被 USENIX ATC'23 收录。
1657 4
降低存储网络55% 延迟!阿里云存储论文入选计算机顶会
|
存储 网络协议 数据中心
|
缓存 负载均衡 监控
中间件网络延迟
中间件网络延迟
171 2
|
存储 网络协议 网络性能优化
网络传输延迟
网络传输延迟
601 1

热门文章

最新文章