Android 架构之长链接技术

《亿级Android架构》小专栏文章列表:html

《亿级 Android 架构》专栏随谈》前端

《Android 架构之网络链接与加速》java

《Android 架构之长链接技术》android

《Android 架构之高可用移动网络链接》git

《Android 架构之网络安全演进》github

《Android 架构之高性能移动端日志系统》golang

《Android 架构之秒级移动配置中心》算法

正文

上一篇文章《Android 架构之网络框架(上)》中,咱们谈过了网络框架OkHttp、网络加速方案如HttpDNS、数据压缩与序列化等技术点。本文咱们结合腾讯Mars框架美团Shark体系等业内主流长链接方案,谈一谈长链接技术的各个方面。后端

本文会包括下面的技术点:安全

  • 长链接与Http短链接、Keep-Alive傻傻分不清
  • 你为何须要长链接
  • 长链接什么时候会断开
  • 如何创建稳定长链接
  • Mars智能心跳机制
  • 长链接数据协议及加密
  • 长链接通道建设及容灾

除了你们经常使用的Http短链接,大型App几乎都会搭建一套完整的TCP长链接网络通道。咱们先来看下美团Shark长链接的线上数据:

图片来源 《美团点评移动网络优化实践

上面两张图片对比了长/短链接的成功率和网络延时数据,这两个是网络模块最重要的衡量指标。能够看出,不管是成功率,仍是网络延时,长链接都明显优于短链接。

另外,你们都知道微信的消息收发很是即时,这便归功于背后稳定高可用的长链接系统。实际上,微信除了消息收发,其余的小数据通讯都是经过长链接来实现的。

下面咱们来说解一些长链接的一些核心技术点。

I. 长链接与Http短链接、Keep-Alive傻傻分不清

为防止你们对于长链接和短链接混淆,这里先简单说明下几点区别。

长链接 vs Http短链接

这二者分别对应的是TCP协议层长链接短链接

你们都知道,TCP会经过三次握手,创建与服务端的链接,而后传递数据,只不过短链接在数据传输完后,会主动关闭链接,而长链接会继续保持这条链接,后续的数据读写继续使用这条链接。

长链接 vs Http的Keep-Alive

上一篇文章中提到了链接复用,经过Http1.1的Keep Alive字段,咱们可让一条Http链接保持不被当即关闭。有些同窗这时就疑惑了,是否是长链接就是Keep Alive呢?

其实不是的。长链接咱们也叫TCP长链接,它是架设在TCP协议上的,而上面说的Keep Alive是Http协议的内容,连协议都不一样,二者天然不是一个东西。

开启了Keep Alive是Http链接,咱们也称之为持久链接,和长链接并不一样。感兴趣可参考此文:《TCP 进阶》

TCP的Keep-Alive vs Http的Keep-Alive

提到Keep Alive,有些同窗就会问了,TCP协议里也有一个Keep Alive,它和Http协议里的Keep Alive有什么区别吗?

两者的用处并不一样。Http协议在完成一个请求后,服务器会自动关闭链接。这时,能够在请求里带上一个Keep Alive给服务器,告诉服务器不要当即关闭链接,我还想继续复用这条链接;而对TCP协议层而言,是不会自动断开的,但这也带来了一个问题,万一因为某些外部缘由致使链接断开,那我如何知道链接已失效呢?TCP会在2个小时间隔后,自动发送一个Keep Alive数据包给服务端,探测一下服务器是否还在响应。它的功能相似心跳包,只是间隔太长,不适合作真正的心跳包。

II. 你为何须要长链接

那么,相比Http短链接,长链接技术能带来什么好处呢?

1. 不一样域名的请求能够复用同一个长链接通道

之前咱们不一样域名的请求,须要作对应的DNS请求,而后创建对应的Http链接。上篇文章里说的Http链接池在不一样域名下不可复用,须要从新创建链接。这些都是一些资源开销,可是若是经过长链接通道,那域名只是这个请求里的一个字段,能够直接复用同一条长链接通道。

2. 不依赖DNS,无DNS耗时和劫持等问题

上文中咱们提到了HttpDNS,虽然它比系统DNS更优,但终归仍是要作DNS操做。而长链接都是IP直接链接,所以没有DNS相关的开销和耗时。

3. 若是有大量网络请求,能够明显减小网络延时,节省带宽

对于大型App而言,存在繁多密集的网络请求,这中间就会存在很是屡次的Http断开和从新链接,浪费了不少时间和带宽。而经过长链接通道的话,则没有这部分耗时,直接传输二进制数据便可,节省了每次链接里Header之类的带宽开销。

4. 服务端主动Push数据到客户端

