当前位置: 首页 > news >正文

电商项目_秒杀_架构及核心

秒杀架构设计

 先看下普通web项目架构: 

(Nginx : 反向代理、负载均衡,一般是运维部分做生产搭建的时候配置好)

秒杀架构设计:

和普通架构区别:

  • 原先由Web 服务或Nginx服务提供的静态资源放到了CDN
  • Nginx的职责放⼤,前置⽤来做Web ⽹关,承担部分业务逻辑校验,并且可能增加⿊⽩名单、限流和流控的功能

秒杀技术选型

核⼼设计是对巨⼤的瞬间流量进⾏层层错峰

错峰1:页面静态化。将包含浏览者信息的动态数据和不包含的静态数据进行区分。

错峰2:秒杀前答题。⽬的是防⽌机器刷单,以及错开⽤户的下单时⻓。

错峰3:Redis扣减库存。快速扣减库存, 扣减库存完通知nginx.

错峰4:Nginx快速通知秒杀结束。

错峰5:MQ进行流量消峰

错峰6:引⼊ MQ 进⾏下单服务异步化

秒杀后端链路图

—场完整的秒杀活动的⼤概流程是这样的:

1.运营⼈员在秒杀系统的运营后台,根据指定商品,创建秒杀活动,指定活动的开始时间、结束时间、活动库存等。

2.活动开始之前,由秒杀系统运营后台开启秒杀,会同时往商城系统的Redis Cluster集群写⼊ ⾸⻚秒杀活动信息 和往秒杀系统的Redis主从集群写诸如 秒杀商品库存 等信息。

3.⽤户进⼊到秒杀商详⻚准备秒杀。

4.商品详情⻚可以看到⽴即抢购的按钮,这⾥我们可以通过增加⼀些逻辑判断来限制按钮是否可以点击,⽐如是否设置了抢购⽤户等级限制,是否还有活动库存,是否设置了预约等等。如果都没限制,⽤户可以点击抢购按钮,进⼊到秒杀结算⻚。

5.在结算⻚,⽤户可更改购买数量,切换地址、⽀付⽅式等,这⾥的结算元素也需要按实际业务来定,更复杂的场景还可以⽀持积分、优惠券、红包、配送时效等,并且这些都会影响最终价格的计算。

6.确认⽆误后,⽤户提交订单,在这⾥后端服务可以调⽤⻛控、限购等接⼝,来完善校验,都通过之后,完成库存的扣减和订单的⽣成。

7.订单完成后,根据⽤户选择的⽀付⽅式跳转到对应的⻚⾯,⽐如在线⽀付就跳转到收银台,货到付款的话,就跳到下单成功提示⻚。

相关技术点:

  • 秒杀活动开始:Canal组件监听DB里秒杀活动变化,同步到Redis,并在首页展示
  • 商品详情页:Nginx配置了详情页的页面,动态数据从Redis中获取, 静态数据在Nginx中配置好
  • 确认订单:
  • 生成订单:Redis中扣减库存

秒杀前流量管控

秒杀中的流量管控

1. 流量削峰

  1. 验证码和回答问题:有两个⽬的,⼀是快速拦截掉部分刷⼦流量,防⽌机器作弊,起到防刷的作⽤;⼆是平滑秒杀的⽑刺请求,延缓并发,对流量进⾏削峰。
  2. 消息调用:用到两个业务系统之间的调用中

2. 限流

Nginx限流

Nginx本身也提供了⾮常强⼤的限流功能,⽐如有两个专⻔的限流模块HttpLimitzone和HttpLimitReqest

  1. HttpLimitzone⽤来限制⼀个客户端的并发连接数,
  2. HttpLimitReqest通过漏桶算法来限制⽤户的连接频率
// HttpLimitzone示例
// 表示同⼀ip不同请求地址,进⼊名为one的zone,限制速率为1请求/秒。http {limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;server {location /search/ {limit_req zone=one burst=2 nodelay;}}
}

应用/服务层限流

1. 线程池:限制连接数

2. 限流组件:QPS的限流

3. 自定义限流:

        比如用户的下订单请求,前端在用户进入订单结算页面时,调用订单号服务生成个orderId,在用户提交订单时,带着这个orderId. 

        订单号的获取,秒杀场景下的改进是:JVM缓存放置预先生成的orderId, 定时任务定时去生成新的orderId并放入缓存中(注意保证线程安全)。

        JVM缓存中的订单号起到限流的作用, 同时前端提前生成orderId, 也防止了同一个订单提交多次。

