记一次服务器大并发下高延迟问题的定位

最近一段时间,项目增加了小游戏平台的支持,而小游戏的网络要求是 websocket,因此服务器也对 websocket 网络进行了支持。

最近,开始压测新的架构,发现了一个很有意思的问题:

  1. 当并发较少时,如100人同时在线,一切正常
  2. 当并发增大,比如增加到1500人,客户端的延迟显著增加,甚至将正常玩的玩家踢下线。

实际感受下来,客户端的延迟能达到1.5s左右,基本不可玩。

于是开始定位这个并发造成的延迟问题。

在现有的架构中,消息流转的方向如下:

client → LB → server → LB → client

整个流程涉及三方:客户端client、负责负载均衡的LB、以及服务器server本身。

这三方都可能会有问题,于是我设计了几个 case 来依次排除:

1)第一个可能就是客户端问题,比如客户端队列调度延迟或者其他bug。排除的方法就是用压测机器人和真实客户端来对比,如果压测机器人也有较高的延迟,那就可以排除client问题。测试下来,机器人统计的延迟也是很高,90%的耗时为900多ms,因此排除客户端client问题。

2)第二个可能是LB问题,有时候如果LB限制了带宽,也可能造成较高的延迟。排除的方法是将LB替换成其他不走LB的形式,在我们K8S服务器集群中是将LB换成 NodePort 的形式供客户端链接。测试下来,换成 NodePort 方式连接后,延迟依然还在,因此排除LB问题。

3)最后一种可能就是服务器server本身的问题。但是之前非小游戏的情况下,压测是正常的,因此我的怀疑点就落到websocket 网络层实现上,当然,还有一个可能是服务器的业务逻辑层的处理比较耗时。

先来看看是否是逻辑层处理比较耗时。

这个比较简单,就是在逻辑处理的入口和出口处增加时间统计。结果是逻辑处理非常快,基本是毫秒级别的耗时,因此排除了逻辑层的问题。

那最后的怀疑点就落到了网络层上。为了证实自己的猜想,我将压测机器人还原为 tcp 网络,发现延迟显著下降到正常水平(10ms以内),于是根据逻辑推理,问题出在 websocket 服务上。

现在的网络层 loop 是这样的流程:

c++ 复制代码
while (IsRunning())
{
    // 处理 websocket 网络IO
    _ProcWebSocket();
    
    // 处理TCP网络IO (内部TCP通信)
    _ProcTcpEpoll();
    
    // 处理逻辑层过来的消息(消息队列)
    _ProcNetQueue()
}

根据以往的经验,很可能是调度循环 loop 里处理消息发送的流程积压的比较多,也就是 _ProcWebSocket 调度时间不足导致的。

查看代码,发现是调用的是 RunOnce, 它的实现也比较简单:

arduino 复制代码
void CWSServer::RunOnce()
{
    m_endpoint.poll_one();
}

翻看 websocket 库文档后,发现除了 poll_one 之外还有个 poll,他们的区别就是一次处理多少 websocket 的IO 事件:

很明显,一次循环调度一次 poll_one 造成了底层IO 的挤压,我调试时候发现,并发超过1500人之后,poll_one 调用10次都不够。

最终的修改方案也比较简单,使用 poll 来尽量多的调度触发的事件,有多少调用多少,类似 epoll(获取有多少个事件,然后依次处理):

arduino 复制代码
void CWSServer::RunOnce()
{
    // Start the Asio io_service run loop
    // 非阻塞调用,会一次处理多个事件
    m_endpoint.poll();
}

修改完毕之后,大并发下,延迟下降到10ms,基本满足需求。

更进一步:这次问题的定位还是比较耗时的,如果引入一下消息追踪的工具,能较快的定位到延迟出在哪个环节; 另外,如果能增加一些消息延迟的监控或者统计,能更快发现问题。

相关推荐
爱勇宝4 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒9 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码10 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo10 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志10 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..11 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects11 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰11 小时前
一些基础和问题解决
后端
陈随易11 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN11 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp