秒杀架构设计

 先看下普通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.pswp.cn/pingmian/89966.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89966.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/89966.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4x4矩阵教程

4x4矩阵教程 1. 简介 四维矩阵是计算机图形学和3D变换中的重要工具&#xff0c;用于表示三维空间中的仿射变换。本教程将介绍如何使用C实现四维矩阵的基本运算和变换。 2. 代码实现 2.1 头文件 (matrix4x4.h) #ifndef MATRIX4X4_H #define MATRIX4X4_H#include <array> #…

Oracle 数据库共享池与大池调优指南

在 Oracle 数据库的内存管理中&#xff0c;共享池&#xff08;Shared Pool&#xff09;和大池&#xff08;Large Pool&#xff09;是 SGA&#xff08;系统全局区&#xff09;中负责缓存与资源分配的核心组件。合理配置和调优这两个池&#xff0c;能显著提升数据库性能 —— 尤其…

C# Lambdab表达式 Var 类

Lambdab 是用于创建一个方法的表达式Func<参数1类型, 参数2类型, 返回值类型> fnName >(参数1 参数2) {方法代码体}Func<int, int, bool> fnName (int a, int b) > {return a > b; };//调用时和普通方法一致 Console.WriteLine(fnName(10,20)); // false…

【Python】常见模块及其用法

文章目录1. 什么是模块和包&#xff1f;2. 常见的模块及其用法2.1 time概览2.1.1 时间获取方法2.1.2 时间格式化与解析2.1.3 程序计时与延迟2.1.4 时间转换2.2 random概览2.2.1 基本随机数2.2.2 随机整数2.2.3 序列操作2.2.4 概率分布2.2.5 随机种子2.2.6 状态管理2.3 os概览2.…

洛谷 P3478 [POI 2008] STA-Station

【题目链接】 洛谷 P3478 [POI 2008] STA-Station 【题目考点】 1. 树形动规&#xff1a;换根动规 换根动规&#xff0c;又名二次扫描法&#xff0c;一般是给一颗不定根树&#xff0c;通过两次扫描来求解。 我们可以先任选一个根结点root&#xff0c;通过树形动规的思想计算…

【爬虫】03 - 爬虫的基本数据存储

爬虫03 - 爬虫的数据存储 文章目录爬虫03 - 爬虫的数据存储一&#xff1a;CSV数据存储1&#xff1a;基本介绍2&#xff1a;基本使用3&#xff1a;高级使用4&#xff1a;使用示例二&#xff1a;JSON数据存储1&#xff1a;基础json读写2&#xff1a;字符串和对象的转换3&#xff…

深入分析计算机网络数据链路层和网络层面试题

计算机网络体系结构1. 请简述 OSI 七层模型和 TCP/IP 四层模型&#xff0c;并比较它们的异同。OSI 七层模型&#xff1a;应用层&#xff1a;直接为用户的应用进程提供服务&#xff0c;如 HTTP&#xff08;超文本传输协议&#xff0c;用于 Web 浏览器与服务器通信&#xff09;、…

云服务器新装的mysql8,无法通过远程连接,然后本地pymysql也连不上

阿里云服务器&#xff0c;用apt-get新装的mysql-server&#xff0c;竟然无法通过远程连接到&#xff0c;竟然是这个原因。不是防火墙&#xff0c;iptables早就关了。也不是安全组&#xff0c;不是人为限制访问的话&#xff0c;根本没必要弄安全组 排查过程 netstat -antop|grep…

质量即服务:从测试策略到平台运营的全链路作战手册

&#xff08;零&#xff09;为什么需要“质量即服务” 当业务方说“今晚一定要上线”&#xff0c; 当开发说“我只改了两行代码”&#xff0c; 当运维说“回滚窗口只有 5 分钟”&#xff0c; 质量必须像水电一样随取随用&#xff0c;而不是上线前的大坝泄洪。 这篇手册提供一张…

Java -- 自定义异常--Wrapper类--String类