对于上面提到的微信消息接收等场景,若是须要客户端主动去轮询,则会频繁发起请求,对于服务器会产生很大的负载压力,浪费带宽流量。而经过长链接,服务端能够主动把消息下发给客户端,作到最高实时性,且节省流量。

III. 长链接什么时候会断开?

正常而言,长链接是不会断开的。你们能够本身试一试,两个socket创建链接,只要网络不变、一切正常,那么这两个socket能够一直互相传送数据,不会断开。

可是,在移动网络下,网络状态复杂多变,好比网络线路被切断、服务器宕机等,都会致使长链接中断。除了这些线路异常外,咱们须要关注下面几个长链接断开缘由:

1. 长链接所在进程被杀

这个很容易理解,若是咱们的App切换到后台,那么系统随时可能将咱们的App杀掉,这时长链接天然也就随之断开。

2. 用户切换网络

好比手机网络断开,或者发生Wi-Fi和蜂窝数据切换,这时会致使手机IP地址变动。而咱们知道,TCP链接是基于IP + Port的,一旦IP变动,TCP链接天然也就失效了,或者说长链接也就至关于断开了。

3. 系统休眠等致使NAT超时

这里对NAT简单解释下,方便有的同窗不太了解。当手机链接上网络时,网关会给咱们分配一个IP地址,这个实际上是内网IP,此时还未真正链接上公网,也链接不上服务器;若是想要链接公网,须要运营商将咱们的内网IP映射成一个公网IP,有了公网IP,服务器就能与咱们创建链接了。NAT指的就是这个映射过程。

也就是说,运营商会给每台设备分配一个公网IP,相似一张通讯证。不过,随着链接网络的设备不断增多,网关负载也会不断加大,这时,运营商就会对一些不太活跃的设备进行公网IP回收了,若是下次这个设备须要连网,那就从新分配一个IP便可。

看似没问题,但实际上,若是咱们的App在一段时间不活跃,发生了NAT超时,便会致使咱们的公网IP失效,长链接也随之失效了。

4. DHCP 租期

DHCP 租期过时,若是没有及时续约,一样会致使IP地址失效。

综合而言,长链接在正常状况下是不会断开的,可是,一旦手机的IP地址失效,这时就不得不从新创建链接了。

IV. 如何创建稳定长链接?

上面咱们提到了多种长链接断开的缘由,那咱们应该如何进行优化,尽量保证长链接不断开,或者及时断开了,也要尽快重连呢?

1. Mars长链接独立进程

为了减小进程被杀的概率,在Mars的Demo代码里咱们能够看到,它将长链接逻辑单独提取到了一个独立的进程里。这个进程只作网络交互,消耗的内存等资源天然较少,从而减小了被系统回收的几率。

图片来自《Android版微信后台保活实战分享(进程保活篇)》

2. 长链接进程复活

进程被杀难以免,不过能够经过AlarmReceiver、 ConnectReceiver、BootReceiver,达到进程的及时唤醒。

固然,进程保活是一个比较大的话题,并且不恰当的进程保活也会对系统体验形成危害。这里就不深究了。

3. 心跳机制

对于心跳包不少人误觉得只是用来按期告诉服务端咱们的状态,实际并不是如此。

上面咱们提到了 NAT 超时,即若是App一段时间内不活跃,会致使运营商那里删除咱们的公网IP映射关系,这会致使咱们的TCP长链接断开。所以,咱们须要经过心跳机制来保证App的活跃度,防止发生 NAT 超时。

4. 断开重连

在线上运行时,长链接颇有可能会因为网络切换之类的缘由断开。这时,咱们须要尽快发现长链接断开,并当即重连。通常有下面几种作法:

  • 建立Receiver,监控网络状态,若是网络发生切换则当即重连;
  • 监控服务端心跳包回包,若是连续5次没有收到回包,则认为长链接已经失效;
  • 设置心跳包超时限制,若是超过期间尚未收到心跳回包,则重连,这种方式比较耗电;
  • 等socket IO异常抛出,不过耗时太长,须要15s左右才能发现。

V. Mars智能心跳机制

1. 固定心跳机制

上面咱们说了,心跳机制主要是为了防止 NAT 超时,外网IP地址失效。所以,通常的作法就是在NAT失效前,保证有心跳包发出。或者说,客户端应当以略小于NAT超时时间的间隔来发送心跳包。

NAT超时时间

早期的微信的心跳是4.5分钟发送一次心跳,能够不错的运行。

2. Mars智能心跳策略

在尽可能不影响用户收消息及时性的前提下,根据网络类型自适应的找出保活信令TCP链接的尽量大的心跳间隔,从而达到减小安卓微信因心跳引发的空中信道资源消耗,减小心跳Server的负载,以及减小部分因心跳引发的耗电。

自适应心跳

