春节红包活动如何应对10亿级流量?看大佬复盘总结
导读:本文整理自高可用架构与数列科技联合举办的技术沙龙,数列科技资深架构师徐汉彬的主题演讲。围绕“峰值流量下的高并发实践”,主要介绍了其在某知名互联网大厂会员活动平台的高可用架构实践。以下为演讲摘录。
”
今天分享的主题的是《面向大规模流量活动的高可用架构实践》,在开始之前先做个简单的自我介绍,我叫徐汉彬,在进入数列科技之前负责过QQ会员活动运营平台,把这个平台从日PV百万级别做到10亿级别,在应对大流量活动这一块积累了一定的经验,今天就这个主题方向跟大家做一个探讨。
分享的内容主要分为三个部分:
1.大流量活动的系统扩容评估方法
2.系统高可用架构设计实践
活动的流量来源,包括内部资源、外部付费购买的广告资源和第三方合作导流。公司在活动上投入了大量的资金,参与用户众多,如果活动中途出现问题,不仅对产品口碑的影响非常负面,而且会有金钱损失,还涉及到与第三方合作失败的问题。
举个例子,假设你的活动跟春晚合作,春晚到了某个环节让大家拿起手机现场扫码,这时系统挂了,扫码失败,这种情形就非常尴尬。遇到这种情况,第一个找你的可能不是你的领导,而是外部的第三方合作商,由此可见,关键时刻的系统高可用有多重要。
大流量活动面临的挑战主要分为三个部分。
第一个挑战是流量评估难,扩容的量级并不是张口就来,如果你跟运维说要扩充10倍容量,他一定会反问你为什么,你要拿出扩容的合理依据。
第二个挑战是架构扩容难,即使我们评估出了比较准确的流量峰值,又该怎么进行系统扩容呢?现代IT系统架构的复杂度越来越高,尤其是现在流行的微服务架构,它的节点数越来越多,服务之间的调用关系非常复杂,链路的梳理本身也是一大难点。
第三个挑战是怎么进行高可用实施,我们把流量评估和链路梳理扩容都做好了,活动在大流量到来的那天就没有问题了吗?当然不是,所以第三个问题就是怎么进行高可用实施。
想要解决上述挑战,绕不开业务和系统的双重复杂度问题。 微服务架构的复杂性,加之业务的复杂性,使得整个系统错综复杂、难以被人类理解。即使是公司的架构师、业务研发同学也很难讲清楚系统整个链路的每一个细节和服务之间的调用关系,因为此时的系统已经是一张庞大又相互交织的的网络了。
要解决流量评估的问题就得进行精细的链路梳理,梳理的第一步就是画架构简图,把每个架构大的模块画出来,再根据架构简图进行业务功能链路拆解。
部分链路图
链路图梳理完成后,我们就可以开始预估扩容量了,这里涉及到三个重要的指标:推广量、环节转化率、单UV的请求总数。
第一个指标推广量,一般情况下会以每秒广告的曝光量计算。将不同广告渠道的曝光量加起来就能得到预估的推广量级了。 还有一种方式是计算APP应用高峰每秒用户的登录数,这个数值约等于推广的每秒曝光量。 一般预测的每秒推广量都在系统现有容量的10倍以上,按这个推广量去扩容,系统基本没有问题,但会它会造成比较严重的资源浪费。
这时则需要用第二个参数来辅佐我们进行更细致的评估,它叫做环节转化率。以红包活动为例,用户看见红包活动,但不一定会点击进入页面,进入页面也不一定会领取红包,每一个环节都有环节转化率。 预估环节转化率一般有两种方法,一种是依据过往的经验数据进行估算;另一种就是提前演习,提前给部分用户推送活动,快速准确地收集到每一个环节转化率,有条件的公司一般会采用这种方式。
还有一个参数是我们需要特别注意的,就是单UV的请求总数,为什么要特别关注呢?
因为用户进入一个活动页面,他可能会查询个人信息、查看活动记录,通常不止一个请求动作,所以你在计算后端压力时不能只算用户进入活动的每秒峰值,还要算上其他请求动作。假设用户平均有4个请求动作,那你的流量就要乘以4,它有一个放大效应。
通过前面3个指标我们就能计算出后端会承受多少流量压力,进而得出扩容的预估值。最后把扩容容量设置为预估值的3倍,这个3倍并不是凭空臆想,而是从过往大量的活动扩容经验中总结得来的规律,活动当天的峰值通常是常规均值的3倍。
具体怎么计算咱们来举个例子,假设我们是100/S的曝光量,只有60%用户进入了领取页面,这其中又只有50%点击了领取按钮,那后端收到的请求是30/S,根据单UV的请求总数来说,整个后端最少要支撑120/S的压力,加上3倍原则那么后端最终的扩容也就是360/S。领取页面的流量峰值则为180/S,这时你带着数据去找运维扩容就有理有据了。
某活动容量评估得到结果是9.6W/S,根据三倍原则,整个业务链路要扩容到30W/S,但是,在实操扩容过程中会发现部分应用很难扩容。举个例子,像Web server这种很容易做平行扩容,只要机器足够就可以扩容上去,但有些接口日常也就2000-3000/S的QPS,要扩到10万QPS基本就是不可能的,也没有那么多的资源和精力。这就涉及到扩容的具体实践了,也是我们接下来要说的系统高可用架构设计的实践内容。
全链路QPS最容易被大家理解,我们也最关注,就不做过多的展开。
机器带宽问题,流量越大越容易遇到。假设CGI请求达到10W/S,通常它的请求存储不是一次,当时我们的常规业务请求存储高达7-8次,包括查询活动配置、查询用户参与记录、查询其他关联信息等。这个10W/S就意味存储端需要承受大几十万每秒甚至百万每秒的量,如果一个存储占1KB或者大几百KB,在这个量级下存储数据就相当庞大了,使用百兆级别网卡显然就会遇到网络带宽瓶颈问题。
接下来说说存储大小,这里说的存储大小通常不是指硬盘的存储大小,而是指内存,它也比较容易遇到瓶颈。大多数公司有使用Redis类的Key-value存储,也有部分公司使用自研的Key-value存储,通常写入的数据会先写入内存,再通过定时淘汰机制,同步到本地的SSD或者磁盘。在大流量场景下,内存很容易被写满,如果没有事前评估,活动当天几百G的内存会瞬间被写满。
还有一个不得不提的内容就是静态资源,它是我们网页请求的图片、JavaScript和CSS样式,通常它的瓶颈不在系统本身。一般情况下,如果不考虑带宽的限制,在一台配置很普通的机器上搭建一个Nginx来压测静态资源的请求性能,可以轻松达到数千QPS。但是,如果考虑到静态资源的大小,加上单个用户打开一个页面就会请求很多静态资源的实际情况,请求的静态资源的大小很较容易就超过1M了。这时第一个撑不住的就是机器的出口带宽,而不是静态资源服务器本身的性能。
针对静态资源问题,我们有常用的应对方法——离线包推送机制。在活动开始前几天就把静态资源推送到活跃用户的的手机里,这样活动当天九成以上的流量都是本地的,他根本没有发起网络请求,以此来解决CDN的请求压力,解决带宽问题。
完成扩容只能说在理论上没问题,接下来说说高可用架构建设的关键要点。概括起来就是几个点:过载保护、柔性可用、容灾建设、轻重分离、监控体系、数据对账。
监控体系很重要,我们需要探知这个系统处于什么状态,并且出现问题时需要一些方案去应对它。
前面的分享提到过一个问题,有些接口日常也就2000-3000/S的量,没有那么多的资源和精力扩到10万/s, 那怎么办呢?
关于系统链路架构优化,我们常用的方式有三种,第一种是异步化,这个好理解,暂时没有这个能力执行完,就放到消息队列里慢慢消化。第二种是内存级的缓存,把需要访问的数据提前放到内存级的Cache里。第三种是服务降级,这个比较常用,就不做过多介绍了。 通过这些方法就可以把链路的性能提升起来。
关于过载保护它的的核心目标是部分不可用至少比彻底不可用户要强,主要的实现手段是进行分层流量控制。这些层级包含推广层、前端层、CGI层和后端服务层。针对推广层,只能在最坏的情况使用,因为它要对广告进行下架处理,不到万不得已,公司也不愿意采用这个方式,它也会影响活动的业务效果。针对前端层,可以实现随机弹出倒计时,限制用户1分钟内不能发起新的网络请求,有助于削平流量峰值。其他流量控制层的实现大同小异,不做过多的展开。
关于部署,我们应该把重要的核心的一些操作给保护起来。例如,在上述案例中,比较重要的是发货,它不应该被其他操作影响。如果查询操作不可用,用户再刷新一次页面就好了,但如果发货不到账,用户会直接投诉,所以上述案例就把发货操作拆出来独立部署了一套异步发货集群。
柔性可用我们应该怎么实现呢?
一般有两个方向,第一种是设置超短的超时时间,例如,给安全接口设置超时时间为30毫秒,假设那天安全接口真的挂了,30毫秒对于一个百毫秒级别的请求来说,用户也不太能感知到,活动的体验还是好的。另外一种,就是直接不等网络回包的方式,例如UDP服务。
针对监控与对账,我们必须建立多维度的监控体系,在流量峰值的压力下部分监控可能会出现问题,多维度的监控能帮助我们探知系统的真实状态,有助于我们采取正确的应对措施。
关于对账能力,假如发货失败了,当天值班的同学需要看跑线上日志和写补发脚本,那么半个小时、一个小时就过去了。值班同学通常都比较忙,所以最好的方式就是提开发好,当天如果发现问题,它就能自动去检测失败的日志并且进行补发。
第一个案例是某年某业务的春节红包活动,尽管前期做了非常多的准备,活动上线时还是出现了一系列问题,但好在都在我们的预案之内,算是有惊无险。
事后我们也进行了反思回顾,出现那么多问题是为什么?首先就是没有遵循3倍扩容原则,再比如说链路梳理没有到位,下面就是我们的一些总结内容。
根据我们的过往经验,最危险的活动反而不是大型活动,因为为了确保大活动的顺利开展,公司会抽调很多骨干参与进来,即使出现问题通常也是小问题。而中小型活动的流量不会太大,没有什么威胁。最容易出问题的恰恰是那些中大型活动,接下来详细讲讲另一个中大型活动案例。
在某游戏的年度活动项目中,我们做了一些评估和准备工作,但不可能对待每个活动都像对待春节红包活动那样。当时我们派了2个人看了一下,各个线上模块团队负责压测各自的模块,都反馈没问题,活动就上线了。活动当天凌晨我被电话叫醒,系统出问题了,当时有很多用户已经无法参加活动了。
当时的Web系统是基于PHP和Apache,采用Apache的多进程模式(perfork)。一个后端服务响应时间一般在几十毫秒,一个worker进程1秒钟应该可以处理十多个请求,但到了高峰时期,在大流量的压力下,后端服务的响应时间从几十毫秒飙到了几百毫秒甚至是1秒。这个时候1个wrker进程1秒钟只能处理1个请求,无法及时处理最终导致请求堆积。我们趁着玩家在凌晨的休息时间去做了不少补救工作,包括降级及其他的动作,经过一个通宵的努力,用户可以正常进入活动了,但还没有完全解决。第二天下午我们又到公司继续,48小时连轴转重新发版后终于解决了问题,安稳度过了那次活动危机。这种大中型的活动最容易出问题,因为通常我们不会给与足够的关注度。
总结一下大流量活动前期需要做的一些总体的经验和流程,首先是相对合理的评估&梳理方案,再进行架构上的优化和调整,最后就是整理紧急预案。
我连续参加过三年春节红包活动活动,每一年都提前大概一个多月召集核心骨干来出具方案,每年都做很多准备,可每年都有一些小问题。
反思为什么投入大量人力物力资源,系统还是出问题? 究其本质,我觉得主要是三个方面:第一很多时候测试环境、甚至性能环境无法代表真实的生产环境;第二,各个局部高可用不代表整体高可用;第三是系统的成长性,复杂的业务系统在持续迭代、膨胀,今天没性能问题,不代表明天没问题。
想让生产环境的性能获得保证,不出问题,从这个点出发我们有一个明确的探索方向——常态化的生产环境性能测试。
大量的准备工作都是为了保证线上环境能够达到一定的性能指标,所以最好的方式就是直接在生产环境去做最真实的性能测试。比如选在凌晨两三点钟没有什么业务流量的时候执行性能测试,看系统能不能达到我的目标性能。
那想要真正做到在生产环境实施性能压测有哪些关键点呢?
主要有三点,测试流量识别、测试流量标识的传递以及最重要的测试流量隔离。做生产环境压测避免不了涉及一些写入请求,如果把大量虚假的数据写入生产环境数据库肯定不合适,后续还要去做数据清理。所以只要前面提到的三个关键点能够解决,在线性能测试就能实现。
这是我们基于JAVA做的一套性能测试平台,因为我们可以在JAVA有中间字节码这一层做增强,通过agent探针在不侵入用户业务代码情况下去做一些控制。正式流量保持不变,我们会对压测的流量做一些控制。举个例子,比如说系统有一个mysql数据库,我们就会在线上建一套影子数据库,跟原来数据库一样,只是数据可能少一点或是空的(只有表结构)。当有流量进来时agent就会进行识别,识别出压测流量时,agent会把连接的数据库替换成影子数据库。 无论是消息队列还是Cache存储都可以用类似的方式来实现。
另外我们还做了一个东西叫挡板,它是干嘛的呢?假设有个第三方的短信接口,业务流量去调用这个接口是可以的,但测试流量直接去调用肯定是不行的,因为第三方不可能配合你做一个影子发短信的系统。挡板的作用就是通过agent来实现一个mock,在调用第三方接口时直接返回,防止测试流量调用第三方接口时对生产数据产生影响。
这是数列的生产环境全链路性能测试的方案,在此基础上我们还研发了链路自动梳理的功能。对于复杂业务以及复杂系统,它内含很多个微服务节点和业务节点,没有人能完全搞清楚整个链路的所有的环节。我们可以通过agent探针,利用技术手段搞清系统链路流向,协助进行链路梳理,与业务相结合就能梳理出业务调用的链路。结合E2E巡检平台不仅能够知道这条链路的性能如何,还能定位到具体环节的具体性能瓶颈,方便及时准确地进行性能调优,梳理业务链路视图,最终实现系统的高可用目标。
参考阅读
原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。