秒杀系统的挑战和应对设计

秒杀系统是日常系统开发过程中经常遇到的场景,那么如何可以准备哪些措施来保证秒杀过程中系统的可用性以及一致性呢?

秒杀活动,需要满足各方的需求

  1. 作为用户,希望能够抢到自己中意的优惠

  2. 作为商户,希望券不超发,系统运行稳定

  3. 作为微信支付,希望能通过每周末活动提高业务口碑,同时保证资金安全

这意味着,我们的目标是高并发场景下保证系统的高可用以及数据的一致性

1. 秒杀活动面临的挑战

整个流程包含支付有优惠、微信支付营销系统、微信开平消息推送、以及大量的商户系统 因此我们主要以下痛点:

  1. 有优惠活动参与用户多,请求量会有激增

  2. 秒杀活动轮次多,每轮展示奖品内容多

  3. 兑换流程长,涉及多个系统、多个服务

  4. 商家券最终依赖商户系统,商户系统发券失败影响微信支付口碑,甚至引起客诉

因此我们的系统主要面临着一下的挑战:

  1. 挑战1: 系统高并发场景下高质量、稳定支持秒杀活动,同时保证所有下游商家系统也能平稳支撑

  2. 挑战2: 奖品不超发,在支付有优惠、营销系统、商户系统之间的最终一致性

  3. 挑战3: 服务上线后,需要做好BCP建设

2. 挑战1-可用性建设

痛点1: 秒杀活动轮次多,每轮展示奖品内容多(超过100个)

我们每周末都会有多个场次,每场展示的奖品超过100个,每个奖品都有大量的素材、图片等信息,同时还需要判断用户是否已经参与过秒杀、兑换过每个奖品,这里如果每次都实时拉取,毫无疑问会增加后台的负担。那么我们能不能将这些信息缓存下来,等来用户请求的时候,我们直接从本机读取即可,而不需要发起RPC,调用存储。

破局1: 设计合理的缓存方案(查询峰值30W/min)

  1. 我们可以区分出静态数据(活动配置、会场数据、奖品配置)和动态数据(用户兑换数据),针对静态数据(变化频率极低的数据)我们可以提前缓存到本地,而动态数据,因为需要实时计算,这里不进行缓存。这样我们就可以减少大量的RPC请求,从而达到保护系统的目的。

  2. 但是这些静态数据仍然可能需要更新,因为运营同学可能需要修改奖金、额度等一些信息,因此我们需要有机制去更新缓存。更新机制一般分为同步和异步,这里我们采用一个daemon进程定时从存储组件中获取静态数据信息,然后写到本机的memcache中,同时过期方式设置为永不过期。这样系统就不存在缓存雪崩、缓存穿透问题。从而提高系统稳定性。

  3. 同时针对用户的兑换数据,我们存储在TTLKV中,设置过期时间为活动的结束时间,同时每10s更新一次

如上方法,就能够解决数据查询的问题

解决了看的问题,接下来我们需要解决抢的问题

痛点2: 秒杀活动瞬时请求量大(峰值20W/min)

秒杀活动一定会出现激增流量,因此我们需要想办法让用户的秒杀请求陆续到达后台,这样就可以通过前端保护后端的方式,提高系统的稳定性,使得用户可以正常秒杀奖品

破局2: 流量削峰

增加用户维度限流和接口维度限流,降低流量,达到保护商家,保护系统的目的

痛点3: 商户系统不可控(每周末3场秒杀,涉及3个商户,普通奖品涉及商户更多)

商户系统属于外部系统,而发券其实强依赖于商户。

如果是同步发券,我们系统就会把所有流量打到营销系统,再由营销系统透传到商户系统,但是商户系统可能无法支撑这么大的请求量,最后引起商户系统雪崩,而用户就无法及时获得商家券,最终引起客诉。所以我们要避免这种情况。

破局3:异步发券

  1. 因为我们可以将发券操作变为异步发券,以3000/s的QPS将发券请求发送到营销系统。然后营销系统再将发券请求通知到商户,这样商户系统的最高流量就变成了可预估的流程,从而达到保护商户的目的,降低潜在的客诉风险。

  2. 所有参与秒杀的商户都必须配合联合压测,并提供压测报告,如压测结果不符合预期,我们可以更换商户,换用系统能够符合要求的商户参与活动

3. 挑战2-一致性建设

接下来我们看看如何提高系统的一致性。 在整个秒杀活动中,我们需要保证以下目标:

目标

  1. 奖品不超发

  2. 用户不多抢(一轮只能秒杀一次)

  3. 有优惠系统、营销系统、商户系统数据一致性

那么我们需要如何做到以上的目标呢?

