尼恩说在前面
1.如何设计高并发优惠券系统 ,请说出你的方案? 2.听说你会架构设计,请问一下如果让你来设计优惠券系统,说说你的架构设计方案。 3.100万用户,抢10万优惠券,如何设计?
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,回复:领电子书
本文目录
- 尼恩说在前面
- 本文目录
- 一、10Wqps抢券系统的功能分析
- V1.0版本的抢券系统需求拆解
- V1.0版本的 模块介绍
- 优惠券 模板管理 的设计
- 抢券系统的业务流程设计
- 优惠券的使用规则设计
-1.叠加规则
-2.命中规则
- 优惠卷的生命周期设计
- V2.0版本的抢券系统需求演进
-优惠券的依赖方和调用方
-依赖方
-调用方
- 二、抢券系统的非功能需求
- NFR难题1:如何实现10Wqps的领券能力?
- NFR难题2:如何实现10Wqps的算券能力?
- NFR难题3:如何实现10Wqps的核销能力?
- NFR难题4:如何实现10Wqps的抢券事务?
- 三、抢券系统的微服务架构
- 抢券的微服务划分
- 1 模版微服务
- 2 分发微服务
-查看优惠券
-领取优惠券
-核销优惠券
- 3 结算微服务
- 四、抢券系统的表设计
- 五: 抢券系统的10Wqps高并发架构亮点
- 1 服务器架构(应用服务器、数据库、中间件...)
- 2 MQ缓冲队列(削峰填谷、系统解耦)
- 3 高并发存储
- 4 网关(令牌桶)
- 5 缓存(静态缓存、动态缓存)
- 6 应用内的代码设计(多线程、锁等等)
- 7 异常流量的抵御(缓存攻击、数据库攻击...)
- 8 并发测试
- 六:10Wpqs 抢券 的核心流程的高并发设计
- 1 结合redis 高并发缓存,完成领券逻辑设计
- 2 大流量 10W qps 场景下的问题及解决方案
-存储瓶颈及解决方案
- 3 redis 热点库存问题及解决方案
- 4:数据分片场景下的库存扣减方案设计
-券模板获取失败问题及解决方案
- 5 参考秒杀Redis分段锁,设计分库库存扣减方案
- 七:10Wpqs 抢券的缓存优化
- 1 消灭缓存大Key问题
- 2 解决缓存热Key问题
- 八:10Wpqs 抢券系统的高并发DB设计
- 1 优惠券分库分表
- 2 DB的读写分离操作
- 3 用户维度优惠券字段冗余
- 4 优惠券V1.0-》V2.0 独立的DB迁移方案
- 九:10Wqps场景的微服务治理
- 十:优惠券系统高并发压测设计
- 注意事项
- 十一:优惠券系统高可用架构设计
- 十二:10Wqps高并发系统的架构思考
- 参考文献
- 说在最后:有问题找老架构取经
一、10Wqps抢券系统的功能分析
优惠券 拼团 砍价 老带新
代金券 可以直接抵扣商品金额,不找零;任意金额可用(可能会导致零元单,看业务是否能接受);可以同非商品券叠加 满减券 可以抵扣商品金额,有使用门槛;门槛金额需大于优惠金额;可以同非商品券叠加 折扣券 可以抵扣商品金额,有使用门槛,需要设置封顶金额;可以同非商品券叠加 运费券 不可以抵扣商品金额;只能够抵扣运费;可以同非商品券叠加
谁能领? 所有用户 or 指定的用户 领取上限 一个优惠券最多能领取多少张? 领取方式 用户主动领取 or 自动发放被动领取
作用范围 商品、商户、类目 计算方式 是否互斥、是否达到门槛等
V1.0版本的抢券系统需求拆解
tob部分:配置券,会涉及到券批次(券模板)创建,券模板的有效期以及券的库存信息 toc部分:发券,会涉及到券记录的创建和管理(过期时间,状态)
V1.0版本的 模块介绍
模板库存管理、 外部券管理、 策略规则管理、 数据报表等功能。
优惠券的兑换发放、 使用核销、 状态流转等功能, 提供统一的API接口,供上游各业务系统调用,参与到各产品功能环节。
优惠券 模板管理 的设计
券的名称描述等信息 券的类型 应该在什么条件下能使用 使用时优惠减免多少。
抢券系统的业务流程设计
优惠券的使用规则设计
1.叠加规则
一般情况下,商品券我们分为商家自有券和平台发放券,都为商品券,平台的自有券是可以和商家的自行发放的券进行叠加的,但是商家券与 商家券不能叠加,平台券和平台券不能叠加,所以有 商家券+平台券 商品券和运费券是可以叠加的,那么我们可以知道,叠加规则可以 商家券+平台券+运费券 有时候,双十一等大促期间,电商平台还会出一些神券,这些券也是可以和上边的券叠加的,给到用户更多的优惠 商家券+平台券+运费券+神券
2.命中规则
金额 金额是用户最关心的一个点,到底能有多大优惠,一定是体现在金额上,所以我们在搭配优惠券时,一定要把金额最大的,排在第一位 时间 优惠券都有有效时间,有可能有两张券,他们的面额、使用条件等,都一样,那么过期时间就作为一个排序条件,最先过期的优先 类型 可能我们的多张优惠券计算出来的金额都一样,时间也都一样,那么券的类型就很重要了。 一般来说满减券要优先,折扣券次之,代金券最后。 因为满减券有门槛,有最大值,但是折扣券可能封顶的优惠更大,而代金券又没有门槛。 也就是说,满减券是限制最多的,优先使用掉 商品 有些券有商品的适用范围,有些券是全品类的,那么我们优先使用限制商品的券 渠道 有些券限制了APP还是小程序使用,有些是全渠道通用的券,那么优先使用限制渠道的券
优惠卷的生命周期设计
券状态 | 说明 |
V2.0版本的抢券系统需求演进
海量优惠券的发放,达到优惠券单库、单表存储瓶颈。 与商城系统的高耦合,直接影响了商城整站接口性能。 优惠券的迭代更新受限于商城的版本安排。 针对多品类优惠券,技术层面没有沉淀通用优惠券能力。
“创”指优惠券的创建,包含各种券规则和使用门槛的配置。 “发”指优惠券的发放,优惠券系统提供了多种发放优惠券的方式,满足针对不同人群的主动发放和被动发放。 “用”指优惠券的使用,包括正向购买商品及反向退款后的优惠券回退。 “计”指优惠券的统计,包括优惠券的发放数量、使用数量、使用商品等数据汇总。
优惠券的依赖方和调用方
依赖方
商品 好多优惠券都是限制哪些商品可用,商品服务作为一个基础服务,是优惠券系统需要依赖的 商户 有些券是商家券,限制了哪个商家可用,比如lining可用,nike不可用,我们要识别到是哪个商户,所以需要依赖商户系统 职能 在权限控制和用户的有效性判断上,需要依赖职能系统,做校验相关的处理 审批流 在创建优惠券的时候,我们需要有流程化的管控,需要对接审批流
调用方
APP、小程序 C端作为流量的入口,需要展示优惠券的信息数据,承接了优惠券展示的所有能力 从领券开始,到提交订单时的查询可以使用的优惠券,到提交订单后的核销优惠券,最后在我的账户里边查询个人优惠券信息,完成了一整个C端的生命周期处理,属于最关键的调用方。 订单 订单系统,在提交订单时,需要向优惠券系统来校验,券的状态等数据,如果订单金额符合满额返券的金额。那么还需要调用优惠券系统来向用户发券 营销工具 一些营销工具多种多样,比如新人礼包等,需要调用优惠券系统来获取券的信息
二、抢券系统的非功能需求
NFR难题1:如何实现10Wqps的领券能力?
优惠券模板本身设置领取时间,只有在区间时间内才有机会领取优惠券,当然是否能最终领取还取决于其他条件。 券库存。正如商品一样,没有库存的商品是无法下单售卖 当日发放限制。为了防止用户对券哄抢,同时为了延长活动的黏性效果,会限量每天发放优惠券数量。
根据券模板的领取条件限制,以及用户的领取记录,判断是否还可以领取
有些券限制只有新人才可以领取。如:新人专享活动 券也可以跟用户等级挂钩,只有达到设置的等级才可以领取 黑名单用户。用风控挂钩,识别风险刷券用户 自定义用户。可以给用户打一些特定标签。并针对该类型的用户发放。
风控如何接入,领券接口的10Wqps,对风控接口性能有较高要求 券缓存如何设计。一般会按变化的频率做拆分。券模板本身内容可以封装一个缓存模型。其中的券库存由于经常变化,需要单独剥离处理,采用缓存+数据库。但如何保证两者的数据一致性需要我们特别关注 领取记录同样采用缓存+数据库 用户标签。由于不用的优惠券会限制发放给不用的用户人群,所以我们会根据券模板设置的用户标,采用策略模式,调用外部服务,实时查询用户是否满足领取条件。
如何实现10Wqps的领券能力?稍后详细展开,当然,也可以来尼恩的 技术自由圈社群交流。
NFR难题2:如何实现10Wqps的算券能力?
单品:创建单品优惠券,限制只有该商品才可以使用 部分商品:可以与活动绑定,也可以独立设置,只有指定的这些商品才可以适用优惠券 所有商品:全场券,所有售卖的商品都可使用。 店铺商品:店铺优惠券,限制只有购买本店铺的商品才可以使用,当然要满足金额门槛 商品分类:类目券,根据商品的类目属性做适用条件 商品品牌:按品牌决定是否可以使用优惠券 商品标签:为指定商品打上自定义标签,然后优惠券模板中配置 指定商品/排除特殊商品:针对特殊商品做给运营人员的灵活配置。 渠道商品:根据商品进货或者销售渠道定义优惠券范围 区域商品:根据商品销售区域划分,此类优惠券社区电商用的较多。 订单范围就是订单金额满减、满赠、包邮等条件下可使用的优惠券。
如何实现10Wqps的算券能力?稍后详细展开,当然,也可以来尼恩的 技术自由圈社群交流。
NFR难题3:如何实现10Wqps的核销能力?
NFR难题4:如何实现10Wqps的抢券事务?
阶段一:Try
阶段二:Confirm
阶段三:Cancel
三、抢券系统的微服务架构
抢券的微服务划分
1 模版微服务
2 分发微服务
查看优惠券
领取优惠券
核销优惠券
3 结算微服务
四、抢券系统的表设计
五: 抢券系统的10Wqps高并发架构亮点
1 服务器架构(应用服务器、数据库、中间件...)
2 MQ缓冲队列(削峰填谷、系统解耦)
3 高并发存储
4 网关(令牌桶)
5 缓存(静态缓存、动态缓存)
由于发券时需要券模板信息,大流量情况下,不可能每次都从 MySQL 获取券模板信息,因此考虑引入缓存 同理,券的库存管理,或者叫库存扣减,也是一个高频、实时的操作,因此也考虑放入缓存中
6 应用内的代码设计(多线程、锁等等)
7 异常流量的抵御(缓存攻击、数据库攻击...)
8 并发测试
六:10Wpqs 抢券 的核心流程的高并发设计
1 结合redis 高并发缓存,完成领券逻辑设计
2 大流量 10W qps 场景下的问题及解决方案
存储瓶颈及解决方案
单个 MySQL 的每秒写入在 4000 QPS 左右,超过这个数字,MySQL 的 I/O 时延会剧量增长。 MySQL 单表记录到达了千万级别,查询效率会大大降低,如果过亿的话,数据查询会成为一个问题。 Redis 单分片的写入瓶颈在 2w 左右,读瓶颈在 10w 左右
读写分离。在查询券模板、查询券记录等场景下,我们可以将 MySQL 进行读写分离,让这部分查询流量走 MySQL 的读库,从而减轻 MySQL 写库的查询压力。 分治。在软件设计中,有一种分治的思想,对于存储瓶颈的问题,业界常用的方案就是分而治之:流量分散、存储分散,即:分库分表。
发券,归根结底是要对用户的领券记录做持久化存储。对于 MySQL 本身 I/O 瓶颈来说,我们可以在不同服务器上部署 MySQL 的不同分片,对 MySQL 做水平扩容,这样一来,写请求就会分布在不同的 MySQL 主机上,这样就能够大幅提升 MySQL 整体的吞吐量。 给用户发了券,那么用户肯定需要查询自己获得的券。基于这个逻辑,我们以 user_id 后四位为分片键,对用户领取的记录表做水平拆分,以支持用户维度的领券记录的查询。 每种券都有对应的数量,在给用户发券的过程中,我们是将发券数记录在 Redis 中的,大流量的情况下,我们也需要对 Redis 做水平扩容,减轻 Redis 单机的压力。
120000/4000 = 30
120000/20000 = 6
3 redis 热点库存问题及解决方案
4:数据分片场景下的库存扣减方案设计
券模板获取失败问题及解决方案
一是从 Redis 获取券模板失败时,内部进行重试; 二是将券模板信息缓存到实例的本地内存中,即引入二级缓存。
5 参考秒杀Redis分段锁,设计分库库存扣减方案
七:10Wpqs 抢券的缓存优化
1 消灭缓存大Key问题
2 解决缓存热Key问题
八:10Wpqs 抢券系统的高并发DB设计
1 优惠券分库分表
库后缀databaseSuffix = hash(userId) / M %N 表后缀tableSuffix = hash(userId) % M
2 DB的读写分离操作
3 用户维度优惠券字段冗余
4 优惠券V1.0-》V2.0 独立的DB迁移方案
迁移前,运营停止与优惠券相关的后台操作,避免产生优惠券静态数据。
静态数据:优惠券后台生成的数据,与用户无关。 动态数据:与用户有关的优惠券数据,含用户领取的券、券和订单的关系数据等。
配置当前数据库开关为单写,即优惠券数据写入商城库(旧库)。 优惠券系统上线,通过脚本迁移静态数据。迁完后,验证静态数据迁移准确性。 配置当前数据库开关为双写,即线上数据同时写入商城库和优惠券新库。此时服务提供的数据源依旧是商城库。 迁移动态数据。迁完后,验证动态数据迁移准确性。 切换数据源,服务提供的数据源切换到新库。验证服务是否正确,出现问题时,切换回商城数据源。 关闭双写,优惠券系统迁移完成。
九:10Wqps场景的微服务治理
超时设置。优惠券系统是一个 RPC 服务,因此我们需要设置合理的 RPC 超时时间,保证系统不会因为上游系统的故障而被拖垮。例如发券的接口,我们内部执行时间不超过 100ms,因此接口超时我们可以设置为 500ms,如果有异常请求,在 500ms 后,就会被拒绝,从而保障我们服务稳定的运行。 监控与报警。对于一些核心接口的监控、稳定性、重要数据,以及系统 CPU、内存等的监控,我们会在 Grafana 上建立对应的可视化图表,在春节活动期间,实时观测 Grafana 仪表盘,以保证能够最快观测到系统异常。同时,对于一些异常情况,我们还有完善的报警机制,从而能够第一时间感知到系统的异常。 限流。优惠券系统是一个底层服务,实际业务场景下会被多个上游服务所调用,因此,合理的对这些上游服务进行限流,也是保证优惠券系统本身稳定性必不可少的一环。 资源隔离。因为我们服务都是部署在 docker 集群中的,因此为了保证服务的高可用,服务部署的集群资源尽量分布在不同的物理区域上,以避免由集群导致的服务不可用。 依赖外部接口隔离熔断 优惠券内部依赖了第三方的系统,为了防止因为依赖方服务不可用,产生连锁效应,最终导致优惠券服务雪崩的事情发生,优惠券对依赖外部接口做了隔离和熔断。
十:优惠券系统高并发压测设计
注意事项
首先是压测思路,由于我们一开始无法确定 docker 的瓶颈、存储组件的瓶颈等。 所以我们的压测思路一般是:
找到单实例瓶颈 找到 MySQL 一主的写瓶颈、读瓶颈 找到 Redis 单分片写瓶颈、读瓶颈
压测资源也很重要,提前申请到足量的压测资源,才能合理制定压测计划。 压测过程中,要注意服务和资源的监控,对不符合预期的部分要深入思考,优化代码。 适时记录压测数据,才能更好的复盘。 实际的使用资源,一般是压测数据的 1.5 倍,我们需要保证线上有部分资源冗余以应对突发的流量增长。
十一:优惠券系统高可用架构设计
系统架构设计:
信息流、业务流、资金流分离:优惠券系统由信息流、业务流、资金流三部分组成,这三部分在组织架构上应由不同的后台团队完成,以提高系统的模块化和可维护性。 微服务架构:采用微服务架构,将优惠券系统拆分成多个独立的服务,每个服务负责特定的功能,这样可以提高系统的可扩展性和容错性。 无状态设计:确保优惠券系统的服务是无状态的,即服务不需要保存用户的会话信息,这样可以提高系统的并发处理能力和可靠性。
冗余部署:将系统的关键组件部署在多台服务器上,通过搭建主备或者集群的架构来实现冗余。当主服务器出现故障时,备用服务器能够自动接管,保证系统的可用性。 负载均衡:通过将流量分发到多台服务器上,均衡系统的请求负载,提高系统的可用性和扩展性。负载均衡可以通过硬件(如负载均衡器)或者软件(如Nginx、HAProxy)实现。 服务容器化:使用容器技术(如Docker、Kubernetes)将应用程序与其依赖项打包为容器,实现快速部署、弹性扩展和自动化管理。容器化可以提高系统的可移植性、弹性和可伸缩性,从而增加系统的高可用性。
数据备份与恢复:定期对关键数据进行备份,并确保备份的数据可用性。这样,在发生数据丢失或损坏时,可以快速恢复数据,减少系统停机时间。 分布式缓存:使用多级缓存技术(如Redis、Memcached等),将数据分别存储在内存缓存、本地缓存和分布式缓存中,以提高访问速度和降低数据库压力。 数据一致性:使用分布式锁技术来保护优惠券的领取操作,确保每个用户只能领取一次优惠券。同时,为了保证数据一致性,可以采用消息队列等技术实现请求的异步处理和结果的返回。
系统监控:对优惠券系统的关键指标(如请求量、响应时间、错误率等)进行实时监控,以便及时发现和解决潜在问题。 告警机制:设置合理的告警阈值,当系统出现异常情况时,及时发送告警通知给相关人员,以便快速响应和处理。
访问控制:实施严格的访问控制策略,确保只有授权的用户才能访问优惠券系统。 数据加密:对敏感数据进行加密存储和传输,以防止数据泄露和篡改。 安全审计:定期对优惠券系统进行安全审计和漏洞扫描,及时修复发现的安全漏洞和隐患。
十二:10Wqps高并发系统的架构思考
参考文献
说在最后:有问题找老架构取经
被裁之后, 空窗1年/空窗2年, 如何 起死回生 ?
案例1:42岁被裁2年,天快塌了,急救1个月,拿到开发经理offer,起死回生
案例2:35岁被裁6个月, 职业绝望,转架构急救上岸,DDD和3高项目太重要了
案例3:失业15个月,学习40天拿offer, 绝境翻盘,如何实现?
被裁之后,100W 年薪 到手, 如何 人生逆袭?
100W案例,100W年薪的底层逻辑是什么? 如何实现年薪百万? 如何远离 中年危机?
其他 历史逆袭案例,包含AI、大数据、golang、Java 等
实现职业转型,极速上岸
关注职业救助站公众号,获取每天职业干货
助您实现职业转型、职业升级、极速上岸
---------------------------------
实现架构转型,再无中年危机
关注技术自由圈公众号,获取每天技术千货
一起成为牛逼的未来超级架构师
几十篇架构笔记、5000页面试宝典、20个技术圣经
请加尼恩个人微信 免费拿走
暗号,请在 公众号后台 发送消息:领电子书
如有收获,请点击底部的"在看"和"赞",谢谢