秒杀系统设计与实现

将从11 个点来进行秒杀系统得设计与实现分析。

1、哪些地方存在瞬时高并发?

  • 1. 预抢购业务:活动未正式开始前,先进行活动预约。在真正秒杀的时间点,很多数据都是预处理好的了,可以很大程度削减系统压力。比如:活动预约、订金预约、火车票预约等
  • 2. 分批抢购业务:分时段多场次抢购,比如我们熟悉的京东满减优惠券就是分场次开放的,整点抢购。
  • 3. 实时秒杀:这是最有难度的秒杀场景,比如双11晚上0点秒杀,在这个时间点前后会涌入高并发流量:频繁刷新页面、疯狂点击抢购按钮、甚至利用机器模拟请求。

2、活动页面得设计

因为用户浏览商品等常规操作,并不会请求到服务端。只有到了秒杀时间点,并且用户主动点了秒杀按钮才允许访问服务端。所以为了减少不必要的服务端请求,通常情况下,会对活动页面做静态化处理

CDN,它的全称是Content Delivery Network,即内容分发网络。用于用户分布在全国各地,有些人在北京,有些人在上海,有些人在深圳,地域相差很远,网速各不相同得情况。

3、秒杀按钮

使用js文件控制秒杀活动在活动开始前得秒杀按钮,可以通过在js中设置标记的方式来设置按钮的状态,比如isBegin=true代表活动开始,isBegin=false代表活动未开始。秒杀开始之前,js标志为false,秒杀活动开始时设置为true。为了达到这个效果,我们另外还需要一个随机参数用来主动刷新CDN。

当秒杀开始的时候系统会生成一个新的js文件,此时标志为true,并且随机参数生成一个新值,然后同步给CDN。由于有了这个随机参数,CDN不会缓存数据,每次都能从CDN中获取最新的js代码。

4、多读写少

这种情况下就要考虑做缓存,使用 redis对访问读得数据进行缓存。

5、缓存怎么做?

缓存雪崩:大量缓存数据同时过期、redis宕机故障。解决方法:给key添加随机过期时间。

缓存击穿:热点数据缓存过期,一个或几个高并发使用得Key失效。 解决方法:分布式锁,redis里面没有的时候,查数据库得时候要先获取分布式锁。 预热,事先把参与秒杀的所有商品,同步到缓存中,这样商品基本都能直接从缓存中获取到,就不会出现缓存击穿的问题了。双保险

缓存穿透:数据不存在,既不在redis里面,也不在数据库里面。解决方法:布隆过滤器,布隆过滤器(BloomFilter)是一种数据结构。特点是存在性检测如果布隆过滤器中不存在,那么实际数据一定不存在;如果布隆过滤器中存在,实际数据不一定存在。相比于传统数据结构(如:List、Set、Map等)来说,它更高效,占用空间更少。缺点是它对于存在的判断是具有概率性。但是有一个数据一致性问题,所以布隆过滤器建议使用在缓存数据更新很少的场景中。

可以巧妙设计一下,把不存在的商品id也缓存起来。

6、库存问题

为了防止超卖或负数得情况,就要考虑 预扣库存。

数据库扣减库存:基于数据库的乐观锁,这样会少一次数据库查询,而且能够天然的保证数据操作的原子性。

 redis扣减库存:redis的incr方法是原子性的,可用于扣减库存 

  1. 先判断该用户有没有秒杀过该商品,如果已经秒杀过,则直接返回-1。
  2. 扣减库存,判断返回值是否小于0,如果小于0,则直接返回0,表示库存不足。
  3. 如果扣减库存后,返回值大于或等于0,则将本次秒杀记录保存起来。然后返回1,表示成功。

Lua脚本扣减库存:使用Lua脚本的好处如下:

  1. 减少网络开销:可以将多个请求通过脚本的形式一次发送,减少网络时延
  2. 原子操作:redis会将整个脚本作为一个整体执行,中间不会被其他请求插入。因此在脚本执行过程中无需担心会出现竞态条件,无需使用事务
  3. 复用:客户端发送的脚本会永久存在redis中,这样其他客户端可以复用这一脚本,而不需要使用代码完成相同的逻辑