分层过滤

举个例子,秒杀如果商品售罄,会将库存为0的结果写到nginx缓存

1. nginx判断库存, 先判断本地缓存, 在判断redis缓存, 结果为0时终止秒杀

2. 业务链路中,同样都会做库存的判断

业务上还要解决退单导致库存量增加,思路:订阅对应的Redis的channel.

3. 限购

限购的策略:

  • 商品维度:秒杀产品的总量、商品发货地 等等
  • 个人维度:1个手机号1单、1人1天1单 等等

秒杀活动时, 流量先经过限流策略过滤后,在进入到订单服务。通过限购策略,也可以过滤到一部分流向订单系统的流量。

库存扣减

库存扣减涉及到两个核心操作,查商品库存,库存充足扣减库存。要保证其原子性

1. 数据库

1. 查询和扣减放在一个事务中

2. where 条件保证库存 >= 0

3. 乐观锁, 先查询,更新时带着版本号

4. 数据库特性:无符号整数字段,值不能小于0, 所以扣减到小于0,SQL报错(性能超,不适合秒杀,适合业务量小的场景)

2. 分布式锁

商品维度加分布式锁,但不适合秒杀场景。

  • 过期时间的设置,太短,业务流程未走完就过期了;太长,如果当前业务流程异常,导致其他线程一直阻塞锁,性能不高。
  • 秒杀场景,商品还串行下单,性能肯定不好

3. 高并发扣减

降级

降级⼀般是有损的,那么必然要有所牺牲,⼏种常⻅的降级:写服务降级、读服务降级。

1. 写服务降级:牺牲数据─致性获取更⾼的性能。 降级手段,同步写数据库降级成同步写缓存、异步写数据库

Redis扣减库存,通过lua脚本,保证查询和扣减原子性的执行

2. 读服务降级:故障场景下紧急降级快速⽌损。

        在做⾼可⽤系统设计时,要牢记就是微服务⾃身所依赖的外部中间件服务或者其他RPC服务,随时都可能发⽣故障,因此我们需要建设多级缓存,以便故障时能及时降级⽌损。

        假设当秒杀的Redis缓存出现故障时,我们就可以通过降级开关,快速将读请求降级到 从Redis 缓存、MongoDB或者ES上。或者当Redis和备份缓存同时出现故障时(现实中很少出现同时故障的场景),我们还是可以通过降级开关将流量切换到数据库上,让数据库暂时承压来完成读请求服务。

简化系统设计

        简化系统功能就是指⼲掉⼀些不必要的流程,舍弃⾮核⼼功能。

        商品的基本信息外,还有很多附加的信息,⽐如你是否收藏过该商品、商品的收藏总数量、商品的排⾏榜、评价和推荐等楼层。同样,对于秒杀结算⻚,还会有礼品卡、优惠券等虚拟⽀付路径。

        不过,实际运⽤中,这种⾮核⼼功能的有损降级,要视具体的SKU⽽定,⼀般为了降低影响范围,我们只对流量⾮常⾼的SKU进⾏降级。⽐如,如果是⼿机秒杀,⼀般是不需要降级的,但是像⼝罩这样的爆品,就需要针对SKU维度进⾏⾮核⼼功能的降级了。

        降级开关的怎么设计呢,其实⽐较简单,核⼼思路就是通过配置中⼼,对降级开关进⾏变更,然后推送到各个微服务实例上。

4. 热点数据

        ⼀般⾼并发的常规解决思路是:数据库通过分库分表来应对;Redis,增加Redis集群的分⽚来解决,⽽应⽤层⼀般是⽆状态的设计。所以从数据库、Redis缓存到应⽤服务,都是可以通过增加机器来⽔平扩展服务能⼒,解决⾼并发的问题。

        但是秒杀场景,就那么几个商品,这些手段显然不够。

1. 读热点

1. 增加热点数据的副本数。 增加Redis从的副本数,然后业务层(Tomcat集群)轮询查询不同的副本,提⾼同⼀数据的QPS。