自定义异常&#xff1a;概念&#xff1a;当程序中出现了某些错误&#xff0c;但该错误信息并没有在Throwable子类中描述处理&#xff0c;这个时候可以自己设计异常&#xff0c;用于描述该错误信息。步骤&#xff1a;1. 定义类&#xff1a;自定义异常类名&#xff08;程序员自己…

一文速通《线性方程组》

目录 一、解题必记知识点 二、解题必备技巧 三、非齐次线性方程组求解 四、齐次线性方程组求解 ★五、解析题目信息&#xff0c;获取暗含条件 一、解题必记知识点 (1) (2)基础解系线性无关&#xff0c;基础解系 解空间的一个基&#xff0c;基 一组线性无关的、能够生…

【Django】DRF API版本和解析器

讲解 Python3 下 Django REST Framework (DRF) API 版本控制解析器&#xff08;Parser&#xff09;一、DRF API 版本控制详解 API 版本控制是构建健壮、可维护的 RESTful API 的关键&#xff0c;尤其在项目演进中需要兼容不同版本的客户端请求。 1.1 API 版本控制的核心原理 AP…

Windows系统暂停更新工具

功能说明 暂停更新至2999年恢复系统更新彻底禁用更新&#xff08;不可逆&#xff09; 使用方法 下载解压后双击运行 .bat 文件 输入数字选择功能&#xff1a; 输入 1&#xff1a;暂停更新至2999年&#xff08;推荐&#xff09;输入 2&#xff1a;恢复系统更新输入 3&#xf…

git push新版问题解决

git 好像不能通过username:password的方式来git push了。但我的电脑依然弹出username和password的弹窗。转战ssh来git push。由于之前是用git clone克隆的&#xff0c;需要再转换成ssh的url来git push。

PyCharm + AI 辅助编程

PyCharm AI&#xff1a;初学者友好的 2 个实用场景&#xff08;附操作步骤&#xff09; PyCharm 专业版&#xff08;或通过插件集成&#xff09;支持 AI 辅助编程&#xff08;如 JetBrains AI 或 GitHub Copilot&#xff09;&#xff0c;能根据代码上下文自动生成代码、解释逻…

疯狂星期四文案网第15天运营日记

网站运营第15天&#xff0c;点击观站&#xff1a; 疯狂星期四 crazy-thursday.com 全网最全的疯狂星期四文案网站 运营报告 昨日访问量 昨天只有20来ip, 太惨了&#xff0c;感觉和最近没有发新段子有关&#xff0c;也没有发新的外链&#xff0c;不知道这周四会怎么样 昨日搜…

如何解决pip安装报错ModuleNotFoundError: No module named ‘Cython’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘Cython’问题 摘要 在使用 PyCharm 控制台或命令行执行 pip install Cython 时&#xff0c;常会遇到 ModuleNotFoundError: No module named Cython 的报错。本…

freertos任务调度关键函数理解 vTaskSwitchContext

void vTaskSwitchContext(void) {//my_printf( "uxSchedulerSuspended %d\n", uxSchedulerSuspended );/* 调度器处于挂起状态 */if (uxSchedulerSuspended ! (UBaseType_t)pdFALSE) {/*** The scheduler is currently suspended - do not allow a context* switch.…

CPU 密集型 和 I/O 密集型 任务

文章目录**CPU 密集型任务&#xff08;CPU-bound&#xff09;**定义&#xff1a;特点&#xff1a;常见场景&#xff1a;如何优化 CPU 密集型任务&#xff1a;**I/O 密集型任务&#xff08;I/O-bound&#xff09;**定义&#xff1a;特点&#xff1a;常见场景&#xff1a;如何优化…

[2025CVPR-小目标检测方向]基于特征信息驱动位置高斯分布估计微小目标检测模型

核心问题 ​小目标检测性能差&#xff1a;​​ 尽管通用目标检测器&#xff08;如 Faster R-CNN, YOLO, SSD&#xff09;在常规目标上表现出色&#xff0c;但在检测微小目标&#xff08;如 AI-TOD 基准定义的&#xff1a;非常小目标 2-8 像素&#xff0c;小目标 8-16 像素&…