7、分布式锁

使用redis的set命令:result,err := redis.set(lockKey, requestId, "NX", "PX", expireTime);

  1. lockKey:锁的标识
  2. requestId:请求id。在释放锁得时候,使用记录得requestId。
  3. NX:只在键不存在时,才对键进行设置操作。
  4. PX:设置键的过期时间为 millisecond 毫秒。
  5. expireTime:过期时间

自旋锁:思路如下:

  1. 在规定的时间,比如500毫秒内,自旋不断尝试加锁
  2. 如果成功则直接返回
  3. 如果失败,则休眠50毫秒,再发起新一轮的尝试。
  4. 如果到了超时时间,还未加锁成功,则直接返回失败。

8、mq异步处理

如果使用mq,需要关注以下几个问题:

  1. 消息丢失问题
  2. 消息重复消费问题
  3. 垃圾消息问题
  4. 延迟消费问题

8.1消息丢失问题:加一张消息发送表、进行消息重发。

其流程如下:

  1. 在生产者发送mq消息之前,先把该条消息写入消息发送表,初始状态是待处理
  2. 然后再发送mq消息。
  3. 消费者消费消息时,回调生产者的一个接口,处理完业务逻辑之后,修改消息状态为已处理。

使用job,增加重试机制。用job每隔一段时间去查询消息发送表中状态为待处理的数据,然后重新发送mq消息。

8.2、重复消费问题加一张消息处理表

8.3、 垃圾消息问题:限制重试次数

8.4、 延迟消费问题使用延迟队列,比如:RocketMQ,自带了延迟队列的功能。

  1. 下单时消息生产者首先生成订单,此时为待支付状态。
  2. 然后向延迟队列中发一条消息。
  3. 当达到了延迟时间,消息消费者读取消息之后,会查询该订单的状态是否为待支付。
  4. 如果是待支付状态,则会更新订单状态为取消状态。
  5. 如果不是待支付状态,说明该订单已经支付过了,则直接返回。

9、限流

对同一用户限流对同一ip限流 对接口限流 加验证码提高业务门槛

提高业务门槛流程是仿12306进行业务设计:

  1. 我们可以通过提高业务门槛,比如只有会员才能参与秒杀活动,普通注册用户没有权限。
  2. 或者只有等级到达3级以上的用户,才有资格参加该活动。
  3. 或者分时间段获得秒杀资格,比如9点、10、11点、参加活动获得秒杀资格,获得资格的朋友12点集中参与秒杀。

10、数据库层隔离

分库分表:先从代码、SQL语句、索引这几个方面着手优化,不行了在进行分库分表。

数据隔离:用专门的表来存放数据,不建议使用业务系统正在使用的表来存放秒杀相关的数据。

数据合并:如果秒杀系统是用的专用表存储,在秒杀活动结束后,需要将其和现有数据进行合并。

11、压力测试

正压力测试:在保证服务器资源不变的情况下,网络请求不断做加法。

负压力测试:在系统正常运行的情况下,逐渐减少支撑系统的服务器资源,观察什么时候系统无法在支撑正常的业务请求。

压力测试步骤:

1.确定测试目标

压力测试和性能测试不同,压力测试的目标是什么时候系统会接近崩溃,比如需要支持100万的访问量,测试出性能阈值。

2. 确定关键问题

二八原则大家一定要知道,压力测试也是有重点的,系统中只有20%的功能是最常用的,比如秒杀接口、下单、扣减库存。要集中火力测试常用的功能,高度还原真实场景。

3. 确定负载

和上面观点一样,不是每个服务都有高负载,测试时要重点关注高负载的服务,真实场景中服务的负载一定是波动的,并且不是均匀分布的。

4. 搭建环境

搭建环境要和生产环境保持一致。

5. 确定监测指标

提前确定好要重点监测的参数指标,比如:CPU负载、内存使用率、系统吞吐量、带宽阈值等

6. 产生负载

  1. 建议优先使用往期的秒杀数据,或者从生产环境中同步数据进行测试
  2. 根据目标系统的承受要求由脚本驱动测试
  3. 模拟不同网络环境,对硬件条件有规律的进行测试

