vivo 推送平台架构演进
本文根据 Li Qingxin 老师在“2021 vivo 开发者大会"现场演讲内容整理而成。公众号回复【2021VDC】获取互联网技术分会场议题相关资料。
一、vivo 推送平台介绍
1.1 从产品和技术角度了解推送平台
推送平台是做什么的?
有的小伙伴可能了解过,有的可能是第一次接触到。无论您是哪一种情况都希望通过今天的分享,能够让您对我们有新的了解。接下来我将从产品和技术两个不同视角,给大家介绍 vivo 推送平台。
首先,从产品角度来看,vivo 推送平台通过和系统的深度结合,建立稳定可靠、安全可控、支持每秒 100w 推送速度、亿级用户同时在线的消息推送服务,帮助不同行业的开发者挖掘更多的运营价值。推送平台的核心能力是利用长连接技术 ,以智能设备、手机为载体为用户提供具备实时、双向的内容和服务传输的能力。
所以如果你是运营人员,可以考虑使用我们推送平台来运营你们在 vivo 手机系统上的 APP 来提升你们 APP 的活跃和留存。对于推送平台的本质是什么?
从技术角上来看,我们是一个通过 TCP 长连接,将消息发送给用户的平台。所以推送平台的本质其实就是借助网络通道,将消息发送到用户设备上。
大家日常都收到过快递通知吧!当快递员将快递放到快递柜中,快递后台就会自动推送一条消息,通知你有快递。我相信,如果你是一位运营人员,你也会喜欢这种自动下发消息高效的方式。大家感兴趣的,可以在分享结束之后,通过 vivo 开放平台入口,选择消息推送来更进一步了解我们。
1.2 内容、服务、设备互联
在这个万物互联的时代,我们平台也具备连接多的能力,我们通过长连接将内容、服务、用户连在一起,将内容分发给用户,为终端设备提供实时、双向通信能力。
这里有个概念长连接,那么什么是长连接?所谓的长连接就是,客户端与服务端维持的一条,在相对较长的时间里,都能够进行网络通信的网络连接(比如:基于 TCP 的长连接)。
为什么我们要采用长连接而不是短连接作为平台底层的网络通信。
我们先来看看短连接下消息下发的场景:使用短连接的方式就是轮询,即客户端定时的去询问后台有没有设备 A 的消息,当有设备 A 的消息时后台返回对应的消息,可能很多情况下都是无功而返,浪费流量;当后台有消息需要发送给设备 A 时,因为设备 A 没有过来取导致消息无法下发。而使用长连接,当有设备 A 的消息时后台直接发送给设备 A 而不用等设备 A 自己过拉取,所以长连接让数据交互更加自然、高效;除此之外,我们平台技术上还具备以下优势:
超过亿级设备同时在线;
支持百万每秒的推送速度;
支持每天超百亿级的消息吞吐量;
实时推送效果分析;
全量推送消息实时审计。
我们推送平台具备的这些能力能够为消息的时效性提供保障,我们平台具备的这些能力是经过不断的演进而来的,接下来跟大家分享 vivo 推送平台的架构这几年的变化。
二、vivo 推送平台架构演进
2.1 拥抱业务
IT 领域的架构它是动态的,不同阶段都可能会发生变化,而推动架构进行演进的推力,主要来自于业务需求,接下来我们一起来回顾,我们平台的业务发展历程。
自 2015 年立项以来,随着业务量增长,我们不断为系统添砖加瓦,丰富整个系统的能力使其满足不同的业务场景需求。比如支持内容完全审核、支持 IM、支持 IoT、支持 WebSocket 通信等。
从图上可以看到,我们业务量几乎每年都有几十亿的增长,不断攀高,给系统带来了挑战,原有的系统架构存在的问题,也逐渐浮出水面,比如延迟、性能瓶颈。架构服务于业务,2018 年之前我们平台所有服务都放在云上,但是我们依赖的其他内部业务部署在自建机房。
2.2 勇于改变
随着业务量增长与自建机房的数据传输,已经出现了延迟的问题,并且在逐渐恶化,不利于我们平台功能的拓展。所以在 2018 年下半年,我们对部署架构进行调整:将所有核心逻辑模块都迁移到自建机房,架构优化之后,数据延迟问题得到彻底解决。同时也为架构进一步演进奠定了基础。从上面的图中可以看到我们接入网关也进行优化三地部署。
为什么要进行三地部署而不是更多区域部署呢?主要基于以下三点考虑:
第一是基于用户分布及成本的考虑;
第二是能为用户提供就近接入;
第三是能够让接入网关具备一定容灾能力。
大家可以设想下,如果没有三地部署,接入网关机房故障时,那么我们平台就瘫痪了。
随着我们平台业务规模的进一步扩大,日吞吐量达到 10 亿的量级,用户对于时效性、并发要求越来越高,而我们 2018 年的逻辑服务的系统架构已经无法业务高并发的需求或者需要更高的服务器成本才能满足高并发需求。所以从平台功能、成本优化出发,我们在 2019 年对系统进行了重构,为用户提供更加丰富的产品功能及更稳定、更高性能的平台。
2.3 利用长连接能力给业务赋能
作为公司较大规模的长连接服务平台,我们积累了非常丰富的长连接经验。我们也一直在思考,如何让长连接能力为更多业务赋能。我们平台服务端各个模块之间通过 RPC 调用,这是一种非常高效的开发模式,不用每个开发人员都去关心底层网络层数据包的。
我们设想下,如果客户端也能通过 RPC 调用后台,这一定是非常棒的开发体验。未来我们将会提供 VRPC 通信框架,用于解决客户端与后台通信及开发效率问题,为客户端与后台提供一致的开发体验,让更多的开发人员不再关心网络通信问题,专心开发业务逻辑。
三、系统稳定性、高性能、安全
作为一个吞吐量超过百亿的推送平台其稳定性、高性能、安全都非常重要,那么接下来和大家分享,我们在系统稳定性、高性能、安全方面的实践经验。
从上图的领域模型可以看出,我们推送平台以通信服务作为核心能力,在核心能力的基础上我们又提供了,大数据服务以及运营系统,通过不同接口对外提供不同的功能、服务。以通信服务为核心的推送平台,其稳定性和性能都会影响消息的时效性。消息的时效性是指,消息从业务方发起用设备收到的耗时,那么如何衡量消息的时效性呢?
3.1 监控与质量度量
传统的消息时效性测量方法如左图所示,发送端和接收端在两个设备上,在发送的时候取时间 t1、在接收到消息的时候取时间 t2,这两个时间相减得到消息的耗时。但是这种方法并不严谨,为什么呢?因为这两个设备的时间基准,很有可能是不一致的。我们采用的解决方案如右图所示,将发送端和接收端放在同一个设备上,这样就可以解决时间基准的问题。我们基于该方案,搭建了一套拨测系统,来主动监控消息送达耗时分布。
3.2 高性能、稳定的长连接网关
过去 10 年讨论单机长连接性能时面对的是单机一万连接的问题,作为一个上亿级设备同时在线的平台,我们要面对的是单机 100 万连接的问题。
作为长连接网关,主要职责是维护与设备端的 TCP 连接及数据包转发。对于长连接网关,我们应该尽可能使其轻量化,所以我们从架构设计、编码、操作系统配置、以及硬件特性,自上而下穿透整个层次来进行重构优化。
调整系统最大文件句柄数、单个进程最大的文件句柄数;
调整系统网卡软中断负载均衡或者开启网卡多队列、RPS/RFS;
调整 TCP 相关参数比如 keepalive(需要根据宿主机的 session 时间进行调整)、关闭 timewait recycles;
硬件上使用 AES-NI 指令加速数据的加解密。
经过我们优化之后,线上 8C32GB 的服务器可以稳定支持 170 万的长连接。
另外一大难点在于,连接保活,一条端到端的 TCP 连接,中间经过层层路由器、网关,而每个硬件的资源都是有限的,不可能将所有 TCP 连接状态都长期保存。所以为了避免 TCP 资源,被中间路由器回收导致连接断开,我们需要定时发送心跳请求,来保持连接的活跃状态。
心跳的发送频率多高才合适?发送太快了会引起功耗、流量问题,太慢了又起不到效果,所以为了减少不必要的心跳及提升连接稳定性,我们采用智能心跳,为不同网络环境采用差异性的频率。
3.3 亿级设备负载均衡
我们平台超过亿级设备同时在线,各个设备连接长连接网关时是通过流量调度系统进行负载均衡的。当客户端请求获取 IP 时,流量调度系统会下发多个就近接入网关 IP。
那么调度系统是如何确保下发的 ip 是可用的呢?大家可以简单思考下,而我们采用四种策略:就近接入 、公网探测 、 机器负载以及接口成功率。采用这几种策略呢?大家可以想下,这两个问题:
内网正常,公网就一定能联通吗?
连接数少服务器,就一定是可用的吗?
答案是否定的,因为长连接网关与流量调度系统是通过内网进行心跳保活的,所以在流量调度系统上看到的长连接网关是正常的,但是很有可能长连接网关公网连接是异常的比如没有开通公网权限等,所以我们需要结合多种策略,来评估节点的可用性,保障系统的负载均衡、为系统稳定性提供保障。
3.4 如何满足高并发需求
有这么一个场景:以每秒一千的推送速度,将一条新闻发送给几亿用户,那么有的用户可能是几天后才收到这条消息,这就非常影响用户体验,所以高并发对消息的时效性来说是非常重要的。
大家从图上的推送流程来看,会不会觉得 TiDB 会成为推送的性能瓶颈?其实不会,初步看可能会觉得它们作为中心存储,因为我们采用分布式缓存,将中心存储的数据,根据一定的策略缓存到各个业务节点,充分利用服务器资源,提升系统性能、吞吐量。我们线上的分布式缓存命中率 99.9% 为中心存储挡住了绝大部分请求,即使 TiDB 短时间故障,对我们影响也比较小。
3.5 如何保障系统稳定性
作为推送平台,我们平台的流量主要分为外部调用及内部上下游之间的调用。它们大幅波动都会影响系统的稳定性,所以我们要进行限流、控速,保障系统稳定运行。
3.5.1 推送网关限流
推送网关作为流量入口其稳定性非常重要,要让推送网关稳定运行,我们首先要解决流量均衡的问题即避免流量倾斜的问题。因为流量倾斜之后,很有可能会引起雪崩的情况。
我们是采用轮询的机制,进行流量的负载均衡,来避免流量倾斜问题。但是这里有个前提条件,那就是所有推送网关节点,服务器配置要保持一致,否则很有可能会因为某个处理能力不足导致过载问题。其次是我们要控制流入我们系统的并发量,避免流量洪峰穿透推送网关导致后端服务过载。我们采用的是令牌桶算法,控制每个推送网关投放速度,进而能够对下游节点起到保护作用。
那么令牌数量设置多少才合适呢?设置低了,下游节点资源不能充分利用;设置太高了,下游节点有可能扛不住,我们可以采用主动+被动的动态调整的策略:
1)当流量超过下游集群处理能力时,通知上游进行限速;
2)当调用下游接口超时,达到一定比例是进行限流。
3.5.2 系统内部限速:标签推送平滑下发
既然推送网关已经限流了,为什么内部节点之间还要限速?这个是由于我们平台的业务特点决定的,我们平台支持全量、标签推送,我们要避免性能较好的模块,把下游节点资源耗尽的情况。我们标签推送模块(提供全量、标签推送)就是一个性能较高的服务,为了避免它对下游造成影响。我们基于 Redis 和令牌桶算法实现了平滑推送的功能,控制每个标签任务的推送速度,来保护下游节点。
另外我们平台支持应用创建多个标签推送,它们的推送速度会叠加,所以仅控制单个标签任务的平滑推送是不够的。需要在推送下发模块对应用粒度进行限速,避免推送过快对业务后台造成压力。
3.5.3 系统内部限速:消息下发时限速发送
所以为了实现应用级别的限速,我们采用 Redis 实现分布式漏桶限流的方案,具体方案如上图所示,这里我们为什么采用的是 clientId(设备唯一标识)而不是使用应用 ID 来做一致性 hash?主要是为了负载均衡因为 clientId 相比应用 ID,自从实现了这个功能之后,业务方再也不用担心推送太快,造成自己服务器压力大的问题。
那么被限速的消息会被丢掉吗?当然不会,我们会将这些消息存储到本地缓存、并且打散存储到 Redis,之所以需要打散存储主要是为了避免后续出现存储热点问题。
3.5.4 熔断降级
推送平台,一些突发事件、热点新闻会给系统带来较大的突发流量。我们应该如何应对突发流量呢?
如左图所示,传统的架构上为了避免突发流量对系统的冲击,冗余部署大量机器,成本高、资源浪费严重。在面临突发流量时,无法及时扩容,导致推送成功率降低。我们是怎么做的呢?我们采用增加缓冲通道,使用消息队列和容器的解决方案,这种方案系统改动小。当无突发流量时以较小量机器部署,当遇到突发流量时我们也不需要人工介入,它会根据系统负载自动扩缩容。
3.6 基于 Karate 的自动化测试系统
在日常开发中大家为了快速开发需求,大家往往忽视了接口的边界测试,这将会给线上服务造成很大的质量风险。另外不知道大家有没有注意到,团队中不同角色沟通时使用的不同媒介比如使用 word、excel、xmind 等,会导致沟通的信息出现不同程度折损。所以为了改善以上问题,我们开发了一个自动化测试平台,用于提升测试效率与接口用例覆盖率,我们采用领域统一的语言减少团队中不同角色沟通信息折损。另外还可以对测试用例统一集中管理,方便迭代维护。
3.7 内容安全
作为推送平台,我们要为内容安全把好关,我们提供了内容审计的能力。我们采用自动审核为主、人工审核为辅机制来提升审核效率,同时结合基于影响面及应用分级的策略进行内容审计,为内容安全保驾护航。从图中可以看到业务请求经过接入网关转发给内容审系统进行第一层本地规则的内容审计,如果没有命中本地规则则调用我们谛听系统进行内容反垃圾审计。
四、平台未来规划
到前面主要介绍了我们推送平台这几年的架构演进及演进过程中的系统稳定性、高性能、安全等方面的实践,接下来将给大家介绍我们未来的重点工作。
为了给用户提供更易用、更稳定、更安全的推送平台,未来我们将会在以下四个方面持续投入建设:
第一在单模块数据一致性的基础上,实现全系统数据一致性;
第二虽然目前我们平台具备了一定的容灾降级的能力,但是还不够,我们将继续完善各系统的熔断降级能力;
第三在平台的易用性方面我们依然会持续优化,为广大用户提供更加便捷的平台服务;
第四作为推送平台,异常流量识别的能力也比较重要,它可以避免异常流量影响系统的稳定性,所以未来我们也会建设异常流量识别的能力。
也希望随着我们在平台能力上持续完善,未来我们可以为大家提供更好的服务。
作者:vivo 互联网服务器团队-Li Qingxin
版权声明: 本文为 InfoQ 作者【vivo互联网技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/9839ec7c7839f913bbf52d4ef】。文章转载请联系作者。
评论