分布式锁功效初探——以电商问题为例

文章目录

  • 电商库存问题
    • 单机处理-Sychronized
    • 多机器处理-分布式锁
      • 入门级别,用redis实现,setnx
        • 问题1:逻辑可能异常,造成死锁
        • 问题2:机器宕机
        • 问题3:锁一直失效,乱套
        • 锁续命
      • redisson
      • 分布式丢锁问题
        • 主从、分布式的情况下锁丢失
        • 红锁问题
      • 分布式锁性能优化
        • 锁的粒度越小越好
        • 分段锁
  • 电商可能存在问题(下单链路)
    • 订单重复生成
    • 付钱了,后台状态取消了
  • Future(成功监听处理)
  • Lua脚本(redisson内部加锁实现)
  • Apache JMeter工具(压测)

电商库存问题

redis里面存储库存
程序里面减
多并发可能会有问题(超卖)

单机处理-Sychronized

可以加锁解决(Sychronized),但是只能解决单机问题,在分布式多机器上用谨慎,很可能出BUG

多机器处理-分布式锁

前台Nginx,后台代码部署于多个tomcat,共用redis
多台机器,并发越多,超卖的情况就越明显

入门级别,用redis实现,setnx

setnx key value,当且仅当key不存在,否则会使用第一次的值,后续不会覆盖
利用这个特性去实现锁
因为redis核心命令执行是单线程,库存计算需要存redis,多次进来需要排队,根据是否存在指定key去判断

Boolean result = stringRedisTemplate.opsForValue().setIfAbsent("lockKey", "aaa");
//用返回结果去判断锁
if(!result){return "系统正在执行"
}
// 执行业务逻辑
// 注意删除锁
stringRedisTemplate.delete("lockKey")
问题1:逻辑可能异常,造成死锁

加try catch,删除放到finaly

try{// 执行业务逻辑
}finally{stringRedisTemplate.delete("lockKey")
}
问题2:机器宕机

锁,加过期时间

// 不要这样分开执行,因为宕机无时不在
stringRedisTemplate.expire("lockKey", 10, TimeUnit.SECONDS);// 使用元执行stringRedisTemplate.opsForValue().setIfAbsent("lockKey", "aaa", 10, TimeUnit.SECONDS);
问题3:锁一直失效,乱套

线程运行时间无法预料,会出现下面的问题
逻辑执行一半,过期时间到时,第二次请求又会进去,但是第一次把第二次的锁删了,第三次请求又会进去,第二次又将锁删除
问题根本点:自己的锁,被别的请求删除
解决:每一个锁的值用唯一值及进行标识,删除时做判断

// 设置锁,值为唯一值
String clientId = UUID.randomUUID().toString();
stringRedisTemplate.opsForValue().setIfAbsent("lockKey", clientId, 10, TimeUnit.SECONDS);// 删除锁,进行值判断
if(clientId.equals(stringRedisTemplate.opsForValue().get("lockKey"))){// 这儿又可能出现锁到时问题,也会有并发问题stringRedisTemplate.delete("lockKey")
}
锁续命

当一个请求过来,加锁成功,开始执行代码逻辑;
这时,在后台开启一个分线程,进行一个定时任务,定时给锁续命;
检查主线程锁是否被删掉,如果删掉了说明任务执行完成了,否则锁快到过期时间时,去延长锁的超时时间

redisson

jedis儿子
redisson github地址
引入依赖

<dependency><groupId>org.redisson</groupId><artifacId>redisson</artifacId><version>3.6.5</version>
</dependency>

配置

@Bean
public Redisson redisson(){// 此为单机模式Config config = new Config();config.useSingleServer().setAddress("redis://localhost:6379").setDatabase(8);return (Redisson) Redisson.create(config);
}

使用

@Autoried
private Redisson redisson;// 获取一把锁对象
RLock redissonLock = redisson.getLock("lockKey");
// 加锁
redissonLock.lock();try{// 执行业务逻辑
}finally{// 删锁redissonLock.unlock();
}

在这里插入图片描述

分布式丢锁问题

主从、分布式的情况下锁丢失

上面的实现,单机没问题。但是多机,在主从、分布式的情况下,会有问题
方案一:
zookeeper,主从节点,主leader,从flowwer,遵循CAP,满足一致性
存到主节点,还要同步到子节点,才能生效

redis遵循AP,满足可用性
存则立马生效

redis性能要比zookeeper强很多,但是zookeeper基本不会丢锁

方案二:
Redlock(红锁)
同zookeeper差不多,也需要将加锁key存到多个节点,只有超过半数节点返回添加成功,加锁才成功
这样,新的加锁请求如果存在问题,则不会超过半数,则不会加锁成功

尽量自己用一套分布式锁服务
在这里插入图片描述

红锁问题

问题1:高可用问题
不要通过主从节点去处理,同步的时候就可能有问题。新加锁,因为有子节点,所以半数的计算还是会有多并发问题

高可用,可以多加几个节点,防止节点被挂问题,一般用3-5个节点,注意用奇数节点,别用偶数

问题2:持久化问题
aof持久化方案,1s中一次,依然会丢锁
如果第二个节点不够1s,但是节点挂了,但是重启数据就会掉了,后续的就可以再在这个节点加锁
aof,百分百不丢锁不可能

如果用aways,每一条命令持久化一次,但是性能又太差了

分布式锁性能优化

在redis中是将并行转串行实现,但是特别高的并发,性能较低

锁的粒度越小越好

让串行执行的数量越小越好

分段锁

ConcurrentHashMap底层实现
在redis中分段存储
P_101 = 200
转化为
P_101_1 = 20

