抽奖活动的高可用、高并发优化

您所在的位置:网站首页 王者积分抽奖一天最多50次嘛 抽奖活动的高可用、高并发优化

抽奖活动的高可用、高并发优化

2024-07-13 13:07| 来源: 网络整理| 查看: 265

这几年工作中做过不少营销活动,这里以抽奖活动为例,讨论一下如何设计出一个高可用、高并发的营销系统。

高可用、高并发架构的核心是分流和限流。系统架构时,应根据每一种营销活动的场景与特性,制定不同的分流、限流方案。

一 业务

在开始进行架构讨论前,我们的简单描述一下业务,以方便我们有针对性的进行讨论。

1.  业务需求

公司希望拉更多的新用户来注册我们的app,所以想通过一个抽奖活动,用一些奖励和刺激的手段来促使用户使用我们的app,并通过奖励手段让用户帮我们一起推广宣传。业务主要诉求如下:

用户需要在app中或者活动页面(H5)中进行某些操作,以获取抽奖机会;例如分享给好友以后奖励一次抽奖机会。

每天每人最多拥有N次抽奖机会。

活动结束后给中奖用户发奖品。

每个人只能中一次奖。

  ……

 

2.  抽奖主流程

840f6d75934584c58173a602062d37132385b83a

这是系统的核心流程,也是后面进行性能优化的核心内容。

 

3.  分析

对活动而言,最重要的是曝光量,只有更多的分享与传播,才能让更多的人参与进来,活动效果才越好,对技术上的要求就是能够提供尽可能好的用户体验。

抽奖活动的页面中,大部分内容都是静态的,只有抽奖按钮需要与服务端交互;对此可以通过客户端、CDN缓存等提升用户体验。

营销活动是拿真金白银来推广,所以需要有效的机制能防止被人恶意攻击,将全部奖品刷走。

如果活动中奖品价值都较高,此种情况下,通常奖品数量有限,中奖概率不高,所以即便是抽奖的并发量较大,实际写DB的压力也并不大,即在扣减奖品库存、向DB中插入中奖记录等环节的写压力并不会大。

如果活动发放类似于优惠券的虚拟奖品,数量可能很大,中奖概率非常高,那么当抽奖并发量大时,写DB的压力会很大。

 

二 核心指标 1.  高并发

营销活动对系统性能的要求,一般来说比常规业务高出很多;如果推广的效果比较好,流量可能会远超初始预期。基于此,系统应该能够支持较高的并发,并且在流量快速上升并超过容量规划时,能够及时、方便扩容。

2.  高可用

核心是提供尽可能好的性能支持,让更多人能够使用我们的产品。具体见高性能优化部分内容

3.  隔离性

营销活动不能影响常规业务;因为营销活动变动频繁,修改时应尽可能的避免影响到其他业务;前一次活动应该能够沉淀出一些内容,降低下一次类似的活动的实现成本。

4.  低耦合

根据上面的需求我们可以看到,营销活动旺旺与主业务有交集。营销活动的特点是变化频繁,定制化需求多,应尽量降低营销活动与常规业务的耦合性。

可以考虑通过旁支流程来解决此问题。例如,用户在app上操作以后奖励抽奖机会这个业务,将用户的行为作为事件,通过MQ消息向外广播,营销活动监听相关的MQ消息,根据MQ消息给用户奖励抽奖机会。

5.  防刷

在营销活动利益的驱动下,常常会有人找系统漏洞,钻系统空子,通过一些手段来刷系统奖品,影响营销效果。一般而言,有以下常规问题需要防范:

防恶意注册用户

防恶意调用接口

防奖品被少部分人获取

防用户误操作

三 架构

高并发的核心思路是逐级分流,逐步分散流量。

高可用的核心思路是通过备份、限流、降级、熔断等手段提升可用性。

1.  整体思路

充分分流,通过缓存、队列、消息等手段将大流量逐步分散。

以空间换时间,通过缓存来提升每个请求的处理速度,提升系统并发量。

异步处理,分析并识别出可以异步处理的逻辑,将他们异步化。

分层逐级拦截非法请求,仅让有效的请求到达底层系统;尽可能让每一次写操作都能成功。

根据每个系统的服务能力,设定流量极限,流量超过极限值后进行限流。

 

2.  分阶段优化模型

为了达到最高的并发性能,需要对整个环节的各个环节进行优化。现实中往往通过如下的倒三角形模型来逐层优化。

8ad242c113e31024c2c04befc82853c6ab9e20eb

注意:这里不过多讲述概念性的内容,而是根据抽奖的需求讲述一些常规的方案;更多内容见博客《高并发技术》

客户端优化方案有:客户端(app、浏览器)缓存。

网络优化方案有:动静分离、静态化

服务端优化包括:缓存(硬盘、堆、分布式)、通信模型优化、异步化技术、线程池、DB存储优化。

响应优化包括:返回结果压缩。

3.  缓存策略

通过分层缓存策略,对每一个环节进行有优化,提升性能。

07ea62551eae0ebc905a001432c399ef39b8f6c7

客户端(或浏览器)缓存:减少用户请求数量,降低系统压力,提升用户体验。

CDN缓存:合理地利用CDN,内容缓存放置在离用户最近的地方,加快响应的速度。

Web服务器缓存:减小后端应用服务器压力,抵挡瞬间峰值和/或针对少量定点内容的攻击。

应用层缓存:减小后端应用服务器压力,加快响应速度。

 

4.  分流模型

13c8ff107f5dac5fffd4e930bb974a5b65459bd9

