Redis之秒杀系统

目录

Redis 秒杀

Mysql数据库设计

Mysql秒杀实现

Mysql+Redis秒杀实现


秒杀是一种高并发场景,通常指的是在短时间内(秒级别)有大量用户同时访问某个商品或服务,争相抢购的情景。在这种情况下,系统需要处理大量并发请求,确保公平性、一致性,并防止因并发而导致的问题,例如超卖、恶意请求等。以下是在高并发秒杀场景下需要考虑的一些关键问题和解决方案:

  1. 超卖问题: 大量用户同时抢购同一商品可能导致超卖(卖出超过库存数量)的问题。为了解决这个问题,可以采用悲观锁或乐观锁的方式来控制库存的访问。数据库的行级锁、分布式锁等技术都可以用来防止超卖。

  2. 性能优化: 高并发场景下,系统性能是关键。使用缓存、异步处理、CDN 加速等手段可以显著提升系统的性能。缓存可以存储商品信息、用户状态等,减轻数据库压力。异步处理可以将一些不需要即时返回结果的操作异步执行,减轻请求的响应时间。

  3. 并发控制: 在高并发场景下,为了防止系统崩溃或服务不可用,需要对并发进行控制。可以使用队列、限流等技术,确保系统在承受能力范围内处理请求,防止系统超负荷崩溃。

  4. 秒杀令牌和时间窗口: 可以在系统中引入秒杀令牌,只有携带有效令牌的用户才能参与秒杀。同时,可以设置一个时间窗口,只在特定的时间范围内允许秒杀操作,有效控制请求的涌入。

  5. 用户鉴权和防刷: 针对恶意请求,需要进行用户鉴权,并采用防刷策略。例如,限制同一用户在短时间内的请求次数,通过验证码等方式增加用户请求的成本,防止恶意请求。

  6. 队列和异步处理: 使用消息队列将用户的秒杀请求进行排队,然后异步处理。这样可以有效地削峰填谷,减轻系统瞬时的压力,提高系统的容错能力。

  7. 分布式事务: 如果系统是分布式的,需要考虑分布式事务的问题。确保在秒杀过程中的各个阶段,包括扣减库存、生成订单等,能够保持事务的一致性。

  8. 实时监控和日志记录: 在高并发场景下,实时监控是及时发现问题、解决问题的关键。记录详细的日志信息,包括用户请求日志、系统性能日志等,便于事后分析和优化。

Redis 秒杀

Mysql数据库设计

