go语言http长连接的简单介绍( 四 )


针对不同网络环境 , 或者客户端本身消息的活跃程度,心跳要自适应的进行调整并与服务端协商,来保证链路的连通性 。并且在弱网络环境下 , 除了网络切换(wifi切3G)或者读写出错情况 , 什么时候重新建立链路也是一个问题 。客户端发出的ping包,不同网络下,多久没有得到响应 , 认为网络出现问题,重新建立链路需要有个权衡 。另外对于不同网络环境下,读取不同的消息长度,也要有不同的容忍时间 , 不能一刀切 。好的心跳和读写超时设置,可以让客户端最快的检测到网络问题,重新建立链路,同时在网络抖动情况下也能完成大数据传输 。
结合服务端做策略
另外系统可能结合服务端做一些特殊的策略 , 比如我们在选路时候,我们会将同一个用户尽量映射到同一个room service实例上 。断线时,客户端尽量对上次连接成功的地址进行重试 。主要是方便服务端做闪断情况下策略,会暂存用户闪断时实例上的信息 , 重新连入的 时候,做单实例内的迁移,减少延时与加载开销.
客户端保活策略
很多创业公司愿意重新搭建一套push系统,确实不难实现 , 其实在协议完备情况下(最简单就是客户端不回ack不清数据) , 服务端会保证消息是不丢的 。但问题是为什么在消息有效期内,到达率上不去?往往因为自己app的push service存活能力不高 。选用云平台或者大厂的,往往sdk会做一些保活策略 , 比如和其他app共生,互相唤醒,这也是云平台的push service更有保障原因 。我相信很多云平台旗下的sdk,多个使用同样sdk的app , 为了实现服务存活,是可以互相唤醒和保证活跃的 。另外现在push sdk本身是单连接,多app复用的 , 这为sdk实现,增加了新的挑战 。
综上,对我来说,选择推送平台,优先会考虑客户端sdk的完善程度 。对于服务端,选择条件稍微简单,要求部署接入点(IDC)越要多 , 配合精细的选路策略,效果越有保证,至于想知道哪些云服务有多少点,这个群里来自各地的小伙伴们,可以合伙测测 。
go语言开发问题与解决方案
下面讲下,go开发过程中遇到挑战和优化策略,给大家看下当年的一张图,在第一版优化方案上线前一天截图~
可以看到,内存最高占用69G , GC时间单实例最高时候高达3~6s.这种情况下,试想一次悲剧的请求,经过了几个正在执行gc的组件,后果必然是超时... gc照成的接入方重试,又加重了系统的负担 。遇到这种情况当时整个系统最差情况每隔2 , 3天就需要重启一次~
当时出现问题,现在总结起来,大概以下几点
1.散落在协程里的I/O,Buffer和对象不复用 。
当时(12年)由于对go的gc效率理解有限,比较奔放,程序里大量short live的协程,对内通信的很多io操作,由于不想阻塞主循环逻辑或者需要及时响应的逻辑,通过单独go协程来实现异步 。这回会gc带来很多负担 。
针对这个问题,应尽量控制协程创建,对于长连接这种应用,本身已经有几百万并发协程情况下,很多情况没必要在各个并发协程内部做异步io , 因为程序的并行度是有限,理论上做协程内做阻塞操作是没问题 。
如果有些需要异步执行,比如如果不异步执行 , 影响对用户心跳或者等待response无法响应,最好通过一个任务池,和一组常驻协程,来消耗,处理结果 , 通过channel再传回调用方 。使用任务池还有额外的好处,可以对请求进行打包处理,提高吞吐量,并且可以加入控量策略.

推荐阅读