7. 执行测试

根据目标系统、关键组件、用负载进行测试、返回监测点的数据。

8. 分析数据

针对测试的目的,对关键服务的压力测试数据进行分析,得出这些服务的承受上限在哪里?

对有波动的负载或者大负载的的服务进行数据分析,明确优化的方向。

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

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

相关文章

03 Shell编程之循环语句与函数

目录 3.1 for 循环语句 3.1.1 for 语句的结构 3.1.2 for 语句应用示例 1. 根据姓名列表批量添加用户 2. 根据IP地址列表检查主机状态 3.2 使用while循环语句 3.2.1 while语句的结构 3.2.2 while语句应用示例 1. 批量添加规律编号的用户 2. 猜价格游戏 3.3 until 循环语句 3.…

aws的eks(k8s)ingress+elb部署实践

eks(k8s)版本1.29 ingress 版本1.10.0 负载均衡elb 1. 创建Ingress-Nginx服务 部署项目地址【点我跳转】推荐自定义部署 可绑定acm证书什么的自己属性 这里就是aws上面Certificate Manager产品上面创建证书 导入 创建都行 对应集群版本推荐阵列GitH…

503.下一个更大元素||

循环解题&#xff1a; class Solution { public:vector<int> nextGreaterElements(vector<int>& nums) {int n nums.size();vector<int> res;for (int i 0; i <n; i){int k i;bool flag false;for (int j 1;j <n-1;j){if((kj)%n ! k &&a…

MySQL中实现随机排序

MySQL中实现随机排序有多种方法&#xff1a; 1、使用 RAND() 函数 通过使用 RAND() 函数可以给每条记录生成一个随机数&#xff0c;然后按照这个随机数进行排序。例如&#xff1a; SELECT * FROM table_name ORDER BY RAND();这种方法简单易用&#xff0c;但不适用于大数据量…

Arc2Face - 一张图生成逼真的多风格人脸,本地一键整合包下载

Arc2Face是用于人脸的基础模型训练&#xff0c;可批量生成超高质量主题的AI人脸艺术风格照&#xff0c;完美复制人脸。只需一张照片&#xff0c;几秒钟&#xff0c;即可批量生成超高质量主题的AI人脸艺术风格照&#xff0c;完美复制人脸。 Arc2Face 是一个创新的开源项目&…

微信小程序-scroll-view实现上拉加载和下拉刷新

一.scroll-view实现上拉加载 scroll-view组件通过自身一些属性实现上拉加载的功能。 lower-threshold“100"属性表示距离底部多少px就会实现触发下拉加载的事件。 类似于在.json文件里面配置"onReachBottomDistance”: 100 bindscrolltolower"getMore"属…

测评:【ONLYOFFICE】版本更迭与AI加持下的最新ONLYOFFICE桌面编辑器8.1

你是否还在为没有一款合适的在线桌面编辑器而苦恼&#xff1f;你是否还在因为办公软件的选择过少而只能使用WPS或者office&#xff1f;随着办公需求的不断变化和发展&#xff0c;办公软件也在不断更新和改进。ONLYOFFICE 作为一款全功能办公软件&#xff0c;一直致力于为用户提…

WordPress如何删除前端评论中的网址字段?

前面跟大家分享的『WordPress插件Comment Link Remove and Other Comment Tools&#xff0c;删除评论网址字段』一文&#xff0c;通过安装插件可轻松删除前端评论中的网址字段&#xff0c;不过有些站长不喜欢安装插件&#xff0c;那么是否可以通过纯代码去掉网址字段呢&#xf…

车辆检测之图像识别

1. 导入资源包 import torch.nn as nn import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTk,ImageDraw,ImageFont import torch from torchvision import transforms, models from efficientnet_pytorch import EfficientNet im…

微信QQ视频裂变加群推广强制分享引流系统

用户在达到一定观看次数后&#xff0c;需要分享给好友或群组。只有好友点击推广链接后&#xff0c;观看次数才会增加。 通过引导用户分享至QQ和微信&#xff0c;实现快速裂变引流的效果&#xff01; 视频裂变推广程序通过强制分享链接&#xff0c;引导用户转发&#xff0c;从…

