网络繁忙时延迟极高,TCP,libevent
Extremely high latency when network gets busy, TCP, libevent
在我们基于C/S的网络游戏项目中,我们使用TCP进行网络传输。我们包括 Libevent,为每个连接使用一个 bufferevent 来自动处理网络 I/O。
之前很好用,最近卡顿的问题浮出水面。当我做一些压力测试以使网络更繁忙时,延迟变得非常高,几秒或更长时间。服务器陷入混乱状态:
- 平均 CPU 使用率下降(0%-60%-0%-60% 重复,还在等什么?)
- 净流量减少(nethogs)
- 连接到服务器的客户端仍然存在(netstat 和 tcpdump)
看起来好像有什么东西神奇地减慢了所有系统的速度,但与服务器的新连接响应及时退出。
当我将协议改为UDP时,同样的情况下效果很好:没有明显的延迟,系统运行速度很快。净流量在3M/S左右。
项目 运行 位于 Intranet 上。我也测试了最大下载速度,接近18M/S
我研究了部分 Libevent 的头文件和文档,尝试对所有连接设置速率限制。它做了一些改进,但即使我尝试了几种不同的配置,也没有完全解决问题。这是我的参数:read_rate 163840,read_burst 163840,write_rate 163840,write_burst 163840,tick_len 500ms。
感谢您的帮助!
TCP = 传输控制协议。它通过在延迟后重新传输未确认的数据包来响应数据包丢失。在重复丢失的情况下,它会呈指数级回退。查看此网络捕获尝试打开与未响应的主机的连接:
它发送初始 SYN,然后在 1 秒内未收到确认后再次尝试。在没有收到 ack 后,它会在 ~2s 后发送另一个,然后是 ~4s,然后是 ~8s,依此类推。所以你可以看到,面对重复的数据包丢失,你会得到一些严重的延迟。
既然你说你故意给网络施加压力,而且 CPU 用法不一致,一种可能的解释是 TCP 正在等待重传丢失的数据包。
查看正在发生的事情的最佳方法是获取实际传输内容的网络捕获。如果您的主机连接到单个交换机,您可以将感兴趣的端口“跨越”到可以进行捕获的另一台主机的端口。
如果您的交换机无法执行此操作,或者如果您没有交换机的管理控制权,那么您将不得不从在线游戏中涉及的主机之一获取捕获。这样做的缺点是进行捕获可能会改变发生的事情,并且它看不到线路上的实际情况。例如,您可能为您的接口启用了 TCP 分段卸载,在这种情况下,捕获将看到将被网络接口分解的大数据包。
我建议安装 wireshark 来分析网络捕获(您也可以使用 wireshark 进行实时捕获)。每当您使用联网系统时,我都建议您使用 wireshark,以便您对网络上实际发生的事情有一定的了解。我建议您使用的第一个过滤器是 tcp.analysis.flags
,它将向您显示提示问题的数据包。
我还建议先关闭速率限制以尝试查看发生了什么(速率限制正在添加 另一个 不发送数据包的原因,这可能会使诊断正在发生的事情变得更加困难)。此外,500 毫秒可能有点长 tick_len
,具体取决于您的游戏运行方式。如果您的突发配置允许速率在 100 毫秒内用完,您最终将等待 400 毫秒才能再次传输。在这方面,IO Graph 是 Wireshark 的一个非常有用的功能。它可以帮助您查看传输速率,尽管默认的滴答间隔和单位在这方面不是很有帮助。以下是速率限制为 200mbit/s 的突发流示例:
请注意,tick 间隔为 1ms,单位为 bits/tick,这使得图表顶部为 1gb/s,即有问题的接口速度。
在我们基于C/S的网络游戏项目中,我们使用TCP进行网络传输。我们包括 Libevent,为每个连接使用一个 bufferevent 来自动处理网络 I/O。
之前很好用,最近卡顿的问题浮出水面。当我做一些压力测试以使网络更繁忙时,延迟变得非常高,几秒或更长时间。服务器陷入混乱状态:
- 平均 CPU 使用率下降(0%-60%-0%-60% 重复,还在等什么?)
- 净流量减少(nethogs)
- 连接到服务器的客户端仍然存在(netstat 和 tcpdump)
看起来好像有什么东西神奇地减慢了所有系统的速度,但与服务器的新连接响应及时退出。
当我将协议改为UDP时,同样的情况下效果很好:没有明显的延迟,系统运行速度很快。净流量在3M/S左右。
项目 运行 位于 Intranet 上。我也测试了最大下载速度,接近18M/S
我研究了部分 Libevent 的头文件和文档,尝试对所有连接设置速率限制。它做了一些改进,但即使我尝试了几种不同的配置,也没有完全解决问题。这是我的参数:read_rate 163840,read_burst 163840,write_rate 163840,write_burst 163840,tick_len 500ms。
感谢您的帮助!
TCP = 传输控制协议。它通过在延迟后重新传输未确认的数据包来响应数据包丢失。在重复丢失的情况下,它会呈指数级回退。查看此网络捕获尝试打开与未响应的主机的连接:
它发送初始 SYN,然后在 1 秒内未收到确认后再次尝试。在没有收到 ack 后,它会在 ~2s 后发送另一个,然后是 ~4s,然后是 ~8s,依此类推。所以你可以看到,面对重复的数据包丢失,你会得到一些严重的延迟。
既然你说你故意给网络施加压力,而且 CPU 用法不一致,一种可能的解释是 TCP 正在等待重传丢失的数据包。
查看正在发生的事情的最佳方法是获取实际传输内容的网络捕获。如果您的主机连接到单个交换机,您可以将感兴趣的端口“跨越”到可以进行捕获的另一台主机的端口。
如果您的交换机无法执行此操作,或者如果您没有交换机的管理控制权,那么您将不得不从在线游戏中涉及的主机之一获取捕获。这样做的缺点是进行捕获可能会改变发生的事情,并且它看不到线路上的实际情况。例如,您可能为您的接口启用了 TCP 分段卸载,在这种情况下,捕获将看到将被网络接口分解的大数据包。
我建议安装 wireshark 来分析网络捕获(您也可以使用 wireshark 进行实时捕获)。每当您使用联网系统时,我都建议您使用 wireshark,以便您对网络上实际发生的事情有一定的了解。我建议您使用的第一个过滤器是 tcp.analysis.flags
,它将向您显示提示问题的数据包。
我还建议先关闭速率限制以尝试查看发生了什么(速率限制正在添加 另一个 不发送数据包的原因,这可能会使诊断正在发生的事情变得更加困难)。此外,500 毫秒可能有点长 tick_len
,具体取决于您的游戏运行方式。如果您的突发配置允许速率在 100 毫秒内用完,您最终将等待 400 毫秒才能再次传输。在这方面,IO Graph 是 Wireshark 的一个非常有用的功能。它可以帮助您查看传输速率,尽管默认的滴答间隔和单位在这方面不是很有帮助。以下是速率限制为 200mbit/s 的突发流示例:
请注意,tick 间隔为 1ms,单位为 bits/tick,这使得图表顶部为 1gb/s,即有问题的接口速度。