从图中可以看到,经过前面的逐层分流,最终只有少部分请求会进行DB操作。当绝大部分的流量都被通过种种手段分担,系统自然就可以轻松处理剩余的少量流量,这也就意味着系统可以具有非常高的性能。

 

四 高并发优化 1.  逐级分流 1)   客户端缓存

我们的营销活动都是通过H5来承接的,app通过webview来加载或者直接通过浏览器加载数据时,可以利用浏览器缓存或者手机SD卡,将数据缓存在客户端,例如图片、CSS、JS文件等。

越多的内容从本地缓存读取,响应速度会越快;不过需要注意缓存数据的更新问题,以及内存占用问题。

 

2)   动静分离

一个抽奖活动页面,绝大多数树内容都是静态的图片、css、js等,极端情况下可能只有一个抽奖按钮需要与服务端交互。通过将图片、css、js等内容存储在CDN节点中,用户浏览活动页面时,直接从距离用户最近的CDN节点获取静态资源,不用和服务端交互。优化模型如下:

fd9ce264ceabe0898b44b6418d25538ae00dac26

在营销活动的场景中,使用此种方案时,至少可以让90%-95%的流量不用与服务端交互,可以节省大量带宽,对性能提升非常明显。

 

3)   防误操作

用户点击抽奖按钮,调用服务端接口时,当请求的响应速度比较慢时,如果客户端不做处理,用户会感觉到卡顿;此种情况下用户和可能会反复点击抽奖按钮,这无疑会进一步加大服务端的访问量,服务端的响应速度可能进一步降低;另外因为每点击一次都需要消耗一次抽奖机会,因一次卡顿导致用户耗费多次抽奖机会也是不合适的。

这种问题的处理方式比较多,例如:可以通过在H5端通过js控制,点击抽奖按钮以后,在请求返回之前将按钮置灰,禁止用户再次点击或者弹出一个loading动画来解决此问题。

这种方案在服务器压力大,响应慢时效果比较明显;另外,可以明显的提升用户体验。

 

4)   防代码请求

如果活动的奖励足够吸引人,就可能有第三方通过代码直接调用抽奖接口。因为代码的执行速度远快于手的点击动作,这可能给营销活动带来非常大的危害,同时也会给系统带来非常大的并发压力。因为风控的性能损耗较大,所以在营销活动中一般不能通过风控系统来解决此问题。

一般而言,每一家公司都会有自己的安全策略,保证请求的安全可靠,应尽可能让第三方伪造此流程的难度加大;除此之外,运营活动中要能够识别出异常流量,做好应对措施,尽可能的降低危害。

a)    伪造一个用户

多个线程中都使用相同的用户进行请求。这种场景比较好解决,通过userId加一个分布式锁即可解决。

b)    伪造多个用户

每个线程使用不同的用户进行请求。这种比较麻烦,常见处理手段有:

在用户注册时加限制,尽可能杜绝通过代码自动注册的行为,让每一个注册的用户尽量可靠。

和业务沟通,限制每个用户每天获取抽奖机会的次数,限制每人中奖次数。

抽奖机会通过用户的行为产生。例如:到社区对帖子评论以后才给一次机会,这将增大用户伪造请求的难度。

如果发现一定时间内某个ip下的流量明显异常,可以对此ip进行限流。例如:一个ip的请求量超过1000/min时,拒绝此ip的请求。注意,此方案可能有误判,因为当多人使用同一个局域网时,此时服务端收到的ip可能是相同的。

添加小黑屋功能,发现恶意用户、ip,将他们拉入小黑屋,一段时间内禁止他们后续的访问。

5)   业务规则拦截

根据前文中的需求我们可以得出:同一个用户只允许中一次奖;每天最多抽奖三次。当收到抽奖请求时,我们可以判断是否符合这这些规则:

可以将中奖用户放在缓存中,收到抽奖请求或抽中时,通过缓存校验此用户之前是否已中奖。

可以将抽奖次数放在缓存中,通过计数器自减的方式扣减抽奖机会。

2.  缓存

大量的运算将消耗大量服务器资源,频繁的DB操作也会给DB带来较大的压力,在高并发场景中,常常通过缓存运算结果或者DB记录,以降低资源消耗,提升请求的响应速度。

1)   缓存不常变动的数据

缓存非常适合存储不经常变动的数据,通过缓存他们可以极大的提升性能。

如,活动中奖品一般不会频繁改变,页面中需要展示奖品信息时,我们可以将奖品信息加载到缓存中,每次请求时直接读取缓存。

2)   缓存实时性要求不高的数据

业务上如果对某些数据的实时性要求并不高,那么也可以通过缓存降低系统的性能损耗,提升请求速度。

如:活动中需要播报中奖信息,业务上并不要求实时展示最新中奖的几人,所以可以通过启动一个线程,将最近一段时间内需要播报的名单加载到缓存中,播报时从缓存中直接返回数据。

3)   频繁变动的内容走缓存

频繁变动且持久化意义不大的数据非常适合走缓存。

如,用户完成一些任务以后,奖励一些抽奖机会,奖励的抽奖机会就很适合存储在缓存。使用redis或者tair的原子性加、减操作,每奖励一次抽奖机会,自增1,每抽奖一次,自减1。

4)   从缓存减库存

抽中奖品时,需要将此奖品总数减1,这其实就是一种减库存操作。并发情况下从DB中减库存,一来性能比较差,二来为了避免脏写可能导致DB更新失败概率大增。此时改为从缓存中减库存。

a)    减库存

活动开始前,将奖品库存加载到缓存。

抽奖时直接从缓存中扣除;如果扣除库存以后,剩余奖品数量>=0,表示扣减库存成功,然后发送MQ消息;如果库存扣除后,剩余奖品数量



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3