百度iOS端长连接组件建设及应用实践
本文旨在探讨长连接技术在移动端的实践,针对百度iOS端在建设长连接过程中的技术选型和整体架构逻辑将做重点展开。同时结合IM即时通讯案例的介绍和分析,展示长连接是如何在移动应用领域为类似业务场景提供解决方案的。
本文将分为五个主要部分。首先,对长连接技术进行概述,包括定义、与短连接的对比以及在移动互联网领域的常见应用。接下来,会简单介绍百度长连接服务,包括搭建的背景以及建成后提供的服务核心主流程。然后,将重点讨论百度iOS端长连接SDK搭建过程中的挑战和解决方案,包含协议的选择、DNS解析优化、长连接保活机制的设计等。紧接着,以IM即时通讯场景中的长连接实践为例,展示了长连接SDK是如何为业务实现请求数据转发、接收服务器主动推送等功能的。最后,对本文的主要内容做了总结,以及对长连接在移动端应用中未来的发展趋势和前景进行了展望。
GEEK TALK
01
长连接简介
1.1 认识长连接
长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。
1.2 长连接与短连接对比
1.3 长连接在移动互联网领域的应用
长连接在移动互联网领域有广泛的应用,特别是在实现实时通信和消息推送等功能方面发挥了关键作用。例如,常见的微信、QQ这样的即时通信软件,就是通过维持客户端和服务器的长连接,实现即时传输信息的需求。又如一些网络游戏、定位服务、新闻推送等,也会使用长连接,实时推送新的动态或者消息给用户。这样,无论用户在何时何地,只要连接到互联网,就能够接收到最新的信息,极大地提升了使用者的体验度并且使得移动互联网更加便捷。
总的来说,对实时性、数据传输效率、频繁通信等有强需求的应用,长连接都是一个好的选择。
GEEK TALK
02
百度长连接服务简介
2.1 搭建统一长连接的背景
此前,百度移动端都是由各业务自运维的长连接,往往搭建和维护成本都偏高,且可复用性不大,因此计划实现一套高并发、低时延、高触达的统一长连接组件,能够更灵活高效地支持各业务接入,能够对百度系的各APP独立输出长连接服务满足各业务的诉求,从而提升服务质量,降低资源成本。
2.2 长连接服务主流程图
百度长连接服务包含客户端的长连接SDK和服务端的长连接接入层两个部分,长连接接入层又包含访问控制模块和接入模块,负责维护长连接管理及业务数据转发。下图描述了长连接建连及心跳保活过程,业务登录和登录后推送过程,以及最终长连接SDK触发断连的过程。后文将针对iOS端长连接SDK的具体实现解决方案,和长连接SDK在百度APP中的业务应用落地进行更为详细的探讨。
GEEK TALK
03
百度iOS端搭建长连接SDK的解决方案
3.1 客户端搭建长连接的挑战点概述
客户端从0到1搭建一套完整的长连接SDK,这个过程涉及到多个技术点的考虑,包括但不限于:连接的创建和维护,网络协议的选择,使用加密传输、验证数据来源等方式保证长连接的安全性,通过数据传输格式选择、数据压缩等方式减少数据量提高传输效率,错误异常处理机制等,需要开发者根据实际情况进行最优实现方案的选择。在这之中,最核心的可以拆解为以下两个部分:
1、连接的创建:完整建连流程的设计,网络协议的选择,设计时需要考虑长连接建连的成功率、时延等核心指标;
2、连接的维护:保证建连成功是第一步,长连接还需要保持维护双方连接才可达成持续通信的目的,这包括:在长时间无数据交互的情况下,需要定期发送心跳包进行连接的保活,以及长连接连接断开后需要及时进行断线重连恢复连接在线状态。
3.2 核心逻辑一:连接的创建
长连接建连即客户端与服务器建立连接,是长连接SDK要做的第一件事,所有业务方数据的传输(上下行)都要基于长连接建连成功的这个前提。长连接建连并不是一个单一简单的操作,而是一个分阶段进行的过程。本小节将主要讨论在设计开发长连接建连模块之前,需要重点考虑确认的几个技术点和实现方案,以及百度iOS端长连接SDK最终实现的长连接建连完整过程的架构。
3.2.1 挑战①:协议的选择
问题点:UDP还是TCP
对于网络编程这个话题,使用哪种数据传输层协议来实现通信是一个非常基础但一直争论不休的问题。UDP和TCP各有各的应用场景,TCP能提供可靠的数据传输,UDP则有更高的传输效率,此处不再赘述TCP与UDP的区别,最终选择哪种协议实现,是一个见仁见智的问题,需结合整体应用场景、开发代价、部署和运营成本等方面综合考虑。
解决方案:TCP为主,同时小流量探索QUIC的潜力
百度iOS端长连接SDK中现有两套数据传输方案:
方案一:在长连接SDK建设初期,根据业内成熟技术方案选型的调研结果,及开发成本、维护便捷性的考虑,第一个方案是参考CocoaAsyncSocket框架改写的,基于Socket原生开发,使用TCP协议,支持TLS/SSL安全传输,并且是线程安全的,该方案较为成熟,使用便捷,建连成功率较高。目前百度APP iOS端中90%的用户流量都是走的该方案实现的长连接逻辑。
方案二:一般稳定网络传输都是通过TCP,但在网络基建本身已经越来越完善的情况下,TCP一些设计本身的问题便暴露了出来,加之TCP是在操作内核和中间固件中实现的,因此对TCP进行重大更改几乎是很难的事情,类似建连过程握手耗时长、队头阻塞等问题没有得到很好地解决,让我们开始考虑一些新的可能性。长连接SDK后续引入了基于QUIC协议实现的第二套方案。QUIC协议是建立在UDP之上,并且实现了可靠传输,相比HTTP2+TCP+TLS协议,QUIC具有不少优点:减少了TCP三次握手及TLS握手时间,改进了拥塞控制,并且没有队头阻塞的多路复用,支持连接迁移等。百度iOS长连接SDK目前通过NWConnection引入了QUIC协议的实现。QUIC的协议虽然比较先进,但这也意味着在工程实现方面有更多可优化的空间,目前方案二还处于小流量实验阶段,仍有很多优化工作有待后续进一步去落地。就当前放量所得到的数据来看,在长连接建连成功率及时延指标上,QUIC实现方案都有较好的表现。
3.2.2 挑战②:DNS解析优化
问题点:国内移动端网络所面临的DNS疑难杂症
国内各ISP运营商的LocalDNS由于域名缓存、解析转发、LocalDNS递归出口NAT的原因,容易引起DNS被劫持造成服务不可用、DNS调度不准确导致性能退化等问题。DNS解析的效率和准确性,直接影响长连接建连的质量,进而影响公司的业务。
解决方案:HTTPDNS
因此在百度iOS端长连接SDK中,采用当前业界比较主流的解决方案:HTTPDNS,来替代LocalDNS解析。HTTPDNS是利用HTTP协议与DNS服务器进行交互,绕开了运营商的LocalDNS服务,有效防止了域名劫持,提高域名解析效率。
3.2.3 完整解决方案:百度iOS端长连接建连整体流程
建连时机
在百度APP中,统一维护了一系列系统事件和生命周期供各个组件监听。iOS长连接SDK根据百度APP的业务特性,选择在环境搭建完成事件后触发长连接建连,即等待APP启动必要数据比如首页资源等加载完成后,开始触发长连接建连。
建连完整过程
下图展示了长连接SDK建连的四个过程:
获取Token:
获取Token的意义:狭义上Token指的是长连接访问控制模块返回的access-token,后续随长连接登录请求上行到长连接接入层,由接入层向长连接访问控制模块进行鉴权用。广义上随此次Token请求下发的,还有传输协议及访问点等数据,包括但不限于:长连接协议使用QUIC还是TCP,是否优先ipv6,连接域名和端口,日志打点小流量开关等。
获取Token的机制:获取Token优先走本地缓存,当本地缓存无有效数据时,才发出网络请求,该请求是基于NSURLSession实现的短连接请求;Token在服务端和客户端均有缓存,存在过期时间,若Token过期,会在下图中阶段四通过长连接登录请求失败体现,这时会清空本地Token缓存并触发重新建连。
DNS域名解析:如前所述,长连接SDK中使用HTTPDNS替代LocalDNS来防止DNS劫持、提高解析效率。同时在iOS Release环境下,为提高DNS解析效率,本地建立了缓存机制,HTTPDNS解析结果返回后会更新本地缓存,下次建连过程优先取缓存,缓存不合法才走网络请求。
建立Socket连接:Socket建连过程涉及到传输协议的选择,根据前面介绍,iOS长连接SDK目前是通过小流量实验的方式,10%的用户走QUIC建连,90%的用户走TCP建连。
长连接登录请求:携带Token中获取的access-token上行请求完成鉴权,长连接登录请求返回成功意味着整个建连过程完成,业务层可开始正常使用长连接进行通讯,若登录返回报错,则会触发重连。
顺利完成这四个阶段后,长连接会在该链路上持续发送心跳包进行连接保活,在异常断连或压后台等触发的主动断连之前,一直保持连接在线状态,为各个业务的数据传输提供通路。
3.3 核心逻辑二:连接的维护
3.3.1 维护连接的意义
上个小节介绍了长连接连接建立的全过程,长连接建连成功后,实际已处于可用状态,即各业务基于长连接的通信已经可以正常进行。但在此之后,保持长连接的可用性也是非常重要的。如果长连接无法很好地保持,在连接已经失效的情况下服务端继续推送下行通知而端却收不到,造成资源的浪费,同时无法及时重新建连,对业务造成损失。
3.3.2 维护长连接的解决方案
针对可能导致长连接断开的几种主要原因,长连接SDK建立了对应的机制来保证连接的稳定性,可总结为两点:心跳保活和断线重连。
解决方案①:心跳保活
心跳保活的定义:实现长连接保活的方式通常是采用应用层心跳,通过心跳包的超时或报错等来执行重连操作。心跳一般是指某端(通常是客户端)每隔一定时间向另一端(通常是服务端)发送自定义指令,以判断双方是否存活,因其按照一定间隔发送,类似于心跳,故被称为心跳保活。
百度iOS端长连接SDK心跳保活机制:长连接登陆请求成功后,解析返回数据,若服务端下发了心跳包的间隔时间,则以服务端下发的时间间隔持续发送心跳包进行连接保活,若没有下发心跳包间隔时间,客户端会默认60s间隔时间来触发心跳包的发送。具体心跳保活过程见下图。
解决方案②:断线重连
断线重连原理:在长连接可能被断开的场景(压后台重进APP、网络状态变更等),检测长连接的可用状态,监测到连接不可用时,及时触发重连机制。
百度iOS端长连接SDK断线重连机制:具体触发断线重连的时机见下图,iOS长连接SDK内部维护有串行队列和统一的长连接状态监测记录,不会导致重复建连的发生。
GEEK TALK
04
长连接在百度APP中的应用与实践
4.1 长连接在百度APP中的业务落地
长连接是客户端到服务端的一种全双工连接,建连完成后,可以为业务方提供请求转发、服务端主动推送等服务。在百度APP中,包括在线健康诊疗、高考志愿填报咨询、情感心理辅导等一系列实时咨询服务,发送直播弹幕、加入某大V粉丝群聊天、私信好友等多种用户实时沟通场景的落地,以及实现用户在线情况下云端可及时主动下发配置控制端的基础能力建设,都离不开长连接的支持。长连接为各个业务与自己服务端的数据交互提供了稳定便捷的方式和渠道。
下图为百度APP中长连接与落地业务的结构示意图。完整的长连接模块包括了客户端的长连接SDK和服务端的长连接接入层两个部分,作为各个业务与自己服务端数据交流的中间渠道,处理了包括连接建立与保活、实现各业务客户端与自己服务端的数据双向互发等逻辑。下面将重点关注长连接在IMSDK实时聊天通讯场景中的实践。
4.2 长连接在IM即时通讯场景中的实践
4.2.1 背景介绍
IMSDK,即百度消息中台为百度APP及百度系其他产品打造的具备应用内即时通讯能力的客户端SDK,包括多种用户沟通场景:私聊、群聊、聊天室、直播弹幕等,并帮助业务推送消息通知触达用户,建立B端和C端的沟通渠道。目前主功能诸如拉取会话列表、拉取消息、发送消息、消息已读等均为长连接实现。本小节将通过介绍用户发送消息、用户收到新消息通知这两个IM及时通讯中的常见场景,展示长连接提供的数据转发和服务器主动推送能力是如何在业务场景落地的。
4.2.2 实践1:实时聊天场景下用户发送消息
实践场景
实时聊天场景下,用户在聊天框向自己好友发送一条消息,消息如果发送失败了,应用通常会在本条消息气泡旁展示一个红叹号,这个应用场景对于互联网用户应该都非常熟悉。从技术角度看,本质上是业务客户端向自己的服务器上行一个请求,服务器再将请求结果返回给客户端。这是一个典型的需要频繁点到点通信的场景,非常适合基于长连接来实现。长连接SDK对外提供了封装好的长连接请求类,外部业务方诸如IMSDK在上行长连接请求时通过创建该类的实例,将上行所需参数和数据赋值给请求实例,并设置回调闭包用于接收和处理请求回执数据和结果,最后将请求发出。业务不需要考虑数据传输及转发等逻辑,长连接会充当业务客户端和服务器之间的通路,黑盒处理这个过程。
技术难点
对于长连接SDK而言,在这条通路上最重要也是比较复杂的逻辑点在于,各个业务方的上行请求和下行通知都是并发进行的,长连接SDK如何有序地管理数据流向。上行请求即写流,接收下行数据即读流,下面就读写流的管理,与请求同回执数据的匹配问题的解决方案作简要的介绍。
技术实现
长连接SDK内就读写数据维护有两个队列:读队列和写队列,以及维护了一个缓存池用作请求实例和请求回执数据的匹配。业务方上行一个长连接请求,实际上是将请求任务添加到写队列中,如果此时处于可写流状态,还会触发写流。当socket建连成功以后,会取出写队列队头的任务,开始写流,写流完毕会检查写队列是否为空,不为空继续取队头任务执行,直至写队列为空为止。同时socket建连成功还会添加一次读任务到读队列中,并检查如果此时处于可读状态,便取出队头第一个读任务,开始读流,读流成功后会继续添加一个读任务到读队列,循环读流操作。
读流得到的服务端下行返回数据,通过serviceId(业务编号)+ methodId(长连接请求方法编号)+ 请求发起的时间戳组成唯一键值,去缓存区匹配到下行返回数据对应的请求体,通过回调的方式,将请求结果返回到调用方。该请求一旦被回调过一次,其实例将从缓存区被删除,及时释放缓存区内存,并且保证一次请求不会发生多次回调的情况。
4.2.3 实践2:实时聊天场景下用户收到新消息通知
实践场景
实时聊天场景下,用户是如何收到别的用户发送给他的新消息通知的呢?其实是依靠服务器的下行通知到客户端。长连接不仅提供为业务客户端转发上行请求的能力,还提供了服务端主动推送的服务。比如在IM业务中,依靠IM服务器下行新消息通知,来完成消息的实时接收和拉取。这些通知又是如何到达IMSDK的呢?其实它与上一小节IMSDK上行长连接请求的过程类似。
技术实现
在IMSDK的长连接管理类初始化阶段,会对需要接收的下行通知方法进行注册,这里的注册实际上指的就是上行多个长连接请求,每个请求有对应的serviceID(业务编号)和methodID(需要注册的通知方法号码)。跟上一小节长连接请求不同的点在于,这些请求在收到回执数据后不会从长连接SDK请求缓存区里移除,而是会长期存在,只要读流时读到了对应methodID的数据,就能在请求缓存区找到对应请求,将下行数据传到IMSDK了。这样一来,只要长连接在线,业务方就能实时接收到其服务器下行的通知消息了。
GEEK TALK
05
结语
长连接服务的核心大致可分为:建连过程、连接维持过程以及数据传输过程。本文给出了搭建长连接服务过程中面临的一些挑战和解决方案,并结合长连接功能在百度APP即时通讯场景下的实践,简要介绍了百度iOS端长连接SDK的整体架构。
在移动端,长连接技术的应用前景非常广阔。随着5G和6G等高速移动网络的发展,将使得移动应用程序能够更加高效地使用长连接技术,从而实现更加实时和高效的数据交换。这也为对实时数据交换有强需求的应用场景提供了更广阔的想象空间,诸如物联网、智能家居、虚拟现实和增强现实等技术,长连接都将在其中发挥更加重要的作用。
END
推荐阅读: