redis分布式锁在项目中的应用总结

项目应用

应用1

redis分布式锁实现两个操作的原子性

需求:实现一人一单业务逻辑时(如果能走到这个逻辑,代表库存是充足的),我们需要

  • 先查询订单

  • 如果订单不存在即没有买过则创建订单

这两个步骤我们要保证是原子性的。在高并发情况下,如果多个线程都查询订单,发现订单都不存在,那么就会出现一人多单的问题。

解决方案1:我们使用redis分布式锁实现。

@Transactional
public Result createVoucherOrder(Long voucherId) {// TODO 5.一人一单Long userId = UserHolder.getUser().getId();// TODO 5.1.查询订单Integer count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();// TODO 5.2.判断是否买过if (count > 0) {return Result.fail("用户已经购买过一次了");}// TODO 6.扣减库存boolean success = seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherId).gt("stock", 0).update();if (!success) {return Result.fail("库存不足");}// TODO 7.创建订单VoucherOrder voucherOrder = new VoucherOrder();long orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);voucherOrder.setUserId(userId);voucherOrder.setVoucherId(voucherId);save(voucherOrder);// TODO 8.返回订单idreturn Result.ok(orderId);
}

解决方案2:用lua脚本来保证多个步骤的原子性。

local voucherId = argv[1]
local userId = argv[2]
​
local stockKey = 'seckill:stock:'..voucherId
local orderKey = 'seckill:order:'..voucherId
​
-- 查询库存量
if(tonumber(redis.call('get',stockKey))<=0) thenreturn 1
end
-- 一人一单
if( redis.call('sismember',orderKey,userId)==1) thenreturn 2
end
​
-- 扣减库存、订单key中新增用户id
redis.call('incrby',stockKey,-1)
redis.call('sadd',orderKey,userId)

当redis执行这一段lua脚本时,是单线程的,保证了原子性。可以看到lua脚本里保证了查询缓存+操作缓存这两个步骤的原子性。

应用2

redis分布式锁实现互斥执行

redis分布式锁可以用在解决缓存雪崩缓存击穿问题。

缓存雪崩:大量缓存数据在同一时间过期,或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增。

缓存击穿:如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮。

以上两种情况都存在相似的问题:

  1. 大量请求查询缓存发现失效

  2. 接着查询数据库

  3. 将数据写入缓存

我们希望查询数据库是互斥执行的,因此我们使用redis分布式锁,保证只有一个请求查询数据库,而其他请求未获取到锁的,循环重试。但在获取锁之前要判断缓存是否已经有数据了,如果已经有数据了则不用再查询数据库了。

但是仔细分析,缓存雪崩是大量缓存失效,而缓存击穿仅仅是一个缓存失效。如果用redis分布式锁解决缓存雪崩的,那速度应该会很慢吧。

以上就是redis分布式锁解决缓存击穿问题的具体应用。

应用3

redis分布式锁防止同一任务重复执行

需求:一个被@Scheduled标识的定时任务,在每天的凌晨2点都会执行一次。如果在集群的环境下,比如两台机器都部署了当前的项目,那么就会出现这个定时任务在同一个时间点被执行了两次。

解决方法:采用redis分布锁,如果一台机器抢到了分布式锁,那么就执行定时任务,如果没抢到,不作处理。抢到分布式锁的机器执行完定时任务后,我们【不应该直接释放锁】,因为可能出现服务器时间不一致的问题,可能你释放锁之后,另外一个服务器到了自己该执行这个定时任务的时间后抢了锁,然后执行定时任务,这不是就又出现了重复执行的问题了吗?因此我们可以设置锁自动释放时间,比如我们设置两小时后再释放锁,服务器误差不可能超过两小时吧?总之思路就是【采用自动释放锁】。

在CacheService类(一个专门用来装着操作redis的各种方法)中定义加锁逻辑:

