skywind3000 / kcp

:zap: KCP - A Fast and Reliable ARQ Protocol

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

关于上行卡顿,下行包流畅的问题

Haoson opened this issue · comments

你好,我是一名游戏开发者。我使用了kcp作为游戏客户端和服务器通信的方式。并且游戏已经成功上线。目前我遇到一个问题我没有思路,特来请教。
现象:极少数玩家反馈在进入游戏副本中看不到敌方,无法释放技能,但是能够看到世界聊天在滚动。
初步分析:通过远程联调,日志分析,我利用游戏中的ping-pong包,其机制是客户端一秒发送一次ping,并且会记录发送时间,服务器收到包之后,回一个pong,并且回传ping包时间+pong包处理时间。通过这个ping-pong包发现,客户端大概70秒之内只有ping包日志,然后70多秒之后,pong包一股脑的回来了。这些回来的pong包记录了ping包到达服务器的时间都已经是70秒左右。
所以我的初步结论是上行包卡顿了,但是这段时间的下行包是流畅的,这也导致检测游戏卡顿踢玩家下线重连机制是没有生效的。

但是为什么上行包卡顿,不知道,我又做了以下事情:

  1. 玩家自述,他在同样的手机上,同样的网络(移动流量)下,使用另一个账号是没问题的。
  2. 难道是账号问题,挣得玩家同意之后,我在本地登陆了玩家账号,去玩同样的副本,一次没有出现(玩家高概率出现)

到这一步,我就不知道下一步如何排查,我有几个猜测:
1、有没有可能是我kcp客户端处理得不对?导致某些情况没发送?我客户端服务器使用同一套代码,每一个连接都是一个kcp instance, 10毫秒一个tick去Poll,参数:nodelay = 1,interval = 10,resend = 0,nc = 1,sndwnd = 128,rcvwnd = 256
2、有没有可能是玩家运营商网络或者路由器之类的策略导致上行包被丢掉或者降权发送?有这种可能吗,上行能卡1分钟多,但是玩家小号又没问题
3、有无可能是客户端某种情况积压数据发送不完?但是账号在我本地又复现不了
感谢阅读,不知有无更好的思路或者排查方法

会不会是你发的数据量太大了,造成堆积了?超过了当前 KCP 的发送能力?

检查下:ikcp_waitsnd

会不会是你发的数据量太大了,造成堆积了?超过了当前 KCP 的发送能力?

检查下:ikcp_waitsnd

好的,感谢。这个主要是复现很麻烦,我准备加更多接口在上层,方便时候可以打印到日志或者调整

我记得用netty时有遇到过客户端读缓冲区满,导致服务器写入拥堵的问题

@Haoson 看这里: https://github.com/skywind3000/kcp/wiki/Flow-Control-for-Users
感谢感谢,其实这些机制我基本都实现了,甚至issuse所有问题都之前都看过一遍。
我在底层做了一个可配置的、根据当前ikcp_waitsnd数量,超过水位线就踢连接的功能,不过我当时只在网关层实现了,没有在客户端实现,因为游戏本身是上行数量很小,不太可能很大,不过你这么说是提醒了我,客户端是不是也需要做一个类似机制?

@skywind3000 这个问题后来没法复现,但是这几天复现了一次,我还抓到了更详细的数据,异常时候,nsnd_buf,nsnd_que分别是1和0,但是cwnd成了1
异常数据(三组):
snd_una,snd_nxt,rcv_nxt=2049 2049 8296, rx_rttval,rx_srtt,rx_rto,rx_minrto,ssthresh=4539 22863 41019 30 128,snd_wnd,rcv_wnd,rmt_wnd,cwnd,incr,probe=256 512 512 82 112832 0, current,interval,ts_flush,xmit=582677661 10 582677671 426, nrcv_buf,nrcv_que,nsnd_buf,nsnd_que=0 0 0 0, nodelay,updated=1 1, ts_probe,probe_wait=0 0,dead_link,ackcount,ackblock=20 0 256, fastresend,fastlimit,nocwnd=0 5 1.

snd_una,snd_nxt,rcv_nxt=2055 2056 8376, rx_rttval,rx_srtt,rx_rto,rx_minrto,ssthresh=7976 27524 59428 30 128, snd_wnd,rcv_wnd,rmt_wnd,cwnd,incr,probe=256 512 512 2 2752 0, current,interval,ts_flush,xmit=583925375 10 583925385 429, nrcv_buf,nrcv_que,nsnd_buf,nsnd_que=0 0 1 0, nodelay,updated=1 1, ts_probe,probe_wait=0 0, dead_link,ackcount,ackblock=20 0 256, fastresend,fastlimit,nocwnd=0 5 1.

snd_una,snd_nxt,rcv_nxt=2056 2069 8398, rx_rttval,rx_srtt,rx_rto,rx_minrto,ssthresh=28568 54067 60000 30 128, snd_wnd,rcv_wnd,rmt_wnd,cwnd,incr,probe=256 512 512 1 1376 0, current,interval,ts_flush,xmit=584708218 10 584708228 437, nrcv_buf,nrcv_que,nsnd_buf,nsnd_que=0 0 1 0, nodelay,updated=1 1, ts_probe,probe_wait=0 0, dead_link,ackcount,ackblock=20 0 256, fastresend,fastlimit,nocwnd=0 5 1.

看数据,下行包还是好的,只是上行窗口成了1,发不出去,我再研究下为啥cwnd为啥会是1

调用 nodelay 打开最后一个参数。