面向失败的设计之播控系统!

面向失败设计的系统架构
本文探讨了面向失败设计的概念,解释了为何需要这种设计思路,并详细介绍了如何在软件生命周期的不同阶段实施。以优酷播放控制系统为例,展示了通过读写分离、缓存冗余更新、数据库兜底等策略,确保系统在面对各种失败场景时仍能稳定运行。

作者 | 阿里文娱高级开发工程师 云琰浅

责编 | 屠敏

谈面向失败的设计

1、什么是面向失败的设计?

面向失败的设计,就是以“失败”为对象,天然为了失败而存在的设计思想,在一开始的系统设计阶段就考虑到各种失败场景,把面向失败当成是系统设计的一部分,准备好从失败中恢复的策略。

2、为什么要面向失败设计?

因为无所不在的失败场景,比如硬件问题,软件bug,配置变更错误,系统恶化,超预期流量,外部攻击,依赖库问题,依赖服务问题。

并且,这些一旦失败,轻则出现业务不可用,影响用户体验和企业声誉;重则导致数据永久丢失、业务再无恢复可能。例如,911事故发生前,约有350家企业在世贸大厦工作。事故后,有200家企业由于重要系统被破坏,关键数据丢失而倒闭。

3、怎么面向失败设计?

在软件的整个生命周期中,不同的阶段面对失败场景有不同的应对规则。在设计阶段将系统的架构简单化,结构层次分明;在发布阶段尽量做到最小变更原则,小规模,多次迭代;在运维阶段做好周期性压测,最小依赖。

播控是如何实现面向失败设计的

1、播控架构设计

优酷播放控制系统从层级结构上将系统分成3层,对外服务层、基础服务层、数据存储层。

第一层:对外服务层包含播控SDK,播控查询服务,播控变更服务,播控筛选服务

第二层:基础服务层包含播控任务调度,播控数据库服务;

第三层:数据存储层包含分布式缓存,数据库,开放搜索。   

从功能上,播控系统共3大核心线路读核心、写核心、筛选服务。

线路一:读核心是整个系统的核心服务,负责优酷、土豆、天猫视频展示、透出能力;

线路二:写核心负责整个系统策略变更核心服务;

线路三:筛选服务提供管理后台多数据源筛选服务。

这样设计的特性如下:

1)  线路上读、写分离,核心与筛选分离(主次分离),单独链路变更失败之后不会影响核心链路的功能;

2)  核心高并发查询服务读取数据库方式从数据库服务隔离开,当压力增加后,无单点瓶颈,可以无限扩展;

3)  任一链路故障,其他链路正常运行,稳定提供服务;

4)  数据库服务遵从容量设计原则,针对查询服务、变更服务相同接口有不同限流策略。 

2、数据库不可用兜底设计

数据库兜底设计的目的在于在数据库不可用的极端场景下,保证生产链路不挂,且不会影响到业务方。实现方式通过全局统一开关,切换核心读链路和写链路使用缓存作为临时的数据持久层,并把数据变更堆积在消息队列中,待数据库可用后再切换回数据库,并消费消息队列。

读链路数据库兜底流程

读链路以查询是否资源是否可播为例,兜底开关打开,则只查询缓存中是否存在该资源。若缓存中存在资源,则返回查询结果。若不存在,则判断资源是否在禁播黑名单,根据判断结果返回是否可播。可见兜底开关打开后,虽然返回的是降级之后的结果,但至少摆脱了对数据库的依赖,整个流程仍能正常进行下去。

写链路数据库兜底流程

写链路以新增资源策略为例,兜底开关打开,则先查询缓存中是否存在该资源策略。若缓存中存在该资源策略,则流程结束。若不存在,则更新缓存,并发送消息,用于延时消费,更新数据库。可以看到思路仍然是以缓存作为临时数据源,降低对数据库的依赖,同时借助了消息队列的异步特性,来解决数据库恢复后,数据库数据与缓存数据的一致性问题。

3、缓存冗余更新和缓存一致性检测设计

高并发的业务场景下,数据库是十分宝贵的资源,也是非常薄弱的环节。系统设计时不可避免的需要使用缓存作为缓冲。上一小节针对数据库不可用的极端场景设计了方案,本小节将会提出两种解决缓存与数据不一致问题的方案。

1)  缓存冗余更新

缓存冗余更新是在数据发生变更时,通过同步与异步冗余更新的方式,保证不会出现脏数据,并且保证最终的数据一致性。

缓存更新基本架构

1-2-6-7即为一个常见的旁路缓存更新结构。但由于业务的复杂性,在播控变更服务执行完数据变更后,需要通过步骤3发消息通知外部系统,外部系统接收到消息后通过步骤4-5进行反查,但由于步骤3和步骤6-7都是异步过程,可能在6-7执行完成之前,3-4-5已经执行,则查询到的是更新之前的脏数据。

缓存冗余更新的思路是,变更服务除了通过消息异步更新缓存之外,同步的调用播控任务调度,去更新缓存。同步更新保证缓存数据的准确性,不会出现脏数据,异步更新保证更新链路的高可用,不会因为接口调用失败而导致缓存更新失败,达到最终数据的一致性。

2) 缓存一致性检测

缓存冗余更新是用来确保写入缓存时数据的正确性。除此之外,我们还提供一种写入缓存后的缓存一致性检测机制,专门检查近期写入缓存的数据是否符合预期,检测到不一致后进行上报和清理。

检测流程如下,利用guava cache设置5s过期机制,在数据变更写入数据库和缓存的5s之后,通过监听器监听guava cache的过期,来触发数据对比的检测,并根据检测结果做出相应的处理。

脏数据检测流程 

4、远端/近端调用动态切换设计

播控除了通过RPC调用方式为上游业务提供基础服务,还提供了播控SDK可以供业务方进行近端调用。近端调用对于业务方来说在降低延时,提高成功率方面都有很好的效果,对于播控来说也能减轻服务器压力,节省资源。但为了防止出现稳定性问题,也必须面向失败设计,提供降级方案,其中一种降级方案是流量动态切换方案。当业务方机器能够承受的SDK流量上限超过阈值时,多余的流量会动态分散到播控中心系统;这在实际中是很有效的,在一些单机QPS达到1000甚至更高的场景下,确保SDK不会压垮业务方机器。极端情况下,所有流量都可以回切到播控中心系统。

总结

一个优秀的架构师往往都是悲观主义者,除了设计好能够支撑业务持续发展的优雅架构,另一个容易被忽略的重要能力在于充分考虑失败场景。面向失败设计是一种十分重要的设计思路,需要能够防患于未然,在设计阶段考虑到各种失败场景,提前准备好预案,并且做好充分的演练和验证。只有这样才能够在失败来临时从容应对。

推荐阅读 

11 国股市熔断,“祸及”程序员?!

深度解读!阿里统一应用管理架构升级的教训与实践

2.2版本发布!TensorFlow推出开发者技能证书

Soul App 高管被捕,恶意举报导致竞品被下架

2020 年最新版 68 道Redis面试题,20000 字干货,赶紧收藏起来备用!

最近一个名为 BTCU 的比特币分叉,准备用新分叉解决比特币网络的旧问题

你点的每一个在看,我认真当成了喜欢

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

优快云资讯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值