/*** 加锁*/
public boolean tryLock(String name,long expire){String key = name + "_lock";String token = UUID.randomUUID().toString();Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(key, token, expire, TimeUnit.MINUTES);return BooleanUtils.isTrue(success);
}
@Override
@Scheduled(cron = "0 */1 * * * ?")//每一分钟执行一次
public void refreshToList() {boolean success = cacheService.tryLock("FUTURE_TASK_SYNC", 1000 * 30);//锁自动释放时间// 如果抢到锁,则执行定时任务;如果未抢到锁,不作处理if(success){// TODO 1.获取zset中的所有keySet<String> futureKeys = cacheService.scan(ScheduleConstants.FUTURE + "*");// TODO 2.根据key查出满足执行时间在【0-当前时间】的任务for (String futureKey : futureKeys) {Set<String> task = cacheService.zRangeByScore(futureKey, 0, System.currentTimeMillis());
​if(!task.isEmpty()){// TODO 3.将任务同步到list中,并把任务在zset中删除String topicKey = ScheduleConstants.TOPIC+futureKey.split(ScheduleConstants.FUTURE)[1];
​cacheService.refreshWithPipeline(futureKey,topicKey,task);log.info("成功的将"+futureKey+"任务同步到"+topicKey+new Date(System.currentTimeMillis()));}}}
}

参考:

集群部署中解决定时任务重复执行的问题-redis分布式锁应用-腾讯云开发者社区-腾讯云

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

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

相关文章

前端 react 面试题(二)

文章目录 hooks的使用规则为什么hooks要确保在函数组件的最顶层,而不能放置在循环或者条件语句中。react的事件模型react的合成事件是如何实现的react事件传参,可以使用箭头函数或bind方法,这两种哪一种更好使用箭头函数:使用`bind`方法:react的事件模型和vue的区别React …

1分钟解决Excel打开CSV文件出现乱码问题

一、编码问题 1、不同编码格式 CSV 文件有多种编码格式&#xff0c;如 UTF - 8、UTF - 16、ANSI 等。如果 CSV 文件是 UTF - 8 编码&#xff0c;而 Excel 默认使用的是 ANSI 编码打开&#xff0c;就可能出现乱码。例如&#xff0c;许多从网络应用程序或非 Windows 系统生成的 …

【python】OpenCV—Tracking(10.4)—Centroid

文章目录 1、任务描述2、人脸检测模型3、完整代码4、结果展示5、涉及到的库函数6、参考 1、任务描述 基于质心实现多目标&#xff08;以人脸为例&#xff09;跟踪 人脸检测采用深度学习的方法 核心步骤&#xff1a; 步骤#1&#xff1a;接受边界框坐标并计算质心 步骤#2&…

GraphQL系列 - 第2讲 Spring集成GraphQL

目录 一、maven依赖二、Schema 定义三、代码集成3.1 创建模型类3.2 创建服务类3.3 创建控制器类 四、单元测试五、实际 HTTP 请求测试5.1 查询单个 Person5.2 查询所有 People5.3 添加 Person 六、其他6.1 开启graphiql6.2 开启schema查看端点 一、maven依赖 首先&#xff0c;…

Golang | Leetcode Golang题解之第526题优美的排列

题目&#xff1a; 题解&#xff1a; func countArrangement(n int) int {f : make([]int, 1<<n)f[0] 1for mask : 1; mask < 1<<n; mask {num : bits.OnesCount(uint(mask))for i : 0; i < n; i {if mask>>i&1 > 0 && (num%(i1) 0 |…

模拟栈的实现

栈的概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出 LIFO &#xff08; Last In First Out &#xff09;的原则。 压栈&…

Win10搭建SFTP服务器

1、下载安装 Release v9.5.0.0p1-Beta PowerShell/Win32-OpenSSH GitHub 下载OpenSSH-Win64.zip 解压之后放入到&#xff1a;C:\Program Files (x86)\OpenSSH-Win64以管理员身份打开CMD进入到 C:\Program Files (x86)\OpenSSH-Win64 文件夹执行命令 powershell.exe -Exec…

WordPress网站添加嵌入B站视频,自适应屏幕大小,取消自动播放

结合bv号 改成以下嵌入式代码&#xff08;自适应屏幕大小,取消自动播放&#xff09; <iframe style"width: 100%; aspect-ratio: 16/9;" src"//player.bilibili.com/player.html?isOutsidetrue&bvidBV13CSVYREpr&p1&autoplay0" scrolling…