2. 让热点数据离⽤户越近越好。

  • 把热点数据再上移, 在服务内部做热点数据的本地缓存。但是本地缓存的数据延迟要有解决方案
  • 如果还是用redis缓存,nginx和nginx需要的缓存部署在一起,业务服务和业务服务使用的缓存部署在一起, 做到不跨网络访问。

3. 直接短路访问。 要具体业务具体分析, 根据商品的配置,直接不走一些业务逻辑。

2. 写热点

  1. 预约人数场景, 实际展示的预约人数并不要求十分精确, 对应的解决方式:先在JVM内存⾥累加,延迟提交到 Redis,这样就可以把 Redis 的OPS降低⼏⼗倍。
  2. 写对象颗粒化,库存的扣减场景,可以通过把⼀个热 key拆解成多个key的⽅式,避免热点问题。
  3. 单SKU的库存直接在Redis 单分⽚上进⾏扣减。实际上,扣减库存在秒杀链路的末端,通过之前的削峰和限流的各种⼿段,真正到库存的流量是有限的,单⽚的Redis OPS 能承受得了。然后,我们可以针对单SKU的库存扣减进⾏单独限流,保证库存单⽚Redis的压⼒。这样双管⻬下,单SKU的库存Redis 扣减压⼒就是可控的了。

相关技术

OpenResty

        Nginx在主要的秒杀系统设计中,扮演着⾮常重要的⻆⾊,意味着Nginx上要承载很多的业务逻辑。Nginx的底层模块⼀般都是⽤C语⾔写的,如果我们想在Nginx的基础之上写业务逻辑会很不⽅便,所以这个时候我们还得借助OpenResty,它是Nginx的⼀个社区分⽀。

        按照官⽹的说法,OpenResty 是⼀个基于 Nginx 与 Lua 的⾼性能 Web 平台,其内部集成了⼤量精良的 Lua库、第三⽅模块以及⼤多数的依赖项。⽤于⽅便地搭建能够处理超⾼并发、扩展性极⾼的动态 Web 应⽤、Web 服务和动态⽹关。

        OpenResty本质上是将 LuaJIT 的虚拟机嵌⼊到 Nginx 的管理进程和⼯作进程中,同⼀个进程内的所有线程都会共享这个虚拟机,并在虚拟机中执⾏Lua代码。在性能上,OpenResty接近或超过 Nginx 的C模块,⽽且开发效率更⾼。

http://www.lryc.cn/news/596616.html

相关文章:

  • Linux文件系统深入理解
  • 交叉编译opencv(Cpp)于arm64架构开发板上
  • 决策规划内容整理
  • 三轴云台之图像处理算法篇
  • 跨越语言壁垒!ZKmall开源商城多语言架构如何支撑电商全球化布局
  • Ext4文件系统全景解析
  • C++基础学习——文件操作详解
  • wangEditor5添加键盘事件/实现定时保存功能
  • 单张显卡运行多个vllm模型
  • 进程优先级切换调度-进程概念(6)
  • 【C++】继承和多态扩展学习
  • PyQt5在Pycharm上的环境搭建 -- Qt Designer + Pyuic + Pyrcc组合,大幅提升GUI开发效率
  • Qt多语言支持初步探索
  • 按键精灵脚本:自动化利刃的双面性 - 从技术原理到深度实践与反思
  • Web3面试题
  • 拥抱区块链红利:机遇无限,风险暗涌
  • 期权分红怎么分的?
  • UNet改进(24):注意力机制-从基础原理到高级融合策略
  • Atcoder Beginner Contest 415 D题
  • 算法笔记之堆排序
  • 2023CCPC秦皇岛 F. Mystery of Prime(线性DP)
  • Python通关秘籍(四)数据结构——列表
  • iView Table组件二次封装
  • Elasticsearch服务器开发(第2版) - 读书笔记 第一章 Elasticsearch集群入门
  • 【uboot/kernel1】启动流程,环境变量,内存,initramfs
  • 【数学建模】基础知识
  • 【Verilog】竞争、冒险
  • 本地大模型VRAM需求计算器:原理与实现详解
  • Web3介绍(Web 3.0)(一种基于区块链技术的去中心化互联网范式,旨在通过技术手段实现用户对数据的自主权、隐私保护和价值共享)
  • 浙江大学PTA程序设计C语言基础编程练习题1-5