网络通信(网络保活)

转载:微信团队原创分享,Android版微信后台保活实战分享(网络保活篇)

哪些部分需要“保活”?


按照我们的理解包含两部分:
 

网络连接保活概述


网络保活,业界主要手段有:
 

  • a. GCM;
  • b. 公共的第三方push通道(信鸽等);
  • c. 自身跟服务器通过轮询,或者长连接。

国产机器大多缺乏GMS,在国内GCM也不稳定(心跳原因),第三方通道需要考虑安全问题和承载能力,最后微信选择使用自己的长连接。而国外, GCM作为辅助,微信无法建立长连接时,才使用GCM。

之前看到大家在聊各种Java网络框架,而微信实际上都是没用上的。早年的微信,直接通过Java socket 实现。微信v5.0后,考虑各系统平台的统一,开始使用自研c++组件。


长连接实现包括几个要素:
 

  • a. 网络切换或者初始化时 server ip 的获取。
  • b. 连接前的 ip筛选,出错后ip 的抛弃。
  • c. 维护长连接的心跳。
  • d. 服务器通过长连notify。
  • e. 选择使用长连通道的业务。
  • f. 断开后重连的策略。


我们重点讨论心跳和 notify 机制。

网络连接保活实施:心跳机制


心跳的目的很简单:通过定期的数据包,对抗NAT超时。以下是部分地区网络NAT 超时统计


上表说明:

  • a. GCM无法适应国内2G环境(GCM 28分钟心跳)。
  • b. 为了兼容国内网络要求,我们至少5分钟心跳一次。

老版本的微信是4.5分钟发送一次心跳,运行良好。


(有关GCM的研究详见移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)

心跳的实现:


 

  • a. 连接后主动到服务器Sync拉取一次数据,确保连接过程的新消息。
  • b. 心跳周期的Alarm 唤醒后,一般有几秒的cpu 时间,无需wakelock。
  • c. 心跳后的Alarm防止发送超时,如服务器正常回包,该Alarm 取消。
  • d. 如果服务器回包,系统通过网络唤醒,无需wakelock。


流程基于两个系统特性:
 

  • a. Alarm唤醒后,足够cpu时间发包。
  • b. 网络回包可唤醒机器。


特别是b项,假如Android封堵该特性,那就只能用GCM了。API level >= 23的doze就关闭所有的网络, alarm等。但进入doze条件苛刻,现在6.0普及低,至今微信没收到相关投诉。另Google也最终加入REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限。
(有关微信Android端心跳的具体技术实现详见微信对网络影响的技术试验及分析(论文全文)》、《移动端IM实践:实现Android版微信的智能心跳机制

网络连接保活实施:动态心跳


4.5min心跳周期是稳定可靠的,但无法确定是最大值。通过终端的尝试,可以获取到特定用户网络下,心跳的最大值。

引入该特性的背景:
 

  • a. 运营商的信令风暴
  • b. 运营商网络换代,NAT超时趋于增大
  • c. Alarm耗电,心跳耗流量。


动态心跳引入下列状态:
 

  • a. 前台活跃态:亮屏,微信在前台,  周期minHeart (4.5min) ,保证体验。
  • b. 后台活跃态:微信在后台10分钟内,周期minHeart ,保证体验。
  • c. 自适应计算态:步增心跳,尝试获取最大心跳周期(sucHeart)。
  • d. 后台稳定态:通过最大周期,保持稳定心跳。


自适应计算态流程:



在自适应态:
 

  • a. curHeart初始值为minHeart , 步增(heartStep)为1分钟。
  • b. curHeart 失败5次, 意味着整个自适应态最多只有5分钟无法接收消息。
  • c. 结束后,如果sucHeart > minHeart,会减去10s(避开临界),为该网络下的稳定周期。
  • d. 进入稳定态时,要求连接连续三次成功minHeart心跳周期,再使用sucHeart。


稳定态的退出:

sucHeart 会对应网络存储下来, 重启后正常使用。考虑到网络的不稳定,如NAT超时变小,用户地理位置变换。当发现sucHeart 连续5次失败, sucHeart 置为minHeart ,重新进入自适应态。

网络连接保活实施:notify机制


网络保活的意义在于消息实时。通过长连接,微信有下列机制保证消息的实时。
 

1Sync


通过Sync CGI直接请求后台数据。Sync 通过后台和终端的seq值对比,判断该下发哪些消息。终端正常处理消息后,seq更新为最新值。
 

2Sync 的主要场景

  • a. 长连无法建立时,通过Sync 定期轮询
  • b. 微信切到前台时,触发Sync(保命机制)
  • c. 长连建立完成,立即触发Sync,防止连接过程漏消息
  • d. 接收到Notify 或者 gcm 后,终端触发Sync 接收消息.

3Notify


类似于GCM。通过长连接,后台发出仅带seq的小包,终端根据seq决定是否触发Sync拉取消息。
 

4NotifyData


在长连稳定, Notify机制正常的情况下(保证seq的同步)。后台直接推送消息内容,节省1个RTT (Sync) 消息接收时间。终端收到内容后,带上seq回应NotifyAck,确认成功。这里会出现Notify和NotifyData状态互相切换的情况:

如NotifyData 后,服务器在没收到NotifyAck,而有新消息的情况下,会切换回到Notify,Sync可能需要冗余之前NotifyData的消息。终端要保证串行处理NotifyData和Sync ,否则seq可能回退。
 

5GCM


只要机器上有GMS ,启动时就尝试注册GCM,并通知后台。服务器会根据终端是否保持长连,决定是否由GCM通知。GCM主要针对国外比较复杂的网络环境。

QA环节


Q:在智能心跳自适应阶段,如果5次心跳失败是否会促发重连?因为5次心跳都失败的话连接是不是已经断开了?
A:这里可能刚才描述不够清晰,任何一次心跳失败后,必然就已经断开重连了,所以每次心跳失败,对应一次重连操作。

Q:在某些网络下,经常出现网络闪断的情况,这种情况下势必会引起频繁的socket重连,微信有没有遇到类似的情况?有没有什么优化的方法,求指教。
A:这种情况是有的,微信在前台时,我们会比较积极的更换ip重试,或者换短连ip。在后台时,如果出现频繁,会加上比较长的间隔。

Q:多端同时登录情况(手机,电脑同时登录),假如有一端网络情况不好,怎么保证收到消息一致性?
A:多终端登录消息一致的问题,是由后台保证的,实际原理也就是上面提到的seq。

Q:有没有遇到过有一些端口被运营商封了的情况?我们之前有一些用户就是死活连不上某个端口。
A:服务器给我们开的端口有好几个,比如80/8080/443等,而且允许服务器下发,所以实际上现在服务器会用哪些端口,终端这边都无需关注了。

Q:再问一个问题,服务端主动notify的话,时间间隔是如何选择的?因为这个关系到用户的流量消耗。
A:notifydata是实时的,只要你的状态允许,你的好友给你发消息的时候就会立即在服务器转换成notifydata给到你,所以这里的频率并不在于时间间隔,而在于你接收消息然后返回ack的间隔。流量消耗上,实际要比触发sync更少。

Q:这种保活机制会极大的增加app的耗电量,在可以通过GCM稳定唤醒app的场景下,是否可以停用后台保活,从而省电?
A:其实心跳机制真的不会带来多少耗电,一个心跳包发出和接收,实际的消耗远远低于您收发一条消息。心跳间隔时间微信实际不会使用任何cpu的。唤醒机制靠的是网络回包。GCM唤醒这种模式国外有app是这样做的,但还是因为国内GCM不靠谱,另外这种模式要比notify,notifydata都慢。

更多文章


微信对网络影响的技术试验及分析(论文全文)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)

(本文下篇《微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》,原文链接:点此进入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值