C语言内幕--全局变量(结合内存分区、汇编视角看类型、连接器)

前言 学习资源&#xff1a;b站up主&#xff1a;底层技术栈学过C语言都知道&#xff0c;全局变量可以再全局中使用&#xff0c;其实全局变量内部还是涉及到不少知识&#xff0c;这里从内存分区、汇编视角看类型、连接器等角度看待全局变量&#xff1b;由于涉及到底层技术&#…

省级-建成区绿化覆盖率数据(2006-2022年)

建成区绿化覆盖率是指城市建成区的绿化覆盖面积占建成区的百分比。 城市绿化覆盖率的提升&#xff0c;不仅能够改善城市的空气质量&#xff0c;降低噪音污染&#xff0c;还能提高城市的生物多样性&#xff0c;为市民提供更多的休闲和娱乐空间。 2006年-2022年省级-建成区绿化…

基于CNN-BiLSTM的时间序列数据预测,15个输入1个输出,可以更改数据集,MATLAB代码

1. 数据收集与预处理 数据清洗&#xff1a;处理缺失值、异常值等。特征工程&#xff1a;提取有助于预测的特征。数据标准化&#xff1a;将时间序列数据标准化&#xff0c;使其具有零均值和单位方差&#xff0c;有助于模型训练。滑动窗口划分&#xff1a;将时间序列数据划分为多…

SSM学习 day02

一、vue项目开发流程 vue根组件 <template><div><h1>{{ message }}</h1><element-view></element-view></div> </template><script> import ElementView from ./views/Element/ElementView.vue export default {compon…

【NOIP普及组】 FBI树

【NOIP普及组】 FBI树 C语言版本C 版本Java版本Python版本 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 我们可以把由“0”和“1”组成的字符串分为三类&#xff1a;全“0”串称为B串&#xff0c;全“1”串称为I串&#xff0c;既含“0”又…

大数据新视界 -- 大数据大厂之数据质量管理全景洞察:从荆棘挑战到辉煌策略与前沿曙光

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

基于 webpack 项目接入 vite 你可能需要注意的点

前言 在之前的 如何优化你的 vue-cli 项目&#xff1f; 一文中介绍基于 webpack 进行的一些优化方法&#xff0c;本文的核心是基于一个 vue2 的项目&#xff08;也就是上篇文章中的项目&#xff09;来继续介绍一下如何接入 vite&#xff0c;以及这个过程中需要关注的点。 之前…

Python工具箱系列(五十七)

图像分割与人脸识别 众所周知图像是由若干有意义的像素组成的&#xff0c;图像分割作为计算机视觉的基础&#xff0c;对具有现有目标和较精确边界的图像进行分割&#xff0c;实现在图像像素级别上的分类任务。图像分割可分为语义分割和实例分割两类&#xff0c;区别如下&#x…

日志代码编写

&#x1f30e;日志代码编写 文章目录&#xff1a; 日志代码编写 了解日志 日志编写       日志等级       获取时间信息       获取文件名行号及处理可变参数列表       以宏的形式传参       日志加锁       日志消息输出方式 完整代码 …

告别繁琐统计,一键掌握微信数据

微信数据管理的挑战在数字时代&#xff0c;微信已成为我们日常沟通和商业活动的重要工具。然而&#xff0c;随着微信号数量的增加&#xff0c;手动统计每个账号的数据变得越来越繁琐。从好友数量到会话记录&#xff0c;再到转账和红包&#xff0c;每一项都需要耗费大量的时间和…

【第几小】

题目 代码 //分块可以AC 20个点的块长&#xff0c; sqrt(n)*5#include<bits/stdc.h> using namespace std;int main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int n; cin>>n;vector<int> a(n1,0);//分块int len sqrt(n)*5; //块长int k (n%len…

详细分析Pytorch中的transpose基本知识(附Demo)| 对比 permute

目录 前言1. 基本知识2. Demo 前言 原先的permute推荐阅读&#xff1a;详细分析Pytorch中的permute基本知识&#xff08;附Demo&#xff09; 1. 基本知识 transpose 是 PyTorch 中用于交换张量维度的函数&#xff0c;特别是用于二维张量&#xff08;矩阵&#xff09;的转置操…