这是个类似分布式事务一致性的问题,我们调研了多种方案,包括代金券系统,消费券系统,行业权益系统等,这里列出了2个:

  1. 一个是代金券系统的方案,代金券要求在扣除券库存之后,记录预发记录,还要扣除用户限额也就是自然人限额,它是通过mysql事务,保证全库存与预发记录的一致性,而用户限额扣除后置,非原子操作,极端情况下可以突破自然人限制。

  2. 另一个方案是行业消费券的方案,消费券先预扣库存,再扣用户限额,在提交库存之后将订单落MQ,交由MQ处理后续事宜。如果有失败,会执行库存回滚。如果库存预扣、提交和回滚有任何不可预知失败,都会抛一个MQ事件,交由MQ驱动数据一致。为避免MQ故障,通过对账服务对出MQ未处理到的部分,再进行处理。

我们的场景有些不一样,我们这里因为包含以下的额度: 活动场次限额、奖品限额、用户账户(兑换奖品需要金币)。而其中活动场次库存由秒杀服务处理,奖品库存、用户账户都是由兑换服务处理。

实现

  1. 通过秒杀服务直接扣库存(Quotakv),这样可以保证奖品不超发,这里没有二阶段的原因是,会增加系统的复杂性,只需要保证不超发,不保证少发。

  2. 然后设计合理的幂等ID来保证一个用户只能参与一次秒杀。

  3. 通过接入事件中心的方式来保证发券的成功,可以利用事件中心的反查机制,重试用户发券的流程,防止中间任何一步出现问题,保证发券成功

  4. 同时对账机制,保障支付有优惠系统和营销系统的数据一致性,如果出现单边账,通过补发机制打到最终数据一致

3. 挑战3-BCP、安全建设

虽然前面我们已经做好了各种可用性的保证,但是等到服务正式运行到过程中,仍然可能出现各种各样的可能会发生的情况,因此我们要对这些这些可能发生的情况准备好各种预案,降低系统风险,

主要包含以下几点:

  1. QuotaKv故障,我们可以通过秒杀服务按照机器数量,在每台机器上预先加载部分库存,本地库存消耗完毕后,再调用quotakv消耗远端库存,并更新本地库存

  2. TabeleKV故障,可以通过挂公告安抚用户,奖品24小时内陆续到帐

  3. 秒杀服务故障,可以通过跨园区多副本部署,降低故障概率

  4. 可靠事件中心故障,通过异步发券的方式,让MQ进行重试,同时接入双链路事件中心,降低故障概率

同时我们也应用STRIDE安全模型,针对系统可能存在的安全风险制定合理的安全消减的方案,保证业务的安全性

4. 秒杀系统总结

总结下来,我们采用了如下策略应对相关的挑战,使用一张图概括

可用性

  1. 并发控制:接入限频组件,保证系统处理请求数量在可控范围内

  2. 幂等重试:设计合理幂等方案保证接口可重入

  3. 过载保护:系统不可处理时,快速拒绝

  4. 流量削峰:前端保护后端,流量打散请求

  5. 灰度策略:针对银行立减金奖品,只对定向人员进行展示

一致性

  1. 基本可用:及时将结果展示给用户,降低用户不安情绪

  2. 最终一致性:同步变异步,降低快慢系统之间的耦合

  3. 对账补偿:通过对账发现数据不一致的地方

BCP

  1. 降级预案:准备降级预案,应为未知风险(屏蔽入口,暂停活动,秒级生效,用于黑天鹅事件事中处理)

  2. 公告预案:准备公告方案,及时安抚用户情绪

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/586782.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB 字符串

MATLAB 字符串 在MATLAB中创建字符串非常简单。实际上,我们已经使用了很多次。例如,您在命令提示符下键入以下内容- 示例 my_string ‘(cainiaojc.com)’ MATLAB将执行上述语句并返回以下结果 my_string (cainiaojc.com) MATLAB将所有变量视为数组&a…

Macos安装OrbStack

什么是OrbStack OrbStack 是一种在 macOS 上运行容器和 Linux 机器的快速、轻便和简单方法。它是 Docker Desktop 和 WSL 的超强替代品,所有这些都在一个易于使用的应用程序中。 在Macos M系列芯片上,经常遇到docker镜像不兼容的问题,此时使…

【初识Redis】

初识Redis Redis(Remote Dictionary Server)是一个开源的内存数据库,它提供了一个高性能的键值存储系统,并且支持多种数据结构,包括字符串、哈希、列表、集合和有序集合等。Redis的特点包括: 内存存储&…

[C语言]典型例题:小蚂蚁爬橡皮筋、买汽水问题、导致单词块、菱形打印……

1、小蚂蚁爬橡皮筋问题 假设橡皮筋长4m,小蚂蚁从一端爬向另一端每天爬1m,且每爬了1m,橡皮筋会立马拉伸4m,在理想条件下,小蚂蚁需要爬多少天可以到达橡皮筋的另一端? 不仔细想,我们很可能认为小蚂…

2023年蓝桥杯C++A组第三题:更小的数(双指针解法)

题目描述 小蓝有一个长度均为 n 且仅由数字字符 0 ∼ 9 组成的字符串,下标从 0 到 n − 1,你可以将其视作是一个具有 n 位的十进制数字 num,小蓝可以从 num 中选出一段连续的子串并将子串进行反转,最多反转一次。小蓝想要将选出的…

