性能优化实战(四):优惠券派发高并发、防超发设计

886 阅读6分钟

如果你觉得这篇文章对你有帮助,请不要吝惜你的“关注”、“点赞”、“评价”、“收藏”,你的支持永远是我前进的动力~~~

本文是我在做网易考拉海购性能优化时的真实实践,希望对你也有帮助!!!


一、优惠券的作用

优惠券在电商中扮演着多重角色,其作用主要体现在以下几个方面:

  1. 吸引顾客:通过发放优惠券,电商平台可以吸引新顾客尝试购买,以及激励老顾客再次购买,从而增加网站的流量和转化率。
  2. 促进销售:优惠券能够直接刺激消费者的购买欲望,增加商品的销售量,尤其是在促销活动中,优惠券常常作为推动销售的有效工具。
  3. 清理库存:对于即将过季或滞销的商品,通过优惠券可以更快地清理库存,减少损失。
  4. 用户粘性提升:定期为顾客提供优惠券可以增加顾客对电商平台的忠诚度和粘性,促进重复购买。
  5. 市场调研:通过优惠券的使用情况,电商平台可以收集消费者行为数据,分析顾客偏好,为市场营销策略提供依据。
  6. 价格歧视:优惠券可以实现价格歧视策略,即对不同顾客群体提供不同的价格,最大化收益。
  7. 促销活动宣传:优惠券常常与特定的促销活动相结合,通过优惠券的发放来宣传促销活动,提高活动的知名度和参与度。
  8. 增加购物体验:顾客在享受优惠的同时,也能获得一种购物满足感,这种体验感的提升有助于建立品牌形象。
  9. 数据分析:通过优惠券的使用情况,商家可以分析促销活动的效果,优化未来的营销策略。
  10. 竞争策略:在竞争激烈的电商市场中,优惠券可以作为竞争策略的一部分,帮助商家在价格战中占据有利位置。

总之,优惠券是电商营销组合中的重要组成部分,它通过多种方式促进了电商平台的销售增长和品牌建设。

二、优惠券派发基本流程

基本派发流程基本如下:

  1. 基本信息校验:
  • 参数校验:检查传入的优惠券发放请求是否包含所有必要的信息,如优惠券ID、用户ID、活动ID等,并验证这些信息的格式是否正确。
  • 发放时间校验:确认当前时间是否在优惠券规定的发放时间范围内,确保优惠券只能在特定时间段内领取。
  1. 计数校验:
  • 优惠券总量数:检查已发放的优惠券数量是否已经达到预设的总限量,如果达到或超过,则停止发放。
  • 日限:检查在当前日期内已发放的优惠券数量是否达到日发放上限,以控制每日的优惠券发放量。
  • 单账户限制:确保单个用户账户领取的优惠券数量不超过规定的限制,避免一个用户领取过多优惠券。
  1. 用户类型校验:
  • 会员:检查用户是否为会员,如果是,则根据会员等级或权益决定是否可以领取优惠券。
  • 限定用户领取:根据活动规则,检查用户是否属于特定群体(如新用户、老用户、特定区域的用户等),只有符合条件的用户才能领取。
  1. 风控校验阶段:
  • 风险控制:对用户的行为进行分析,判断是否存在刷券、作弊等异常行为,通过一系列风控规则来决定是否允许用户领取优惠券。
  1. 更新计数:
  • 在确认用户可以领取优惠券后,更新优惠券的发放计数,包括总发放量、日发放量以及用户领取计数,确保数据的准确性。
  1. 派发数据落库:
  • 将优惠券的派发记录保存到数据库中,包括用户ID、优惠券ID、领取时间等信息,以便后续的核销和数据分析。
  1. 异步抄送风控:
  • 将优惠券的派发结果异步发送到风控系统,以便风控系统能够根据最新的数据调整风控策略,进一步提高系统的安全性和稳定性。

整个流程的设计旨在确保优惠券的发放公平、合理,同时防止欺诈行为,保护电商平台的利益。

三、多种方案对比

同一个业务流程,有多种技术实现方案,但都有着各自的优缺点。

我们设计了四种不同的方案及其优缺点。具体如下:

  1. 常规数据库计数 - DB全搞定
  • 优点:实现简单,数据不会丢,一致性好
  • 缺点:热点严重,难以支撑较高派发量
  1. DB分片计数:为了解决热点,我们又设计了DB分片计数的方案
  • 优点:计数及时落库,一定程度上解决了热点问题
  • 缺点:临界点难以处理,需要动态调整
  1. 缓存计数,定期统计DB并修正缓存计数
  • 优点:消除了DB热点,并发高
  • 缺点:缓存失效会导致超发,不能清理派发数据
  1. 缓存计数 + DB记录增减流水 - 促销现用的方案
  • 优点:消除了DB热点,并发高
  • 缺点:需要占用额外的DB空间,难以防止超发
  1. 黑科技:AIISQL/MySQL线程池/合并提交
  • 优点:可以提供上万的TPS(每秒事务数)
  • 缺点:考拉渴望而不可求

四、网易考拉海购的方案

为了应对网易考拉海购的高并发场景,同时又要防超发,我们最终设计了如下的方案,结合了DB和缓存的特性,达到了高并发及防超发的目的。

我们的目标是结合各方案的优点:

  1. 支持高并发
  2. 缓存计数
  3. DB分片计数
  4. 处理好临界点

但又有我们自己的技术要求,既要满足业务的需要不超发,又不能实现过于复杂

  1. 不要超发
  2. 不要丢派发计数
  3. 不要复杂的调整逻辑
  4. 不要插流水

最终我们通过redis lua脚本保证缓存操作原子性

缓存不存在时,利用异步、加锁,单线程从DB中统计已派发计数回填缓存

派发计数分片存储,可以派发时,随机选一个分片更新,无事务