所以,在固定心跳机制下,微信又研究了一套动态计算心跳的方案,动态的探测最大的NAT超时时间,而后选定合适的心跳间隔区间去发送心跳包。这里说一下大体思路:

首先,若是心跳间隔越久,产生的负载和消耗也会越小。所以微信采用了自适应心跳:当找到一个有效心跳间隔后,咱们主动去加大这个间隔,而后测试是否能成功,若是不能,则使用比上一次成功间隔稍短的时间做为间隔;不然继续加大间隔,直到找到可用的有效间隔。

那么,如何判断一个心跳间隔有效呢?微信采用的方案是使用固定短心跳直到知足三次连续短心跳成功,则认为这个间隔有效。

探测过程大体为:60秒短心跳,连续发3次后开始探测,90,120,150,180,210,240,270

先后台策略

另外,考虑到App在先后台对于长链接的需求是不一样的。所以当微信在前台活跃态时,采用了固定心跳机制;在前台熄屏态或者后台活跃态(进入后台10分钟内)时,先用几回最当心跳维持长链接,而后进入自适应心跳机制;在后台稳定态(超过10分钟),则采用自适应心跳计算出来的最大心跳做为固定值。

若是在运行过程当中,发生了心跳失败,则进行重连。同时将心跳间隔调整为断线前间隔减去20s,从新走自适应心跳;若是连续5次均失败,则以初始心跳180s继续测试。

Alarm对齐策略

对于Android系统而言,为了减小频繁唤醒系统致使的电量损耗,提供了Alarm对齐唤醒机制:把必定时间段内的屡次Alarm唤醒合并成一次,减小系统被唤醒次数,增长待机时间。

而咱们的心跳包就是须要在定时结束后自动触发一次心跳包的发送,所以,在Mars里面的心跳时间也是按照Alarm对齐时间来作心跳间隔,减小电量损耗。

其余

对于微信心跳策略感兴趣的话能够阅读文末的参考文献,代码能够参考smart_heartbeat

VI. 长链接数据协议及加密

长链接传递的是二进制数据,先后端能够自行协商每一个字节要存放的内容便可。固然,也能够考虑采用一些通用协议:好比SMTP、ProtoBuf等序列化方案。

参考文章:《一个基于TCP/WebSockets的超级精简的长链接消息协议》.

另外,在数据加密方面,能够结合非对称加密算法RSA和对称加密算法AES来对数据进行加密传输。

这一点不是本文的重点,不作过多赘述。

VII. 长链接通道建设及容灾

上面讲了长链接的优点,那咱们该如何搭建整个长链接通道呢?这里咱们以美团的长链接通道为例子进行说明,各大厂的方案也是相似的。

美团长连通道
上面是一个简图,大致流程以下:

  1. 客户端与代理长连服务器创建长链接,代理服务器可全国多地部署,在创建长连时能够选择最近的服务器IP就近接入;
  2. 长链接创建好后,客户端对要发送的二进制数据进行加密并传输;
  3. 代理服务器收到后,能够经过内部专线或普通Http请求来访问业务服务器;
  4. 若是长链接出现问题致使不可用,为保障客户端运行,须要当即降级成普通Http短连或者UDP通道。

小结

本文结合了国内大厂如腾讯、美团等长链接框架,针对长链接这个技术点作了完整的介绍和剖析,若有不对或疑问,欢迎留言。


谢谢。

wingjay


《亿级Android架构》小专栏介绍

业务的快速增加离不开稳定可靠的架构。《亿级Android架构》小专栏会基于做者实际工做经验,结合国内大厂如阿里、腾讯、美团等基础架构现状,尝试谈谈如何设计一套好的架构来支持业务从0到1,甚至到亿,但愿与你们多多探讨。

本专栏主要内容:

  1. 当前大厂有哪些Android架构;
  2. 这些架构能解决什么问题;
  3. 这些架构的原理是什么;
  4. 学习这些架构对咱们自身的意义。

《亿级Android架构》小专栏文章列表:

《亿级 Android 架构》专栏随谈》

《Android 架构之网络链接与加速》

《Android 架构之长链接技术》

《Android 架构之高可用移动网络链接》

《Android 架构之网络安全演进》

《Android 架构之高性能移动端日志系统》


参考:

《移动端IM实践:实现Android版微信的智能心跳机制》

《Android端消息推送总结:实现原理、心跳保活、遇到的问题等》

《美团点评移动网络优化实践》

《Android版微信后台保活实战分享(网络保活篇)》

《移动 APP 网络优化概述》

《高效 保活长链接:手把手教你实现 自适应的心跳保活机制》

《一种Android端IM智能心跳算法的设计与实现探讨》

《HTTP长链接说明》

《TCP 进阶》

公众号,专一于Android、Java、大前端等技术领域,也包含程序猿成长、跳槽等内容。

相关文章
相关标签/搜索