JavaEE 初阶篇-深入了解网络原理中传输层的端口号与 UDP 协议报文格式

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 端口号概述 1.1 端口号的作用 1.2 端口号不能重复被多个进程绑定 2.0 传输层协议 - UDP 2.1 UDP 的特性 2.2 UDP 的报文格式 1.0 端口号概述 端口号是计算机网络中…

多线程事务怎么回滚

1、背景介绍 1,最近有一个大数据量插入的操作入库的业务场景,需要先做一些其他修改操作,然后在执行插入操作,由于插入数据可能会很多,用到多线程去拆分数据并行处理来提高响应时间,如果有一个线程执行失败…

【算法小白周赛1A】分析 - 题解与代码

题目链接:https://www.starrycoding.com/problem/155 题目描述 小可可最近在学数学运算!他希望考考你,给你两个整数 A , B A,B A,B,询问 A B A\times B AB 是否是偶数。 注意,可能存在前导 0 0 0,比如…

面试题-Redis篇

什么是 Redis? Redis 是完全开源免费的,遵守 BSD 协议,是一个高性能的 key-value 数据库。 Redis 与其他 key - value 缓存产品有以下三个特点: Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时 …

【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5)

🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C笔记专栏: C笔记 🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅 文章目录 一、回调函数二、快速排序(Qsort)2.1 Qsort参数部分介绍2.2 不…

【Flutter】极光推送配置流程(小米厂商通道) 章二

前言 继【Flutter】极光推送配置流程(极光通道/华为厂商/IOS) 章一 并且,我大概率不会去修改第一篇文章的内容。 随着我自己在配置公司的项目的同时,我希望一直更新这个推送系列文章。 在章一配置完后,也是出现了一些问题,所以本…

【第1章】spring-mvc搭建

文章目录 前言一、准备二、搭建1.搭建2.项目结构 三、第一个Servlet程序1. jsp2. servlet3. 启动 总结 前言 Java已经进入了飞速发展的阶段,spring-mvc也发生了巨大的变化,最让人无法忍受的就是javax.servlet.* 变成了jakarta.servlet.* ps:虽然使用起来…

GPT-ArcGIS数据处理、空间分析、可视化及多案例综合应用

在数字化和智能化的浪潮中,GIS(地理信息系统)和GPT(生成式预训练模型)的结合正日益成为推动科研、城市规划、环境监测等领域发展的关键技术。GIS以其强大的空间数据处理、先进的空间分析工具、灵活的地图制作与可视化能…

吴恩达2022机器学习专项课程(一)7.2 逻辑回归的简化成本函数课后实验 Lab5

问题预览/关键词 二分类问题的训练集(多特征)绘制训练集数据的散点图自定义plot_data() Python实现逻辑回归的成本函数自定义sigmoid() 调用成本函数不同的w,b,绘制逻辑回归模型的决策边界验证哪条决策边界效果好总结 二分类问题的…

精通GDBus:Linux IPC的现代C接口

目录标题 1. GDBus介绍2. GDBus的优点3. 安装GDBus4. 使用GDBus连接到D-Bus总线实现D-Bus服务调用D-Bus方法发送和接收信号 5. 总结 在Linux环境下,不同的程序需要通过某种方式进行通信和协同工作。GDBus是GLib库的一部分,提供了一个基于GObject系统的、…

中科驭数受邀成为移动云智能芯片开放实验室首批成员企业

4月28日至29日,2024中国移动算力网络大会在苏州举行。大会以“算力网络点亮AI新时代”为主题,全面展示了中国移动最新算力网络成果与能力。中科驭数作为移动云智能芯片开放实验室首批合作伙伴,受邀参加入驻仪式,中科驭数高级副总裁…

OpenCV的图像矩(64)

返回:OpenCV系列文章目录(持续更新中......) 上一篇:OpenCV如何为等值线创建边界旋转框和椭圆(63) 下一篇 :OpenCV系列文章目录(持续更新中......) Image Moments(图像矩)是 OpenCV 库中的一个…

C语言----函数

1.函数的概念 函数:founction c语言的程序代码都是函数组成的 c语言中的函数就是一个完成某项特定的任务的一段代码,这段代码有特殊的写法和调用方法 c语言中我们一般见到两种函数: .库函数 .自定义函数 2.库函数 有对应的头文件 #i…

Python | Leetcode Python题解之第60题排列序列

题目: 题解: class Solution:def getPermutation(self, n: int, k: int) -> str:factorial [1]for i in range(1, n):factorial.append(factorial[-1] * i)k - 1ans list()valid [1] * (n 1)for i in range(1, n 1):order k // factorial[n - …

大数据分析与内存计算学习笔记

一、Scala编程初级实践 1.计算级数: 请用脚本的方式编程计算并输出下列级数的前n项之和Sn,直到Sn刚好大于或等于q为止,其中q为大于0的整数,其值通过键盘输入。(不使用脚本执行方式可写Java代码转换成Scala代码执行&a…