`
nanjingjiangbiao_T
  • 浏览: 2593154 次
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

临时优化了一下可靠UDP程序

 
阅读更多


之前做的一个简单的可靠UDP传输,基本的可靠是实现了,但没做动态的流控。当时为了简单,也为了快速实现。当然 运算简单服务器也能撑起更多用户,比如一个服务端单线程进程可能撑起上万的用户连接。几个数据量小的业务,跑了几个月并没发现什么明显问题。


后来迁移一个业务过去,灰度测试,客户端获取一份数据的速度很慢,比原来使用TCP的慢多了。对比之后发现用来使用TCP传的时候,这份业务数据有做压缩,迁移到可靠UDP后没做压缩,没压缩很多一百多K,两百多K的包。所以就发客户端版本,把压缩做上。压缩上线之后,整体上是大幅改善了,很多包压缩之后就几十K或更小。但有些大的包压缩后还有150K,用户网络很好 可能有时都差不多一秒内完成,但大多数情况 或者 中等用户网络环境,对这种大包区别就很多,旧方式走TCP链路,很多3秒内或三四秒左右就完成;而走可靠UDP链路,很多十多秒的。这种差的情况还是差得一塌糊涂,不可接受...


当时是12月中,12月最后2个星期我是请假的,机票也买好了。没办法,问题在那里,业务也赶着上,原划是希望Q4就能上线稳定的。所以虽然休了假,还是跑到公司去加班了,希望在离开之前将其优化到可以接受。而且因为赶着用,也只能从服务端但方面优化。如果对整体的协议都做调整,那发布客户端可能就要等上一两个月才能大面积用上。


分析了若干客户端和服务端详细的debug log(log收集不易,有的log是其他同事在家里,e家宽或不太好的ADSL网络下收集的),发现服务端除了受到Nack之后的少数包的重传之外,成批的重传都是长时间的重传timer超时后的重传,受到客户端ack之后并没有重传。客户端本来定时ack就比较慢,比较慢的ack服务端收到之后这个反馈没用上,那重传肯定迟缓了。所以第一个优化就是收到ack之后,将滑动窗口向前滑动,未被ack确认的包立即重传。这第一个优化做上去之后,差的网络环境下是提高了几秒。


从log中也发现,每一次下发数据的时候,都一次性把滑动窗口允许范围内的包一次性下发,但客户端收到几十个包之后,后面的都丢掉了。假设一次性猛发500个UDP包,一个包500字节的话,也发了500*500Byte = 250K左右的数据,乘以8换算成带宽 相当于 2Mbps的带宽。很多用户的网络根本达不到2Mbps,很多平时512Kbps的宽带都多人共用,所以瞬间下几十个或接近百个,超过用户端带宽的,会被电信局的网络设备丢掉了。所以自然想到第二个优化,服务端发数据的时候,有节奏的发,每次发100个(或50个)就停下,等下次定时程序调到再继续发。如此不会超过普通用户的带宽,丢包少了,效率自然高了。做了这个之后,速度又提高了几秒。(当然,理想的改进方式是,客户端和服务器都做修改,协议上做调整,把ack做得敏捷一点,然后只通过滑动窗口控制发送的速率..不过目前因为改客户端不可行,在协议不做改造的情况下,服务端单方面只能这么做了)


程序还有个缺点,虽然控制了发送的节奏,但两次发送间隔了1秒,时间间隔还是太长了。历史原因,进程的代码做的timer粒度是秒。分析代码几番思量之后,觉得还是可能通过不太大的改动让timer精细一些的,当然最怕的是改动之后其他模块多个类的timer都错掉了... 这部分timer实现的基本原理是,每一个循环,读取一下当前时间,以秒为单位记下,和上次比,如果不同则说明过了一秒了,那就执行timer检查程序,超时的调用一下各类的timer执行函数。


把精度提升一点是可以做到的,只要读取和记录时间用毫秒,当然还是不能精确到1毫秒,因为一次程序循环,你还调用epoll_wait()可能就等待用掉了几十毫秒,所以用这种方式实现的timer精度不可能少于epoll_wait()的超时时间(程序设的大概是几十毫秒超时)。所以最后我把精度控制到100毫秒。并且timer初始化新加接口,设置超时时间以毫秒为单位,旧的以秒为单位的接口保留。这样除了可靠UDP程序之外,其他模块代码可以不用动(当然它们的时间也只精细到1秒)。最方便地做了兼容,也大大减少出错的可能。


这几个地方的优化上了之后,业务的统计显示传输效率和之前使用TCP链路的很接近了。大多数情况两者3秒内都能获取到该业务的数据,差距也就零点几个百分点。我也安心的休假去。


-------------------------------------------------------------------------------------------------

更多博文请订阅RSS,更多微博请关注@千里孤行Nerd


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics