这是 2015 年年初(羊年春晚)摇一摇流动的技术复盘文章。在数年之后再次复习,有很多架构上的取舍依然能够给相似的流动参考,因而从新收回来。
羊年春晚摇一摇流动曾经落下帷幕,当初回过头来看看这一全民参加的乏味的流动背地,有着怎么的后盾零碎?这个零碎又是如何被设计与实现进去的?
春晚摇一摇流动
在理解这个零碎之前,先看看羊年春晚有哪些流动模式?春晚摇一摇复用了摇一摇入口,但提供了全新的界面和交互内容。
在羊年春晚摇一摇界面里,用户摇动手机后,能够看到明星拜年、全家福、好友贺卡等精彩纷呈的流动页;也会有舒适的“劳动一下”,或让很多误以为中奖的“挂服务器”等非凡用处的页面。
大家最期待的必定是摇红包,摇中红包的侥幸用户除了本人领到一份红包(种子红包)外,还能够领到若干份用于分享给其余好友的红包(决裂红包)。
围绕这些流动,上面将会通过 4 个处于我的项目不同阶段的里程碑版本来介绍咱们设计、实现这一零碎过程中的一些思考和做法,特地是题目里提到的“有把握”是由何而来。
V0.1 原型零碎
原型零碎很简略,但曾经根本实现了春晚摇一摇的需要。原型零碎的架构见下图。
相干的解决流程如下:
- 用户摇动手机后,客户端产生摇一摇申请,申请发到接入服务后,会被转发到摇一摇服务;
- 摇一摇服务会依据现场节目的流程,通过一系列的逻辑判断,给客户端返回一个后果:明星拜年、红包或者其余流动;
- 假如是摇到了红包,因为红包都是企业资助的,须要对企业形象进行展现,客户端会从 CDN 拉回这个企业的 LOGO 等资源,最终展现出一个残缺的红包;
- 随后用户拆红包时,申请会进入红包零碎,再到领取零碎,最初到财付通零碎实现一系列简单的账务解决,最终拿到红包;
- 用户还能够分享红包,被分享的红包通过音讯零碎发给好友或群,其他人能够再抢一轮;
- 在这一过程中,平安零碎保障红包流动的业务平安。
上述数据的流动能够分下类:资源流、信息流、业务流和资金流。本文将次要聚焦在资源流和信息流。
面临的挑战
原型零碎看起来曾经足够简略,性能也根本齐备,是不是能够稍加批改后间接用在春晚现场呢?答案必定是不行。那么问题来了:为什么不行?
答复这一问题前,咱们先看一下看似简略的流动背地,面临着哪些挑战?
海量用户申请,预计申请峰值 1000 万 / 秒
**
**
1000 万 / 秒到底是多大的规模,能够通过下图更直观地感触下:
注:抢火车票数据援用自公开数据
春晚全程互动,不确定因素多
这个零碎须要跟羊年春晚全程严密互动,从我的项目开始到完结,有一系列的不确定因素会加大零碎实现的复杂度:在开发阶段,针对节目与流动模式如何配合这个问题的探讨有可能继续到春晚前,如何使零碎能服务多变的需要?在春晚现场,节目数量多,节目时长甚至程序都有可能调整,如何做到现场节目与摇一摇流动无缝连接?
零碎深度定制,成败在此一举
作为专为春晚设计的零碎,部署上线后真正能运行的工夫就只有几个小时,这几个小时内,惯例零碎所提倡的灰度公布、先扛住再优化等做法并不是太实用。在这短暂的工夫内,只有一次机会:要么胜利,要么失败。
全民高度关注,必须胜利
春晚会有 7 亿左右的观众,大家对这一流动抱有很大冀望,全民注目之下,只能胜利,不能失败。
短少历史教训,把握不大
如此大型的流动,对咱们而言是前所未有的,并没有太大的信念。前边提到的 1000 万 / 秒的峰值是如何估算进去?各个环节会有多少用户参加?零碎须要预留多少资源?这些问题不会有现成的答案,都须要摸索与思考。
可见,在看似简略的流动背地,暗藏了微小的挑战,之前假如的原型零碎不太可能胜任,须要做更深刻的优化。
须要优化哪些环节?比拟不言而喻的有三个:
流量带宽
春晚摇一摇须要用到大量的多媒体资源,这些资源都须要从 CDN 下载。通过评估,带宽峰值需要是 3Tb/s,会带来微小的带宽压力。即便咱们有有限的资源,带宽需要能被满足,客户端在摇一摇后下载资源所需的等待时间也会带来很大的用户体验侵害,是不可承受的。
接入品质
**
**
接入是后盾零碎的第一道关,所有申请都会达到接入。预计当晚会有 3.5 亿的在线,如何尽可能保障外网接入品质?甚至在外网稳定时也不受太大影响?
海量申请
1000 万 / 秒的申请从外网涌进来后,都被路由给摇一摇服务,也就是说摇一摇服务也将有 1000 万 / 秒的申请量。这意味着须要确保零碎内 2 个 1000 万 / 秒的高可用,在分布式系统内,这是个挺大的问题。
如果要对系统是否最终取得成功量化一个信念指数的话,这个原型零碎的信念指数是 10。这个数字示意如果春晚摇一摇采纳这套零碎并取得成功,咱们认为 90% 是靠运气。也能够换种说法:拿这个零碎到春晚摇一摇,90% 的可能会挂掉。
零碎必定不能以运气为根底,这几个问题如何解决?
V0.5 测试版
V0.5 的指标就是为了解决 V0.1 原型零碎里的几个问题。
资源预下载
春晚应用的资源比拟多,也比拟大,但根本都是动态资源,是能够提前几天下载到客户端的。保留到本地后,在须要应用的时候,客户端间接从本地加载,从而省去了集中在线下载所需的带宽需要,另外用户摇一摇时不再须要下载资源,能够有更好的用户体验。下图展现了资源预下载过程。
资源推送模块负责将资源上传到 CDN,同时推送资源列表给客户端。推送过程基于微信音讯零碎实现,能够在极短时间内把资源列表推送给几亿的用户。
资源预下载须要解决以下几个问题:
- 资源交付状况
- 资源更新
- 资源下载失败
- 资源覆盖率
- 离线资源平安
通过这套资源预下载零碎,2015.2.9 – 2015.2.18 期间,下发了资源 65 个,累计流量 3.7PB,其中闲时峰值达到 1Tb/s。
外网接入梳理
要保障接入品质,除了须要保障接入服务自身的稳定性外,须要做到:
- 具备在某些外网接入呈现稳定的时候,能主动切换到失常接入服务的能力;
- 保障网络与服务具备足够的冗余容量。
微信客户端曾经具备了外网主动容灾切换的能力,下边再看一下零碎的外网部署状况。
咱们从新梳理了外网的部署,最终在上海 IDC 和深圳 IDC 各设置了 9 个 TGW 接入集群。每个 IDC 都在 3 个不同的园区别离部署了电信、挪动和联通的外网接入线路。
另外,接入服务也进行了长期裁减,两地共有 638 台接入服务器,最多反对 14.6 亿的同时在线。
接入服务内置“摇一摇”
架构变动
后面提到,零碎须要面对预计 1000 万 / 秒从外网的申请,同时还须要在内网转发同样是 1000 万 / 秒的申请给摇一摇服务,除此之外,还须要在各种异常情况下确保高可用。在如此海量申请之下,在这个分布式系统中,任何一点网络或服务的稳定都可能是灾难性的,这里边的艰难水平可想而知。
侧面解决这一问题的老本过高,咱们抉择了去掉摇一摇服务——把摇一摇逻辑集成到了接入服务,从而去掉了 1000 万 / 秒的转发申请。
但这样做,有一个前提:不能升高接入服务的稳定性。因为不单是春晚摇一摇申请,微信音讯收发等根底性能的申请也须要通过接入服务来直达,如果嵌入的摇一摇逻辑把接入服务拖垮,将得失相当。
接入服务的架构刚好有助于解决这个问题。
如上图所示,接入服务有一个网络 IO 模块,这个模块保护了来自客户端的 TCP 连贯,收发数据,负责跟客户端通信。网络 IO 模块是作为独立的过程组运作的,收到的申请通过本机共享内存发给接入逻辑模块解决。接入逻辑模块也是一组独立运行的过程,通常状况下是由申请直达逻辑通过 RPC 把申请转发给其余逻辑服务器解决。当初摇一摇逻辑作为嵌入逻辑,整合到了接入逻辑模块。因为网络 IO 模块与接入逻辑模块互相隔离,能够独自对接入逻辑模块进行降级,不会影响到已有的网络连接,这大大降低了嵌入逻辑带来的危险。
但这样还不够,还能够把嵌入到接入逻辑模块里的摇一摇逻辑尽可能简化,只保留比较简单、稳固、只须要单机计算即可实现的轻量逻辑;把其余较简单、可能须要常常变更、或须要跨机拜访的逻辑独立为摇一摇 agent,作为独立运行的过程,通过本机共享内存与嵌入摇一摇逻辑通信。
摇一摇逻辑实现
接入服务架构的批改使得内置摇一摇逻辑变得可能,剩下的就是怎么实现春晚摇一摇逻辑?春晚摇一摇逻辑最重要的是摇红包,摇红包则须要重点解决以下问题:
红包如何发放?
所有红包都源自红包零碎,但为了在运行时不依赖红包零碎,红包系统生成的种子红包文件被提前部署到了接入服务。为确保红包文件不会被反复发放,有个文件切分程序实现不同机器的文件切分,每台机只保留本人须要解决的那局部红包;另外,为了确保红包不漏,还有另一个程序实现所有机器红包文件的合并校验。
摇到红包的用户如果抉择不分享红包,这些红包会被红包零碎回收,一部分作为种子红包经由摇一摇 agent 回流到接入服务进行发放。
摇一摇 agent 会依据预设的策略给内置的摇一摇逻辑提供可下发的种子红包。红包是每秒匀速下发的,能够准确管制全局红包下发速度,放弃在红包 / 领取零碎能失常解决的范畴之内。
怎么保障平安?
- 单用户红包个数限度
业务要求每个用户最多能够支付 3 个红包,并且每个赞助商最多 1 个。惯例实现里,须要在后盾存储用户支付记录,每次摇一摇申请时取出来计算,如果拿到红包还须要更新存储。但这里减少了对存储的依赖,海量申请下,稳定性不易保障。咱们借鉴了 HTTP 协定的 COOKIE,在摇一摇协定里也实现了相似的机制:后盾能够写入用户的红包支付状况到 COOKIE,交由客户端保留,客户端在下次申请时带上来,服务器再取出来判断。这就无需后盾存储也能够实现同样的目标。
- 破解协定的歹意用户
协定总是有可能被破解的,歹意用户能够制作自动机,绕开 COOKIE 检测机制。所以 COOKIE 检测机制只能用于绝大部分应用失常客户端的用户。对于破解协定的歹意用户能够通过在本机存储红包下发记录来打击。
- 游击战
尽管接入服务应用长连贯,但歹意用户能够一直重连,变换不同的服务器来获取红包,针对这种状况,咱们设计了红包发放汇总服务,能够在所有接入服务上同步曾经达到红包支付下限的用户。
以上策略顺次递进,后一步较前一步更深刻一层解决问题,然而在设计上,前一步并不依赖后一步,即便后边的步骤呈现故障无奈按预期进行,也不会影响前边的后果,在最差的状况下,零碎依然能够保障单用户红包个数限度的需要。
如何与春晚现场同步互动?
春晚摇一摇零碎须要配合春晚现场节目进行互动,春晚切换节目或者主持人进行流动的口播时,零碎都须要同步切换流动配置。
这里一是要求疾速,二是要求稳固。为此咱们设计了这样一个配置零碎。
春晚现场有一个配置前台,现场人员能够通过这个配置前台发送变更指令到后盾。后盾有上海和深圳两个接收点,每个接收点由处于不同园区的 3 组冗余的配置服务形成。配置服务接管到配置后会同步到另一接收点,同时以文件模式下发到所有接入服务。为确保同步胜利,应用了 RPC/RSYNC/ 变更零碎三个冗余变更通道来同时变更配置。从配置前台发动变更,到接入服务加载配置,全程能够在 10 秒内实现。
看起来疾速和稳固都满足了,是不是就曾经足够了?请思考以下异样场景:
- 春晚前台无奈工作或网络故障,指令无奈发给配置服务;
- 所有配置服务均无奈工作或网络故障,配置无奈同步给接入服务。
这些异样在春晚节目过程中长期呈现的话,个别状况下影响并不大,咱们能够长期手工变更配置,博得足够工夫去修复零碎。然而,如果此时主持人正在号召大家拿起手机抢红包,咱们是没有足够的把握能够在极短时间内实现全零碎的配置变更的,也就是说极有可能功亏一篑,要害配置变更不了,红包基本出不来。还有一种相似的场景,就是抢红包开始后,也因为配置变更问题,完结不了,没法切回其余流动,损坏用户体验。
针对口播抢红包这个关键点,咱们采纳这样的配置变更策略:应用抢红包倒计时配置,到点后主动开始抢红包时段,通过预设的工夫后,又主动完结。另外,因为春晚节目的口播工夫点具备不确定性,咱们制订了变更策略,在节目过程中能够逐渐校对倒计时。于是这一要害配置就只与工夫相干,机器工夫绝对容易保障,通过 NTP 就能够达到足够精度的工夫同步,咱们还对机器工夫进行集中监控,能够发现并解决机器工夫出现异常的机器。
预估带来的问题
至此,V0.1 原型零碎前边提到的三个问题均已解决,1000 万 / 秒的海量申请能够扛住。然而,1000 万 / 秒是预估的,如果最终来了 2000 万怎么办?4000 万呢?看起来数字有点不堪设想,但真有 1 亿甚至几亿用户在不停的摇,也还是有可能呈现的。
对于 2000 万 / 秒,咱们其实并不放心,接入服务通过一直的优化,能够在提供容灾冗余的根底上,仍有 2500 万 / 秒的吞吐能力。
然而 4000 万 / 秒大大超出了后盾服务能力,怎么办?
海量服务之道有个过载爱护,如果没法硬扛,能够做到自我爱护。简略的说就是前端爱护后端,后端回绝前端。
客户端在服务拜访不了、服务拜访超时和服务限速时被动缩小申请。
接入服务能够在发现某个客户端申请过于频繁时,会主动提早回包,间接达到拉大申请距离的成果,最终实现在后盾把客户端申请频率限度在正当范畴内;另外,接入服务会计算机器的 CPU 应用状况,CPU 使用率达到不同预设阈值时,会主动返回不同品位的限速给客户端,通过客户端配合实现限速。
通过这些措施,在申请量超预期时,零碎会主动降级,从而实现自保。
综上,能够失去 V0.5 测试版的架构,信念指数 50。
V0.8 预览版
外围体验是什么?
为什么 V0.5 测试版的信念指数只有 50?还有哪些没做到位?
反思一下,能够发现:V0.5 测试版次要聚焦于如何解决海量的摇一摇申请,让用户能够欢快的摇出红包,那摇出红包之后呢?V0.5 测试版并未对这个问题作进一步的思考。
先看一下摇一摇的外围体验——摇红包,摇红包波及摇到红包、拆红包、分享红包、好友抢红包等等步骤。
稍加剖析即可发现,前三步是自己操作,后续是好友操作。从自己操作到好友操作之间是有肯定时延的,这也就意味着这里其实能够承受肯定水平的有损体验——延时。
V0.5 测试版曾经解决摇红包的问题,剩下就看拆红包和分享红包了。
如何确保拆红包和分享红包的用户体验?
能够把拆红包和分享红包形象一下,它们都是由两个局部组成:用户操作(信息流)和后盾的红包解决逻辑(业务流)。对用户来说,他关怀的是操作是否胜利,而不是后盾的红包解决逻辑。因而这个问题能够进一步简化为:如何确保拆红包和分享红包的用户操作能胜利?
咱们在用户操作和红包解决逻辑之间退出了一个中间层。这个中间层包含红包简化逻辑和红包异步队列,实现了信息流和业务流的异步化和解耦。
红包简化逻辑
通过一些算法设计,红包简化逻辑能够通过本地计算实现对红包申请是否非法的初步判断,非法申请放入异步队列,而后就能够返回客户端解决胜利;
红包异步队列
红包异步队列存储来自简化逻辑的申请。在存储上,异步队列应用 3 机计划,3 机写 2 份胜利即算入队胜利。异步队列的解决逻辑会从队列取出申请持续发动对红包零碎的调用,实现后续的红包逻辑。在红包系统故障时,会有妥善的重试策略,确保在零碎复原后重试胜利。
接入服务、红包简化逻辑服务、红包异步队列形成了所谓的“铁三角”,能够在红包零碎呈现重大问题时,爱护用户体验在较长时间内根本不受损,争取到修复故障的宝贵时间。
其实再认真思考一下,“铁三角”还能够做得更强:把红包简化逻辑再次拆分为根本的业务逻辑和本地透传队列。业务逻辑实现红包合法性校验后,把申请写入本地文件队列,本地文件队列再透传给红包异步队列实现后续解决。这样即便红包异步队列出现意外抖动,也不会影响到用户操作后果。
V0.8 预览版曾经根本成型,信念指数达到 70。
V1.0 正式版
大家晓得设计≠实现,为保障最终实现和线上零碎运作合乎设计预期,咱们还做了:
全程压测
未经压测的零碎是很危险的,无奈真正理解零碎在压力下的体现是否合乎预期?零碎的极限在哪?为此,咱们建设一个压测环境,对系统进行不间断的压测。零碎部署后,在现网环境也进行了多轮实在压测。
专题 CODE REVIEW
多部门联结做了专题 CODE REVIEW,在代码层面对要害门路做了认真的评估。
外部演练
客户端公布流程较长,全面铺开版本须要更长的工夫,做不到像服务器一样能够迅速上线 fix 问题。因而在公布客户端前,除了测试外,一次次的实在演练是十分必要的。
线上预热
在 2015.2.12 和 2015.2.15,最终争取到了两次预热的机会,对系统进行了实战验证。
2015.2.12 | 2015.2.15 | |
---|---|---|
摇一摇总次数 (次) | 3.1 亿 | 4000 万 |
摇一摇峰值 (次 / 分) | 5000 万 | 1700 万 |
摇一摇峰值 (次 / 秒) | 100 万 | 43 万 |
发放红包速率 (个 / 秒) | 5 万 | 5 万 |
因为预热规模的起因,摇一摇峰值并未达到预估值。但发放红包的速率始终维持在 5 万 / 秒的预设值,对后端“铁三角”和其后的红包零碎进行了充沛的测验。
复盘与调整
每次演练和预热都是难得的机会,不仅那些出异样的模块,那些看起来体现失常的模块,也能够通过复盘和推演,确认是否完全符合预期,挖掘出可能的隐患点,进而解决。
最终,咱们公布了 V1.0 正式版。
V1.0 正式版架构上与 V0.8 预览版并无不同,然而信念指数加到了 80。
咱们认为剩下的 20% 里,有 10% 体现在对突发状况的预案与现场处理。零碎如此宏大与简单,是不是还有没想到、未裸露进去、还做得不够或者在无限资源内无奈解决的问题?这些问题一旦如果呈现了,是不是有可能最终左右了整个场面?所以最初的 10% 就是靠运气,别呈现这些问题。
后记
本文转自微信后盾团队, 如有进犯, 请分割咱们立刻删除
OpenIMgithub 开源地址:
https://github.com/OpenIMSDK/…
OpenIM 官网: https://www.rentsoft.cn
OpenIM 官方论坛 :https://forum.rentsoft.cn/
更多技术文章:
开源 OpenIM:高性能、可伸缩、易扩大的即时通讯架构
https://forum.rentsoft.cn/thr…
【OpenIM 原创】简略轻松入门 一文解说 WebRTC 实现 1 对 1 音视频通信原理
https://forum.rentsoft.cn/thr…
【OpenIM 原创】开源 OpenIM:轻量、高效、实时、牢靠、低成本的音讯模型
https://forum.rentsoft.cn/thr…