移动 > 游戏 > 手游

小游戏如何应对大流量?Shopee Shake 的大促实践

153人参与 2024-08-04 手游

背景

1. 游戏与大促

每年 shopee 会在五至十二月的每个大促节点举行电视直播活动。每次大促活动时,各市场的运营人员会与当地电视台合作,在节目直播过程中插入一段玩 shopee 小游戏的互动环节。

1.1 大促游戏的选择

在大促筹备阶段,当地运营人员会根据大促时间表,在游戏管理平台设置游戏活动的开始时间、结束时间、奖池及页面素材。待大促进行时,电视台主持人将引导用户打开 shopee app 并进入小游戏页面。

当地运营人员会根据大促计划,从多款小游戏中选择几款参与到电视直播大促当中,而 shopee shake 是被使用次数最多的大促小游戏,几乎每次大促活动都会出现它的身影。通过这款游戏,当地运营人员可以发放 shopee 金币,吸引用户在 shopee 下单购买商品。

每次大促时,shopee shake 都会带来大量用户流量。2021 年 5.5 大促时,该游戏接口最高 qps 达到 30 万+,在大促过程中发挥了重要的引流作用。

1.2 shopee shake

shopee shake 是用户通过在游戏页面摇动手机,获得 shopee 金币的类似摇一摇的小游戏。用户摇动次数越多,得到金币的概率越大。下图展示了三个不同阶段的游戏页面:

最左侧是游戏预热阶段的页面。游戏开始前,用户进入这个页面后,可以看到金币池的大小和游戏开始的倒计时,也可以将页面通过第三方或发送消息的方式分享给好友,获得额外金币奖励。

中间是游戏过程页面。游戏过程中,该页面会不停掉落金币。用户需要在有限的时间内摇动手机。摇动速度越快,得到金币的概率就越大。

最右边是游戏结果页面。用户在当局游戏获得的金币数量会显示在这一页面。另外,由于每一局游戏会消耗一次机会,剩余游戏机会在此页面也有直观呈现,若用户还有机会,可以直接点击按钮,继续进行游戏。有时,当地运营人员还会配置一些抽奖机会,如果用户抽中了某项奖品,同样会在这个页面显示。

2. 技术方案

从游戏机制来看,shopee shake 的后端系统面临以下几项挑战:

因此,我们的技术方案需要支持高并发请求,支持水平扩容,并解决潜在的奖池单点问题。

2.1 架构设计

从产品特点来看,shopee shake 系统主要提供两大功能,分别是供当地运营人员进行大促活动配置,以及供 shopee 终端用户玩游戏获得金币。

相应地,系统也分成两端,即 admin 管理端和用户端,分别面向当地运营人员和 shopee 终端用户。

在大促前,当地运营人员会通过 admin 端进行游戏相关配置。活动进行时,用户通过 shopee 终端访问游戏页面,请求后端。其中,最重要的两个请求是“游戏开始”及“游戏结束”请求:

综合以上考虑,shopee shake 系统整体架构分为三层,即接入层、应用层和资源层。

2.2 高并发技术

为了应付高并发的情况,shopee shake 的后端系统采用了很多高并发技术。这些技术并不是在最初设计时就被采用,而是经过不断的“踩坑-优化”,慢慢迭代而成。优化方案可能不是最优的方案,但都是结合产品特性,综合权衡得到的结果。下文将着重介绍几项主要的优化方案。

2.2.1 水平扩容

为了支撑大流量,我们的游戏系统需要支持水平扩容。只要支持水平扩容,就可以通过增加机器数量来提高系统可承载的吞吐量。

系统支持水平扩容,这就要求系统的接入层、应用层和存储层都支持水平扩容。

其中,接入层和应用层可以做成无状态服务,以支持水平扩容。但存储层支持水平扩容是不容易的,需要将存储数据均匀分布在不同存储节点上。

shopee shake 系统采用 codis 作为存储层,主要考虑到了以下几个因素:

由上面几点可以看出,codis 作为该游戏的存储层是非常合适的。

但并不是说只要使用了 codis 作为存储层,就支持水平扩容,还需要想办法将数据均匀分布在不同的存储节点上。我们最初设计游戏时并没有注意到这一点,以致于系统在大流量压测的时候出现了瓶颈。后经分析发现,codis 集群有一台 redis 实例的 cpu 使用率达到 100%,原因是游戏的金币库存使用的 codis key 是单点 key,超出了单台 redis 实例性能上限。在流量较小的时候,这并不是问题,但放在大流量场景下,会导致整个系统的性能瓶颈。

在 shopee shake 游戏中,金币库存供所有用户共享,所有用户端在游戏结束时都会并发查询及扣减这个库存值。当库存低于指定值时,游戏会提前结束,目的是防止库存超发。因此,金币库存值的读写非常频繁,而且要求数值精确可靠。

使用单点 key 虽然能保证金币库存值是实时且可靠的,但却会带来性能瓶颈。

