作者| 阿里文娱开发工程师 张满
作为大型基础服务,播控系统有几十个上游业务方,并且其中大部分都是直接参与视频播 放生产链路的重要应用。这些业务方比如 CMS、媒资、播放服务、搜酷和 OTT 等对播控服务 的 RT 和成功率的抖动很敏感,播控的任何抖动直接影响视频播放链路,进而影响用户观看体验。
随着播控应用的业务方数目和调用量不断上涨,系统流量不断增大但是机器资源有限,如何在资源有限的条件下解决系统稳定性?
除了持续进行系统优化, 我们以去中心的思路来解决问题:提供一个封装播控核心服务的 近端调用 SDK,大流量业务方使用 SDK 完成内容播控的需要,以此降低对播控中心服务的依 赖,减少风险;对于播控中心系统,SDK 抵挡了大流量的冲击,提升系统稳定性的同时节省了 机器资源。
一、播控 SDK 的技术架构与进展
播控系统作为控制内容播放的服务,业务方的请求到达播控后,处理流程可以分为两步:
第一步是先获取视频关联的播控策略, 会进行分布式缓存、本地缓存以及数据库的查询;
第二步是根据查询出的数据进行静态计算并返回结果。
由于查询分布式缓存和本地缓存具有极高的缓存中率,所以可以将查询缓存和静态计算的 过程迁移到播控 SDK 中,完成大部分请求的响应,剩下没有命中缓存的部分,再进行 RPC 调 用获取结果。播控中心系统和 SDK 的关系图如下:
播控中心系统和 SDK 共用基础设施资源,并且具有相同的静态计算过程。与之前所有业务 方都集中请求播控系统,由播控系统统一收集信息并进行计算的调用方式相比,播控 SDK 以去 中心化的方式来提供服务,由业务方机器来收集信息并进行静态计算,防止由于播控系统的故 障,造成所有业务方请求播控都失败,减少了系统性风险。同时业务方引入播控 SDK 后,99% 的查询和计算都在本地完成,减少远程请求的通信耗时和网络延迟, 依赖的播控服务的稳定性 大幅度提升。对于播控中心系统来说,SDK 抵挡了业务方流量,减少机器成本的同时,提升了 系统稳定性。
当前,已经有几个较大的业务方接入了播控 SDK,经过 SDK 处理的流量占播控系统总体 流量四成以上,相当于年度节省上百万的机器成本。
二、播控 SDK 遇到的技术挑战和解决方案
播控 SDK 在去中心化过程中,遇到三个核心技术挑战:
1)接入播控 SDK 的业务方在多个环境多套机房, SDK 如何屏蔽业务方环境差异,与播控 中心系统提供一致的播放控制服务功能;
2)业务方机器资源有限,如何提升 SDK 的性能和减少计算资源消耗;
3)播控 SDK 嵌入多个业务方环境运行,如何监控 SDK 的运行状态,并且出现问题时具备 有效的预警和稳定性方案。
接下来从以上三个方面来具体介绍播控 SDK 解决上述问题的方案。
1. 多机房多环境的数据和服务一致性
播控 SDK 要和播控中心系统提供一致的服务,需要从两个方面保障:所用数据一致性和计 算过程一致性;
1)数据一致性的保障。当前集团出于异地容灾等方面的考虑,采用多机房多单元方式部署; 接入播控 SDK 的业务方所在环境复杂,与播控系统本身所在环境是隔离的;SDK 所用的大部 分数据来自分布式缓存和本地缓存,业务方的环境差异给 SDK 的获取缓存数据带来麻烦;为了 确保不同环境下的数据一致性,SDK 采用如下的结构进行数据获取和数据更新:
针对不同环境下获取分布式缓存的数据,我们采用两种方式解决:
a)同单元内使用跨机房访问的方式。如图 2 所示,业务方 B 的 SDK 使用跨机房访问的方式获取分布式缓存 A 的数据,对于可以接受跨机房访问延迟的业务方,很轻量级地解决了环境的差异;同时,SDK 访问的缓存数据和播控中心系统访问的缓存数据是同一份,所以数据是一 致的;
b)播控系统额外部署业务方所在环境的缓存系统。如图 2 所示,业务方 C 所在的环境额 外部署了分布式缓存 C,SDK 从分布式缓存 C 中获取数据,避免了缓存访问的跨机房延迟;虽 然 SDK 访问的缓存和中心系统访问的缓存不是同一个,但是缓存数据的最终来源是同一个数据库,所以只要确保不同环境的缓存都是从同一个数据库的主库中获取的数据,缓存数据也是一 致的。
针对 SDK 的本地缓存,主要存在缓存更新和数据实效性问题,我们采用两种方案确保本地缓存数据一致性:
a)对于实效性很高的本地缓存数据,使用消息中间件-广播消费的方式将内存缓存失效的 消息通知到每一台机器,比如消息源 A 将消息广播到业务方 A 的每台机器上;当业务方所在环 境与播控的消息源所在环境隔离时,采用消息全球路由的方式(比如消息中转中心 B 和消息中转 中心 C), 将播控系统消息源的消息投递到其他环境;
b)对于实效性不高的本地缓存数据,使用定时任务调用 RPC 接口定时刷新;
2)计算过程一致性的保障。
a)业务代码一致性。由于播控 SDK 和播控中心系统的功能大致相同,所以如果 SDK 和中 心系统业务逻辑冗余度高,会产生大量相似的代码,后期任何改动需要维护两份,会给未来埋 下很多隐患。经过评估后,我们决定将整个播控核心接口主流程进行重构,抽象出一公共的模 板二方包; 针对 SDK 和主系统不一样的地方,留出抽象方法,分别实现,达到最大复用功能模 块的目的。
b)接口响应一致性。为了确保对任意一个请求,SDK 和中心系统的返回值一模一样,我们使用线上流量回放工具作为最后的质量验收标准。每次涉及到任何改动,我们都会使用回放工具录制线上的请求导入 SDK 中进行回放, 对比返回结果, 及时发现差异和异常。
通过数据一致性和计算过程一致性的保障手段,播控 SDK 和中心系统的数据差异延迟控制 在毫秒内,能够提供一致的服务功能,满足不同业务方的不同业务诉求。
2. 如何兼顾 SDK 的高性能和低消耗
SDK 运行在业务方的机器上,很多时候业务方机器资源紧张,必须要在有限的资源内提升SDK 性能,降低计算资源消耗。SDK 性能优化集中在业务和技术层面,如下图所示:
1)日志优化。在高并发系统中,日志会成为系统的瓶颈;除了定制高性能的日志参数外,还要从打印日志的源头进行优化;比如进行日志压缩,只保留关键日志信息,减少日志中的字 符数量等;
2)减少序列化和反序列化。序列化和反序列化是高CPU 消耗的操作,使用本地对象缓存 代替字符串缓存以及提升内存缓存命中率来减少 RPC 调用等手段,来减少序列化和反序列化;
3)对象拷贝优化。基于 CGLIB 的字节码生成实现对象拷贝来代替反射,接近原生对象属 性赋值方法;
4)业务代码逻辑优化。减少重复调用,减少对象创建以及提升接口批量处理能力等。 经过上述优化,播控 SDK 的 CPU 消耗和 Load 压力相比优化前降低了 60%以上;
3. 有效的监控预警和稳定性保障方案
1)监控预警
在各个业务方机器上运行的 SDK 如果没有有效的预警体系,当问题发生时,就不能第一时 间发现。为了建立监控体系,我们做了以下工作:
a)SDK 中做好业务日志埋点和日志采样;
b)使用全链路工具标记 SDK 中的关键方法;
c)SDK 定时收集缓存命中率、单机 QPS 以及接口成功率和 RT 等信息,并上报; 整个监控预警体系的建立如下图所示:
基于上述的监控信息,将分散在各个业务方机器上的日志统一收集到日志中心,并建立重 要指标的预警基线,确保能够第一时间发现问题。
2)稳定性方案
有了问题发现机制,必须要有问题解决机制;SDK 中为了应对不同程度的稳定性问题,提 供了不同程度的降级方案,如下图所示:
a)流量动态切换方案。当业务方机器能够承受的 SDK 流量上限超过阈值时,多余的流量 会动态分散到播控中心系统;这在实际中是很有效的,在一些单机 1000 QPS 甚至更高的场景下,确保 SDK 不会压垮业务方机器。极端情况下,所有流量都可以回切到播控中心系统。
b)数据库不可用降级方案。当数据库出现故障时,及时与数据库切割开来,使用缓存的数据继续对外服务,防止出现更大面积的故障。
c)黑名单降级方案。当分布式缓存出现故障时,使用黑名单降级方案,SDK 此时只控制 涉黄涉暴涉政等敏感视频不透出;接口 RT 和成功率仍然能确保正常。
播控 SDK 建立的监控预警和稳定性保障体系,经历双 11 和多次实战考验,能够在分钟内 发现问题并解决问题。
三、总结
本节介绍了播控系统的近端调用能力,在系统流量不断上涨、机器资源有限的局面下,以 去中心化的方式来分散中心系统的压力,解决了系统稳定性问题。其中重点讲述了播控 SDK 的 三个核心技术挑战:“服务一致性”“资源利用率”和“稳定性保障”,以及解决这些问题的思路。 在这些解决方案中,很多部分触及到了高并发系统的共性问题,在一些公开场合的技术分享中, 诸如日志性能优化、缓存更新方式和减少序列化、反序列化等这些点都能引起大家的共鸣,也 期待这些经验能够帮助到他人。去中心化是当前软件系统的发展趋势,播控作为大型基础应用, 在去中心化的道路上做了一次重要的尝试,并且取得不错的进展。未来播控 SDK 会继续优化和 推广,作为播控中心系统能力的一种补充,继续发挥重要价值。