/*
SQLyog Community v11.26 (32 bit)
MySQL - 8.0.33 : Database - test
*********************************************************************
*//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE=''*/;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`test` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;USE `test`;/*Table structure for table `stock` */DROP TABLE IF EXISTS `stock`;CREATE TABLE `stock` (`id` BIGINT NOT NULL AUTO_INCREMENT,`name` VARCHAR(20) DEFAULT NULL,`count` INT DEFAULT NULL,`create_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;/*Data for the table `stock` */INSERT  INTO `stock`(`id`,`name`,`count`,`create_time`) VALUES (1,'apple',500,'2023-11-28 19:02:04'),(2,'huawei',500,'2023-11-28 19:02:26');/*Table structure for table `stock_order` */DROP TABLE IF EXISTS `stock_order`;CREATE TABLE `stock_order` (`id` BIGINT NOT NULL AUTO_INCREMENT,`name` VARCHAR(20) DEFAULT NULL,`price` INT DEFAULT NULL,`create_time` TIMESTAMP NULL DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1729467951815541250 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;/*Data for the table `stock_order` *//*Table structure for table `article_select` */DROP TABLE IF EXISTS `article_select`;/*!50001 DROP VIEW IF EXISTS `article_select` */;
/*!50001 DROP TABLE IF EXISTS `article_select` */;/*!50001 CREATE TABLE  `article_select`(`a` bigint ,`b` varchar(11) ,`c` varchar(20) ,`d` bigint 
)*/;/*View structure for view article_select *//*!50001 DROP TABLE IF EXISTS `article_select` */;
/*!50001 DROP VIEW IF EXISTS `article_select` */;/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `article_select` (`a`,`b`,`c`,`d`) AS select `article`.`id` AS `id`,`article`.`name` AS `name`,`article`.`des` AS `des`,`article`.`categoryid` AS `categoryid` from `article` */;/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

Mysql秒杀实现

秒杀代码设计初步代码如下:

@RestController
public class MyController {@AutowiredStockMapper stockMapper;@AutowiredStockOrderMapper stockOrderMapper;@Transactional@GetMapping("/order/{id}")public String order(@PathVariable("id") Long id){Stock stock = stockMapper.selectById(id);Integer count = stock.getCount();if(count<=0){throw new RuntimeException("库存不足");}StockOrder stockOrder=new StockOrder();stockOrder.setName(stock.getName());stockOrderMapper.insert(stockOrder);UpdateWrapper<Stock> updateWrapper=new UpdateWrapper<>();updateWrapper.setSql("count = count - 1 where count > 0 and id ="+id); //在mysql这里执行的时候,数据库会加行锁,所以相对是安全的int update = stockMapper.update(null, updateWrapper);if(update<=0){throw new RuntimeException("库存不足");}return "success";}
}

由于业务代码直接与mysql数据库进行交互,mysql一秒支持的并发量低,性能较低,然后下面进行压测:

压测得到的汇总报告如下图:

Mysql+Redis秒杀实现

使用redis修改代码如下:

@RestController
public class MyController {@AutowiredStringRedisTemplate stringRedisTemplate;@AutowiredStockMapper stockMapper;@AutowiredStockOrderMapper stockOrderMapper;@PostConstructpublic void init(){List<Stock> stocks = stockMapper.selectList(null);for (Stock stock : stocks) {stringRedisTemplate.opsForValue().set("product_"+stock.getId(),stock.getCount()+"");}}@GetMapping("/order/{id}")public String order(@PathVariable("id") Long id){Long decrement = stringRedisTemplate.opsForValue().decrement("product_" + id);if(decrement<0){stringRedisTemplate.opsForValue().increment("product_"+id);return "库存不足";}try {((MyController)AopContext.currentProxy()).mys_order(id);}catch (Exception e){stringRedisTemplate.opsForValue().increment("product_"+id);return "库存不足";}return "购买成功";}@Transactionalpublic void mys_order(Long id){Stock stock = stockMapper.selectById(id);if(stock.getCount()<=0){throw new RuntimeException("库存不足");}StockOrder stockOrder=new StockOrder();stockOrder.setName(stock.getName());stockOrderMapper.insert(stockOrder);UpdateWrapper<Stock> updateWrapper=new UpdateWrapper<>();updateWrapper.setSql("count = count - 1 where count > 0 and id ="+id); //在mysql这里执行的时候,数据库会加行锁,所以相对是安全的int update = stockMapper.update(null, updateWrapper);if(update<=0){throw new RuntimeException("库存不足");}}
}

压测结果吞吐量如下图,使用redis作为缓存相对于仅仅使用mysql数据库吞吐量提升了不少,性能得到了提升。

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

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

相关文章

P27 C++this 关键字

目录 前言 01 this关键字的引入 02 this关键字 前言 本章的主题是 C 中的 this 关键字。 以前第一次学qt的时候就遇到了this关键字&#xff0c;那时候还不是很会C&#xff0c;所以有点懵&#xff0c;现在我们就来讲解以下C中的this关键字 C 中有一个关键字 this&#xff0…

多种卫星遥感数据反演黑龙江省蒸腾与蒸散(ET)数据服务

引言 多种卫星遥感数据反演黑龙江省地表蒸腾与蒸散率&#xff08;ET&#xff09;产品是地理遥感生态网平台推出的生态环境类数据产品之一&#xff0c;产品包括1981-2023年数据&#xff0c;&#xff0c;数据类型为8bit整型。该产品经过数据搜集—模型模拟—质量检查—地表蒸腾与…

“前端已死”?从ChatGPT与低代码平台看未来编程之路

每隔一段时间&#xff0c;“前端已死”的论调就会如潮水般重新涌现&#xff0c;引发行业内外的热议。这种论调背后&#xff0c;除了对于新技术&#xff0c;如ChatGPT、GPT-4对前端开发者影响的担忧&#xff0c;还反映了人们对于技术变革的焦虑。 作为前端开发者&#xff0c;我坚…

数据预处理:随机裁剪放缩

随机裁剪放缩是一种数据增强技术&#xff0c;可以在训练神经网络时增加数据的多样性&#xff0c;提高模型的泛化能力。具体来说&#xff0c;随机裁剪放缩可以通过随机裁剪和缩放原始图片来生成多个不同的训练样本&#xff0c;从而增加数据集的大小和多样性。这种技术在图像分类…

小航助学题库蓝桥杯题库python选拔赛(23年8月)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSDN博客 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSD…

BOM浏览器对象模型

BOM(Browser Object Model) 浏览器对象模型 操作浏览器api和接口 1.打开链接 返回一个窗口对象 w window.open(url,"_blank",wi…

C++——取地址和自增运算

今天做了道题一下给我整蒙了&#xff0c;把实验探索发篇文章&#xff0c;题目如下&#xff1a; int a[]{10,11,12},*p&a[0];执行完*p;*p1;后a[0],a[1],a[2]的值各为多少 答案是 10, 12, 12怎么理解*p,*p1呢&#xff0c;我觉得可以用汉语把代码读一下&#xff0c;p&#xf…

SAP PI SFTP适配器发送方和接收方文件编码转换问题

Sender Adapter 发送方 PI默认是以UTF-8解析文件内容&#xff0c;当文件内容为日文或其他编码时&#xff0c;非英文、数字的内容解析结果将会是乱码&#xff0c;需要在PI中做以下设置。 Advanced页签->Advanced Mode中添加参数&#xff1a;encodingFormat MS932&#xff…

基于PaddleOCR银行卡识别实现(三)

前言 基于PaddleOCR银行卡识别实现&#xff08;一&#xff09; 基于PaddleOCR银行卡识别实现&#xff08;二&#xff09; 前两篇文章讲了检测模型和识别模型的实现&#xff0c;这一篇文章姗姗来迟&#xff0c;将讲解下两个模型的串联应用和PaddleOCR的源码精简&#xff0c;下面…

新手老师如何管理班级的日常工作

作为一名新手老师&#xff0c;管理班级的日常工作可能会是一项挑战&#xff0c;但以下是一些可能有用的建议&#xff1a; 建立良好的班级文化 班级文化是班级氛围的重要组成部分&#xff0c;对于学生的学习和成长具有重要影响。作为老师&#xff0c;要积极营造一种积极向上、团…

Jenkins 如何查看已经记录登录服务器的凭证密码

文章目录 一、背景描述二、解决方案一&#xff08;查看所有账号密码&#xff09;三、解决方案二&#xff08;查询指定账号密码&#xff09; 一、背景描述 在日常的开发过程中&#xff0c;有时候会出现忘记开发、测试服务器的登录密码的情况。此时恰巧 Jenkins 上记录了登录该主…

AI工具导航网站(包含写作、翻译、设计、论文润色去重的AI工具集)

人工智能工具导航网站集合了国内外各种热门、创意、有趣、前沿的AI工具盒网站&#xff0c;方便用户迅速访问和体验各种AI应用。 关注底部公众号回复"126899"获取工具集链接。 一、写作翻译编程设计AI工具集 AI写作工具&#xff1a;这些工具可以帮助用户生成或优化各…