我们解决这个问题采用的方法是分桶——将一个金币库存拆分成多个分库存,不同用户去扣减不同分库存。这样做,就可以将单点 key 拆分成多个 key,不同 key 的流量则分散到不同的 redis 实例。因此存储层能承载的qps = n * 单台 redis ops,n 为分库存个数。

另外,分库存的数量也可以随着流量的增长而增长。示意图如下:

使用分桶的方法,会导致一种异常情况——分库存扣减不均,部分用户会因库存不足而提前结束游戏,但实际上另一个分库仍有库存。这种情况不可能完全避免,在大流量场景下,会出现大量扣减库存的请求,只要将用户流量尽量均匀分到不同分库存,则可以大大降低出现这种情况的概率。

采取分桶的方法,可以有效地提高系统的吞吐量。而因此引入的分库存扣减不均的问题,在大流量情况下,也相对可以接受。

2.2.2 缓存

对于很多面对高并发、大流量的系统来说,缓存是一种常用的技术,shopee shake 系统也使用了大量缓存。

在游戏过程中,有很多数据是读多写少的,甚至是只读的,如游戏配置、静态资源等。这些读多写少的数据非常适合使用缓存。利用缓存可以极大地缓解数据库压力,也能减少接口响应延时。

缓存有个漏斗模型:经过层层过滤后,透传到后面的系统流量越来越低。所以设计游戏系统时,考虑到数据的读写频率,应当尽量将数据放到更接近用户的缓存。

shopee shake 在每一层系统都使用了缓存,如 web 缓存、进程缓存、codis 缓存。对于热点数据,需要提前缓存,这样做可以防止当缓存不存在时,大流量瞬间冲击到数据库的情况。web 静态数据则使用 cdn 边缘缓存,以此提高游戏加载速度。

系统后端使用缓存时,需要解决另一个问题——缓存如何更新?对于流量较小的系统来说,当缓存过期后,直接尝试从数据库获取数据,这是比较常见的方案。但在大流量场景下,这种方案会导致大量请求直接请求数据库,会造成数据库受到极大的冲击,甚至导致 “雪崩”现象。

解决这个问题,可以使用锁的机制:多个并发请求发现缓存过期,需要去查询数据库时,先去获取“更新缓存锁”,只有获取到“更新缓存锁”的请求才会去查询数据库,当查询数据库完成且更新缓存成功后,释放“更新缓存锁”,而其他请求则进入等待状态,直到缓存被更新时,直接返回缓存。示意图如下:

但该方案存在一个弊端:如果出现网络抖动或后端数据库出现异常,导致查询后端数据库耗时过长,会有大量读请求因此被阻塞,最终占满内存。

shopee shake 曾在一次压测过程中暴露出这一问题。当时,游戏服务内存在短时间内大幅增长,且接口延时变大。经过分析,我们最终发现是缓存更新时后端数据库出现异常,无法及时响应,导致大量请求被阻塞。

为了解决这一问题,我们采用了有限等待时间的方法,如果在设定的等待时间内无法获取到最新的缓存,则使用旧缓存。但这种解决方案有可能会导致数据不一致的情况。对于 shopee shake 系统来说,需要查询数据库的数据都是游戏的基本配置,而这些配置在游戏开始后的修改频率是非常低的,所以有限等待时间的方案比较符合我们的业务场景。

2.3 异步

在高并发场景下,为了提高接口性能,有时会将一些耗时高,但不需要阻塞主流程的操作放到消息队列,减少在线系统的压力。同时使用另一个异步处理的服务,不断处理消息队列的数据。shopee shake 系统也采用了这样的方案。

在一次压测过程中,我们发现游戏系统的游戏结束接口延时相比其他接口要大,而该接口主要用于接收用户摇动手机的次数、计算用户获得的金币数以及给用户发放金币,是整个游戏中最重要的写接口,会直接影响整个系统的吞吐量。

经过性能分析及代码分析发现,游戏结束接口在以下两个功能上耗时最大,大约占接口总延时的 30%:

对用户场景进行分析并和产品经理讨论后,我们梳理了游戏结束接口中所有可以异步处理的功能,并将这些功能异步处理。

可以异步处理的功能有以下几项:

异步处理要解决两个问题:一是不能丢失消息;二是幂等,即重复消费消息,要保证结果一致。

第一点是因为异步处理无法实时感知消息处理的结果,所以需要保证消息不会丢失。第二点的原因是,消息队列的消息有可能会出现重复消费的问题,则需要保证重复消息不会产生副作用。

对于不能丢失消息这点,使用现有成熟消息队列中间件,如 kafka,是能保证的。但存在消息队列出现故障或消息队列容量满载,无法写入新消息的情况,这时需要提取日志,重新生成消息,发送到异步处理服务。所以对于消息队列,需要加强监控,及时发现故障及进行数据补发。

对于重复消费的问题,可以在每一次游戏生成全局唯一的 id,作为请求 id 传给派奖系统,派奖系统根据请求 id 作为唯一键,派奖前先查询当前请求 id 是否曾经派过奖,确保同一个请求不会被重复处理。

由此可见,引入异步处理会增加系统的复杂度,但也能有效提高接口的性能。

3. 容量规划