代理IP知识:导致代理IP访问超时的原因有哪些?

很多用户在使用代理IP进行网络访问时&#xff0c;可能会遇到代理IP超时的情况&#xff0c;也就是代理IP的延迟过高。代理IP延迟过高会影响用户的网络体验和数据获取效率。因此&#xff0c;了解代理IP延迟过高的原因很重要。以下是导致代理IP延迟过高的一些常见原因&#xff1a;…

怎么使用RSI指标分析现货黄金行情走势?

拿到一波现货黄金行情走势&#xff0c;如何着手对其进行分析呢&#xff1f;投资者只要在网络上搜索一下&#xff0c;保管能够找到各种各样的答案&#xff0c;而本文要讨论的就是其中一种&#xff0c;我们借助RSI指标进行分析。 RSI就是相对强弱指标的简称&#xff0c;这是市场中…

炎炎夏日,矿物质水为你防暑补水

炎炎夏日&#xff0c;整座城市如同一个巨大的“烤箱” 人们行走在炙热烈阳中 汗如雨下&#xff0c;口干舌燥 在这样的高温天气中 中暑的风险也随之增加 烈日当头的夏天 该如何预防中暑呢&#xff1f; 或许答案藏在一杯矿物质水中 为什么矿物质水能够预防中暑&#xff1f;…

编译xlnt开源库源码, 使用c++读写excel文件

编译xlnt开源库源码,在linux平台使用c读写excel文件 下载xnlt源码 官方网站https://tfussell.gitbooks.io/xlnt/content/ 下载地址https://github.com/tfussell/xlnt 下载libstudxml开源库源码 下载地址https://github.com/kamxgal/libstudxml 下载xnlt源码 官方网站https://…

项目启动端口被占用

项目启动端口被占用 Identify and stop the process that’s listening on port XXXX or configure this application to listen on another port. 1、查询占用端口的pid netstat -aon|findstr "端口号"2、终止进程 taskkill /pid 进程号 /f3、重启项目

宝宝早教电子图书 酷得电子方案

宝宝早教发声书是一种专为婴幼儿设计的图书&#xff0c;旨在通过有趣的图画和声音来吸引宝宝的注意力&#xff0c;帮助他们学习语言、认知和发展各种技能。这类书籍通常包括以下特点&#xff1a; 鲜艳的图画&#xff1a;发声书通常配有色彩鲜艳、形象生动的图画&#xff0c;以…

Ceph入门到精通-shell脚本读取指定文件,并按行使用rclone命令进行复制操作

要使用shell脚本读取指定文件,并按行使用rclone命令进行复制操作,您可以编写一个简单的脚本来实现这一功能。以下是一个示例脚本,它将读取指定文件的每一行,然后使用rclone copy命令将远程存储中的文件复制到本地目录。 首先,创建一个新的shell脚本文件,例如download_fi…

Java Matcher类方法深度剖析:查找和匹配、索引方法

1. 引言 在Java中,正则表达式是处理字符串的强大工具,而java.util.regex包中的Matcher类则是实现这一功能的核心。对于Java工程师而言,熟练掌握Matcher类的使用方法,无疑能够极大地提升字符串处理的效率和准确性。本文将对Matcher类的方法进行深度讲解,并按照查找和匹配方…

el-tree检查当前节点是否是传入节点的父级或祖先节点

实现的效果就是&#xff1a;树形结构选中一个目录后点击收起的时候需要知道当前收起的是不是选中目录的父节点或者是祖先节点 这就用到了递归&#xff0c;什么是递归呢&#xff1f;简单来说递归就是方法自己调用自己&#xff0c;每次调用时传入不同的变量。一直到程序执行到指定…

spring的bean定义和扫描规则

1、bean的基本定义 在Spring框架中&#xff0c;Bean是一个核心概念&#xff0c;它是Spring IoC&#xff08;Inverse of Control&#xff0c;控制反转&#xff09;容器管理的一个对象实例。简单来说&#xff0c;Bean就是由Spring容器初始化、配置和管理的对象。这些对象可以是J…