P_101_10 = 20
每一个段位都加一个锁
通过分发算法,去请求不同的redis,可以去进行多次并发打到不同请求

这样有多少个段位,就相当于提升了多少倍

电商可能存在问题(下单链路)

订单重复生成

快速多次点击提交订单
多个tab(浏览器)点击提交订单

通过分布式锁处理,key设为(userId + 购物车商品id排序(id1+id2+id2+…))

付钱了,后台状态取消了

马上过期的时候支付,支付成功了,但是后台取消了

通过分布式锁处理,支付的时候加一把锁(针对订单id),取消的时候加一把锁(针对订单id),key一样,则不会执行业务。

Future(成功监听处理)

Lua脚本(redisson内部加锁实现)

在Redis中执行,具备原子性

Apache JMeter工具(压测)

JAVA开发的压测软件,模拟多并发

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

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

相关文章

前菜---二叉树+堆的小练习

目录 前言&#x1f3dc;️ 1. 二叉树性质总结⛱️ 1.2 性质3⏰ 2. 二叉树性质小练习&#x1f3d5;️ 3. 答案解析&#x1f4a1; 4. 堆概念结构小练习&#x1fa94; 5. 答案解析&#x1f9ff; 6. 前/中/后/层序遍历小练习&#x1f52b; 7. 答案解析&#x1f9fa; 后语…

C++中的内存锁定

内存锁定(memory locking)是确保进程保留在主内存中并且免于分页的一种方法。在实时环境中&#xff0c;系统必须能够保证将进程锁定在内存中&#xff0c;以减少数据访问、指令获取、进程之间的缓冲区传递等的延迟。锁定内存中进程的地址空间有助于确保应用程序的响应时间满足实…

LeetCode 1954. 收集足够苹果的最小花园周长

一、题目 1、题目描述 给你一个用无限二维网格表示的花园&#xff0c;每一个 整数坐标处都有一棵苹果树。整数坐标 (i, j) 处的苹果树有 |i| |j| 个苹果。 你将会买下正中心坐标是 (0, 0) 的一块 正方形土地 &#xff0c;且每条边都与两条坐标轴之一平行。 给你一个整数 need…

DevC++ 用C语言的多线程 实现简单的客户端和服务器

知识来源一&#xff1a; 使用Dev-C实现简单的客户端和服务器-CSDN博客 此先生的博客使用的是win32 SDK来创建多线程&#xff0c;然后鄙人对这个版本的多线程细节不明。于是又重新用C语言的线程替代win32API,以此继续学习服务器代码。 知识来源二&#xff1a;DevC 多线程创建…

Windows 11中显示文件扩展名的方法与Windows 10大同小异,但前者更人性化

默认情况下&#xff0c;Windows 11会隐藏已知文件类型的文件扩展名。这可能会使在不首先打开文件的情况下很难识别文件类型。 幸运的是&#xff0c;你可以将Windows 11配置为显示已知文件类型的扩展名。该方法类似于Windows 10&#xff0c;但该选项现在组织在下拉菜单中&#…

在线客服系统:解决常见问题的实用工具与解决方案

市场得不断发展促使着消费者服务意识的觉醒&#xff0c;越来越多的消费者在购买产品的时候不仅看产品的功能、外观、性能&#xff0c;还关注品牌的服务质量。在线客服系统的出现帮助企业解决了客户服务难的问题。接下来&#xff0c;我们具体聊一聊在线客服系统能解决哪些问题&a…

BTF:实践指南

本文地址&#xff1a;BTF&#xff1a;实践指南 | 深入浅出 eBPF 1. BPF 的常见限制 1.1 调试限制1.2 可移植性2. BTF 是什么&#xff1f;3. BTF 快速入门 3.1 BPF 快速入门3.1 BTF 和 CO-RE4. 结论 BPF 是 Linux 内核中基于寄存器的虚拟机&#xff0c;可安全、高效和事件驱动…

Bresenham 算法

1965 年&#xff0c;Bresenham 为数字绘图仪开发了一种绘制直线的算法&#xff0c;该算法同样使用于光栅扫描显示器&#xff0c;被称为 Bresenham 算法。 原理 算法的目标是选择表示直线的最佳光栅位置。Bresenhan 算法在主位移方向上每次递增一个单位。另一个方向的增量为 0…

浅谈Redis分布式锁(下)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 自定义Redis分布式锁的…

分布式核心技术之分布式共识

文章目录 什么是分布式共识&#xff1f;分布式共识方法PoWPoSDPoS 三种分布式共识算法对比分析 选主过程就是一个分布式共识问题&#xff0c;因为每个节点在选出主节点之前都可以认为自己会成为主节点&#xff0c;也就是说集群节点“存异”&#xff1b;而通过选举的过程选出主节…

Qt 开源项目

Qt 开源项目 Omniverse View链接技术介绍 QuickQanava链接技术介绍QField链接技术介绍 AtomicDEX链接技术介绍 Status-desktop链接技术介绍 Librum链接技术介绍 A Simple Cross-Platform ReaderQPrompt链接技术介绍 GCompris链接技术介绍 Scrite链接技术介绍 QSkinny链接技术介…

【LeetCode】链表精选11题

目录 快慢指针&#xff1a; 1. 相交链表&#xff08;简单&#xff09; 2. 环形链表&#xff08;简单&#xff09; 3. 快乐数&#xff08;简单&#xff09; 4. 环形链表 II&#xff08;中等&#xff09; 5. 删除链表的倒数第 N 个节点&#xff08;中等&#xff09; 递归迭…