在每次大促前,我们需要评估系统容量是否足够,是否能支持当地运营人员预估的用户量。这时就需要对系统的容量进行规划。

容量规划主要由下面几个步骤组成:

1. 单容器容量评估。该数据通过全链路压测获得。通过部署单容器容量,压测得到系统的极限容量。单容器容量粒度精确到每个接口可承载的 qps。

2. 将当地运营人员预估的 pcu(最大同时在线用户数)与 qps 进行转换,计算得出系统需要承载最大的 qps。

3. 计算部署的容器数量。

4. 计算下游容量要求。如 codis ops、下游服务 qps。

5. 计算得出的容量后,按需求容量实际部署,包含业务容器数及下游中间件及游戏的需求部署。部署成功后,再做一次全链路压测,验证容量是否满足预估的 qps 需求。

4. 立体监控

为了能实时观察服务运行情况,及时发现异常,团队要对系统进行全方位、立体的监控。立体监控包括接入层、应用层、资源层、硬件层等监控,每层监控指标各不一样。只有做到完整的立体监控,才能及时发现潜在问题。

下表展示了不同层次的监控指标:

5. 大促预案

凡事预则立,不预则废。在大促过程中,面对突发情况,如何应对?

突发情况可能会在系统任何一个环节出现。因此,在梳理预案的时候,我们会根据系统的关键链路寻找链路上的关键节点,并针对关键节点制定预案。

常见的突发情况包括:活动配置错误、接入层不稳定、服务自身出现 bug、依赖的存储层服务不稳定、依赖的下游服务不稳定、依赖的中间件不稳定等等。

根据这些突发情况出现的阶段不同,预案也相应地分为前置预案、应急预案和恢复预案三种类型,有针对地展开处理。

例如:针对“活动配置错误”的突发情况,我们准备了相应的前置预案,在大促活动开始前,检查大促游戏各项配置是否正确。

6. 故障演练

有了预案,并不代表就高枕无忧。这些预案在故障发生时是否真的有效?处理问题的人是否熟练?沟通机制是否顺畅?我们并不希望线上真正出现故障时才去验证这些问题,这样风险太大,成本太大。所以应在线上环境隔离真实流量的情况下,提前模拟各种可能产生的故障,来观察系统的反应和人员处理情况,以验证预期策略。

于是,在大促前我们都会进行故障演练,以低成本的方式发现预案的不足,暴露系统的问题,不断提高人员及系统的能力。

6.1 人员分工

故障演练不仅仅包含突发情况的应对预案,也包含不同职能人员的分工。不同职能人员聚集职能内的责任,同时又能保证信息的有效流转,提高发现问题、执行预案的效率。

上述职能中,除了破坏组是为故障演练而设,其他都是在真实大促活动中切实存在的。在每次大促时,相关职能的人员都会值班待命,随时处理大促过程中出现的异常情况。

6.2 演练过程

制定好人员分工及应对流程后,应该如何进行演练?下文将从故障演练前、故障演练中和故障演练后三个阶段来展开介绍。

6.2.1 故障演练前

6.2.2 故障演练中

被染色的流量注入系统的那一刻起,故障演练就正式拉开序幕。据上图所示,整个演练流程分为八个主要步骤:

  1. 破坏组按故障剧本,注入故障到演练系统;

  2. 定位组观察各指标,及时发现故障,进行初步定位,排查问题;

  3. 定位组汇总关键信息上报故障给决策组;

  4. 决策组收到故障报告,根据关键信息决定是否执行预案,并告知执行组决策结果,要求执行某个预案;

  5. 执行组收到决策组的决策结果,执行某个预案;

  6. 执行组将执行结果反馈给决策组;

  7. 决策组同步预案执行结果给定位组;

  8. 定位组观察预案执行后的指标是否恢复,并将结果反馈给决策组及其他人员。

6.2.3 故障演练后

7. 总结

本文从游戏的逻辑、系统架构、使用的高并发技术,和团队的立体监控、大促前的容量规划、大促预案以及故障演练等方面介绍了小游戏 shopee shake 如何应对大促。

在大流量冲击下,系统保持稳定需要靠系统性思维,不仅仅要考虑系统自身情况,更重要的是技术团队要不断总结教训,积累实践经验,提高自身能力。面对大促,团队应该要做到以下几点:

shopee shake 的现有系统及预案还有不少可以更加完善的地方。为进一步提升游戏系统在大促中的响应能力,后续我们将继续在以下几方面做出优化:

要想做到从容应对大促,并非能一蹴而就,这需要技术团队平时不断积累与磨练,不断提高技术水平及应急能力。大促路上,我们仍需努力。

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

一行Java代码实现游戏中交换装备

08-04

华为帐号“一号畅玩”体验,助力游戏用户增长

08-04

【高手问答汇总】游戏服务器十问,《百万在线》作者倾情作答

08-04

蜗牛游戏独立游戏分支Wandering Wizard获两款惊悚新游发行权

08-04

下载速率提升40% ,《斗罗大陆:魂师对决》是如何做到的?

08-04

独立3D网络游戏《战域重甲》开发与上架经验分享

08-04

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论