vivo手机上的系统级消息IM电竞推送平台的架构设计实践
栏目:im资讯 发布时间:2022-09-13 11:33:08

  本文内容来自vivo互联网服务器团队李青鑫在“2021 vivo开发者大会”现场的演讲内容整理而成(现场演讲稿可从本文末附件中下载)。

  本文将要分享的是手机厂商vivo的系统级推送平台在架构设计上的技术实践和总结。这也是目前为止首次由手机厂商分享的自建系统级推送平台的技术细节,我们也得以借此机会一窥厂商ROOM级推送通道的技术水准。

  消息推送对于移动端APP来说,是很常见的业务特征,比如新闻APP中的最新资讯、社交应用中的系统通知、IM即时通讯应用的离线聊天消息等等。

  可以说,没有消息推送能力,APP就失去了实时触达的能力,对于一个应用来说,它对用户的“粘性”将大大下降。而对于用户来说,信息实时获取的能力也将大大降低,用户体验也将大幅下降。

  但随着Android系统的不断升级,离线推送已经不单单是一个后台服务加长连接那么理所当然了。

  对于早期的Android系统来说,想要实现IM的离线消息推送并不困难,搞个后台服务再加上socket长连接就算是齐活了。

  但随着Android系统的升级,针对后台进程和网络服务限制不断加码,为了继续实现离线消息的推送,开发者们不得不跟系统斗志斗勇,搞出了各种保活黑科技,比如:Android4.0之后的双进程守护、Android6.0及之后的防杀复活术、以及发展到后来的腾讯TIM进程永生技术,一时间群魔乱舞、无比风骚(有兴趣的同学,可以读读《Android进程永生技术终极揭秘:进程被杀底层原理、APP应对被杀技巧》这篇针对所有保活黑科技的总结性文章)。

  随着Andriod 9.0的到来,基本从系统上堵死了各种保活黑科技的活路(详见《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》),各Android厂商的ROOM系统级推送通道也应运而生——华为推送、小米推送、魅族推送、OPPO推送、vivo推送,一时间从用户的噩梦(保活黑科技对用户困扰很大)变成了开发者的恶梦并持续至今(想要做好IM离线推送,如今的IM开发者们不得不一家家对接各手机厂商的离线推送,你说烦不烦)。

  也别跟我说为什么不用Android官方的FCM服务(在国内这链接你能打开算我输,至于为什么,你懂的。。。),也别我跟提那个统一推送联盟(4、5年过去了,看样子还要继续等下去)。

  随着Android系统对于开发者保活黑科技的“堵”,手机厂商们搞出自家的系统级推送通道来“疏”,也算是理所当然。而这些厂商之中,vivo的系统级推送通道出现的算是比较晚的。

  本篇文章的余下技术内容,算是目前为止首次由手机厂商分享的自建系统级推送平台的技术细节,我们一起来学习。

  从技术的角度上来看,推送平台就是一个通过TCP长连接,将消息发送给用户的平台。所以推送平台的本质其实就是借助网络通道,将消息发送到用户设备上。

  大家日常都收到过快递通知吧!当快递员将快递放到快递柜中,快递后台就会自动推送一条消息,通知你有快递。我相信,如果你是一位运营人员,你也会喜欢这种自动下发消息高效的方式。

  大家感兴趣的,可以通过vivo开放平台入口,选择消息推送来更进一步了解更多技术细节,这里就不做展开了。

  消息推送平台的本质,就是通过长连接将内容、服务、用户连在一起,将内容分发给用户,为终端设备提供实时、双向通信能力。

  所谓的长连接就是:客户端与服务端维持的一条、在相对较长的时间里、都能够进行网络通信的网络连接(比如:基于TCP的长连接)。

  先来看看短连接下消息下发的场景:使用短连接的方式就是轮询,即客户端定时的去询问后台有没有设备A的消息,当有设备A的消息时后台返回对应的消息,可能很多情况下都是无功而返,浪费流量。当后台有消息需要发送给设备A时,因为设备A没有过来取导致消息无法下发。

  而使用长连接:当有设备A的消息时后台直接发送给设备A而不用等设备A自己过拉取,所以长连接让数据交互更加自然、高效。

  对于系统的技术架构来说,它是动态的,不同阶段都可能会发生变化。而推动架构进行演进的推力,主要来自于业务需求,一起来回顾,平台的业务发展历程。

  自2015年立项以来,随着业务量增长,不断为系统添加功能特性,丰富整个系统的能力使其满足不同的业务场景需求。比如支持内容完全审核、支持IM、支持IoT、支持WebSocket 通信等。

  从图上可以看到,业务量几乎每年都有几十亿的增长,不断攀高,给系统带来了挑战,原有的系统架构存在的问题,也逐渐浮出水面,比如延迟、性能瓶颈。

  架构服务于业务,2018年之前我们平台所有服务都放在云上,但是依赖的其他内部业务部署在自建机房。

  随着业务量增长与自建机房的数据传输,已经出现了延迟的问题,并且在逐渐恶化,不利于我们平台功能的拓展。

  所以在2018年下半年,我们对部署架构进行调整:将所有核心逻辑模块都迁移到自建机房,架构优化之后,数据延迟问题得到彻底解决,同时也为架构进一步演进奠定了基础。从上面的图中可以看到我们接入网关也进行优化三地部署。

  大家可以设想下,如果没有三地部署,接入网关机房故障时,那么平台就瘫痪了。

  随着平台业务规模的进一步扩大,日吞吐量达到10亿的量级,用户对于时效性、并发要求越来越高。而2018年的逻辑服务的系统架构已经无法业务高并发的需求或者需要更高的服务器成本才能满足高并发需求。

  所以从平台功能、成本优化出发,在2019年对系统进行了重构,为用户提供更加丰富的产品功能及更稳定、更高性能的平台。

  作为公司较大规模的长连接服务平台,团队积累了非常丰富的长连接经验im资讯。我们也一直在思考,如何让长连接能力为更多业务赋能。

  我们平台服务端各个模块之间通过RPC调用,这是一种非常高效的开发模式,不用每个开发人员都去关心底层网络层数据包的。

  我们设想一下,如果客户端也能通过RPC调用后台,这一定是非常棒的开发体验。

  未来我们将会提供VRPC通信框架,用于解决客户端与后台通信及开发效率问题,为客户端与后台提供一致的开发体验,让更多的开发人员不再关心网络通信问题,专心开发业务逻辑。

  作为一个吞吐量超过百亿的推送平台其稳定性IM电竞、高性能、安全都非常重要,接下来和大家分享,我们在系统稳定性、高性能、安全方面的实践经验。

  从上图的领域模型可以看出,推送平台以通信服务作为核心能力,在核心能力的基础上我们又提供了,大数据服务以及运营系统,通过不同接口对外提供不同的功能、服务。

  传统的消息时效性测量方法如上图左所示:发送端和接收端在两个设备上,在发送的时候取时间t1、在接收到消息的时候取时间t2,这两个时间相减得到消息的耗时。

  但是这种方法并不严谨,为什么呢?因为这两个设备的时间基准,很有可能是不一致的。

  我们采用的解决方案如上图右图所示:将发送端和接收端放在同一个设备上,这样就可以解决时间基准的问题。我们就是基于该方案,搭建了一套拨测系统,来主动监控消息送达耗时分布。

  过去10年讨论单机长连接性能时面对的是单机一万连接的问题(C10K问题),而作为一个上亿级设备同时在线的平台,我们要面对的是单机100万连接的问题。

  另外一大难点在于连接保活:一条端到端的 TCP连接,中间经过层层路由器、网关,而每个硬件的资源都是有限的,不可能将所有TCP连接状态都长期保存。

  所以为了避免TCP资源,被中间路由器回收导致连接断开,我们需要定时发送心跳请求,来保持连接的活跃状态(为什么TCP有这样的问题?有兴趣可以读这两篇:《为什么说基于TCP的移动端IM仍然需要心跳保活?》、《彻底搞懂TCP协议层的KeepAlive保活机制》)。

  心跳的发送频率多高才合适?发送太快了会引起功耗、流量问题,太慢了又起不到效果,所以为了减少不必要的心跳及提升连接稳定性,我们采用智能心跳,为不同网络环境采用差异性的频率。

  我们平台超过亿级设备同时在线,各个设备连接长连接网关时是通过流量调度系统进行负载均衡的。

  答案是否定的,因为长连接网关与流量调度系统是通过内网进行心跳保活的,所以在流量调度系统上看到的长连接网关是正常的,但是很有可能长连接网关公网连接是异常的比如没有开通公网权限等。

  所以我们需要结合多种策略,来评估节点的可用性,保障系统的负载均衡、为系统稳定性提供保障。

  有这么一个场景:以每秒1000的推送速度,将一条新闻发送给几亿用户,那么有的用户可能是几天后才收到这条消息,这就非常影响用户体验,所以高并发对消息的时效性来说是非常重要的。

  其实不会:初步看可能会觉得它们作为中心存储,但因为我们采用分布式缓存,将中心存储的数据,根据一定的策略缓存到各个业务节点,充分利用服务器资源,提升系统性能、吞吐量。我们线% 为中心存储挡住了绝大部分请求,即使TiDB短时间故障,对我们影响也比较小。

  作为推送平台,平台的流量主要分为外部调用及内部上下游之间的调用。它们大幅波动都会影响系统的稳定性,所以需要进行限流、控速,保障系统稳定运行。

  要让推送网关稳定运行IM电竞,我们首先要解决流量均衡的问题即避免流量倾斜的问题。因为流量倾斜之后,很有可能会引起雪崩的情况。

  我们采用的是令牌桶算法,控制每个推送网关投放速度,进而能够对下游节点起到保护作用。

  那么令牌数量设置多少才合适呢?设置低了,下游节点资源不能充分利用;设置太高了,IM电竞下游节点有可能扛不住。

  这个是由于我们平台的业务特点决定的,平台支持全量、标签推送,要避免性能较好的模块,把下游节点资源耗尽的情况。

  标签推送模块(提供全量、标签推送)就是一个性能较高的服务,为了避免它对下游造成影响。我们基于Redis和令牌桶算法实现了平滑推送的功能,控制每个标签任务的推送速度,来保护下游节点。

  另外:平台支持应用创建多个标签推送,它们的推送速度会叠加,所以仅控制单个标签任务的平滑推送是不够的。需要在推送下发模块对应用粒度进行限速,避免推送过快对业务后台造成压力。

  为了实现应用级别的限速,我们采用Redis实现分布式漏桶限流的方案,具体方案如上图所示。

  这里我们为什么采用的是clientId(设备唯一标识),而不是使用应用ID来做一致性hash?主要是为了负载均衡。

  自从实现了这个功能之后,业务方再也不用担心推送太快,造成自己服务器压力大的问题。

  那么被限速的消息会被丢掉吗?当然不会,我们会将这些消息存储到本地缓存、并且打散存储到Redis,之所以需要打散存储主要是为了避免后续出现存储热点问题。

  推送平台,一些突发事件、热点新闻会给系统带来较大的突发流量。我们应该如何应对突发流量呢?

  如上图左所示:传统的架构上为了避免突发流量对系统的冲击,冗余部署大量机器,成本高、资源浪费严重。在面临突发流量时,无法及时扩容,导致推送成功率降低。

  我们是怎么做的呢?我们采用增加缓冲通道,使用消息队列和容器的解决方案(这种方案系统改动小)。当无突发流量时以较小量机器部署,当遇到突发流量时我们也不需要人工介入,它会根据系统负载自动扩缩容。

  在日常开发中大家为了快速开发需求,往往忽视了接口的边界测试,这将会给线上服务造成很大的质量风险。

  另外,不知道大家有没有注意到,团队中不同角色沟通时使用的不同媒介比如使用word、excel、xmind等,会导致沟通的信息出现不同程度折损。

  所以为了改善以上问题,我们开发了一个自动化测试平台,用于提升测试效率与接口用例覆盖率,我们采用领域统一的语言减少团队中不同角色沟通信息折损。另外还可以对测试用例统一集中管理,方便迭代维护。

  审计方法采用自动审核为主、人工审核为辅机制来提升审核效率。同时结合基于影响面及应用分级的策略进行内容审计。

  从下图中可以看到业务请求经过接入网关转发给内容审系统进行第一层本地规则的内容审计,如果没有命中本地规则则调用我们谛听系统进行内容反垃圾审计。

  前面我们主要介绍了推送平台这几年的架构演进及演进过程中的系统稳定性、高性能、安全等方面的技术实践,接下来介绍未来的重点工作。

  [6] Android P正式版即将到来:后台应用保活、消息推送的线] 融云安卓端IM产品的网络链路保活技术实践

  [9] 史上最强Android保活思路:深入剖析腾讯TIM的进程永生技术

  [10] Android进程永生技术终极揭秘:进程被杀底层原理、APP对抗被杀技巧

  [11] Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?