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

文章目录

  • 电商库存问题
    • 单机处理-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开发的压测软件,模拟多并发

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数独 -- 合法数独与完全数独

一、数独的介绍 从2004年底开始&#xff0c;数独游戏在英国变得非常流行。数独(Sudoku)是一个日语单词意思是数字位置之类的单词(或短语)。谜题的理念非常简单;面对一个9 9的网格&#xff0c;被分成9个3 3的块: 在其中的一些盒子里&#xff0c;设置者放一些数字1-9:求解者的目…

前端未死,顺势而生

随着人工智能和低代码的崛起&#xff0c;“前端已死”的声音逐渐兴起。前端已死&#xff1f;尊嘟假嘟&#xff1f;快来发表你的看法吧&#xff01; 一、“前端已死”因何而来&#xff1f; 在开始讨论之前&#xff0c;首先要明确什么是“前端”。 所谓前端&#xff0c;主要涉及…

vue使用ElementUI搭建精美页面入门

ElementUI简直是css学得不好的同学的福音 ElementUI官网&#xff1a; Element - The worlds most popular Vue UI framework 安装 在vue文件下&#xff0c;用这个命令去安装Element UI。 npm i element-ui -S step1\先切换到vue的目录下去&#xff0c;注意这里面的WARN不是…

每日一题:LCR 095.最长公共子序列(DP)

题目描述&#xff1a; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些…

R语言基础 | 安徽某高校《统计建模与R软件》期末复习

第一节 数字、字符与向量 1.1 向量的赋值 c<-(1,2,3,4,5) 1.2 向量的运算 对于向量&#xff0c;我们可以直接对其作加&#xff08;&#xff09;&#xff0c;减&#xff08;-&#xff09;&#xff0c;乘&#xff08;*&#xff09;&#xff0c;除&#xff08;/&#xff09…

使用Python实现发送Email电子邮件【第19篇—python发邮件】

文章目录 &#x1f47d;使用Python实现发送Email电子邮件&#x1f3b6;实现原理&#x1f3c3;Python实现发送Email电子邮件-基础版&#x1f46b;实现源码&#x1f646;源码解析 &#x1f487;Python实现发送Email电子邮件-完善版&#x1f46b;实现源码&#x1f646;源码解析&am…

随机无限采集JK妹妹高清壁纸下载HTML网页源码

源码介绍 美图网站千千万&#xff0c;美图自己说了算&#xff01;本源码由宋佳乐博客 开发&#xff0c;首页图片做了浏览器窗口自适应&#xff0c;最大化占满PC浏览器和移动浏览器的窗口&#xff0c;并且防止出现滚动条。 功能介绍 首页图片设置了4个点击功能区&#xff0c;…

【数据结构入门精讲 | 第十一篇】一文讲清树

在上一篇中我们进行了排序算法的专项练习&#xff0c;现在让我们开始树的知识点讲解。 目录 树二叉搜索树二叉排序树哈夫曼树折半查找判定树kruskal算法、prim算法、最小生成树完全二叉树 树 树是一种非线性的数据结构&#xff0c;也是一种表示一对多关系的数据结构&#xff0…

Flink CDC 1.0至3.0回忆录

Flink CDC 1.0至3.0回忆录 一、引言二、CDC概述三、Flink CDC 1.0&#xff1a;扬帆起航3.1 架构设计3.2 版本痛点 四、Flink CDC 2.0&#xff1a;成长突破4.1 DBlog 无锁算法4.2 FLIP-27 架构实现4.3 整体流程 五、Flink CDC 3.0&#xff1a;应运而生六、Flink CDC 的影响和价值…

Python 数据分析 Matplotlib篇 plot设置线条样式(第2讲)

Python 数据分析 Matplotlib篇 plot设置线条样式(第2讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

算法基础之完全背包问题

完全背包问题 核心思想&#xff1a;集合表示&#xff1a; f[i][j]表示前i种物品 总容量不超过j的最大价值 求f[i][j]时 分为选0、1、2……n个第i种物品 n种情况 每种情况为 f[i][j-kv] (取k个第i种物品) 即f[i][j] max(f[i-1][j] , f[i-1][j-v]w,f[i-1][j-2v]2w….f[i-1][j-k…

【自用】Ubuntu20.4从Vivado到ddr200t运行HelloWorld

【自用】Ubuntu20.4新系统从输入法到ddr200t运行HelloWorld 一、编辑bashrc二、Vivado2022.2安装三、编译蜂鸟E203自测样例1. 环境准备2. 下载e203_hbirdv2工程文件3. 尝试编译自测案例1. 安装RISC-V GNU工具链2. 编译测试样例 4. 用vivado为FPGA生成mcs文件1.准备RTL2.生成bit…

Centos 7.9安装Oracle19c步骤亲测可用有视频

视频介绍了在虚拟机安装centos 7.9并安装数据库软件的全过程 视频链接&#xff1a;https://www.zhihu.com/zvideo/1721267375351996416 下面的文字描述是安装数据库的部分介绍 一.安装环境准备 链接&#xff1a;https://pan.baidu.com/s/1Ogn47UZQ2w7iiHAiVdWDSQ 提取码&am…

贝叶斯球快速检验条件独立

贝叶斯球 定义几个术语&#xff0c;描述贝叶斯球在一个结点上的动作&#xff1a; 通过&#xff08;pass through&#xff09;&#xff1a;从当前结点的父结点方向过来的球&#xff0c;可以访问当前结点的任意子结点&#xff08;父->子&#xff09;。从当前节点的子结点方向…

基于电商场景的高并发RocketMQ实战-NameServer内核原理剖析、Broker 主从架构与集群模式原理分析

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 【11来了】文章导读地址&#xff1a;点击查看文章导读&#xff01; &#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f3…

Prometheus介绍和安装

Prometheus介绍和安装 1. Prometheus介绍 Prometheus&#xff08;普罗米修斯&#xff09;是一个最初在SoundCloud上构建的监控系统。自2012年成为社区开源项目&#xff0c;拥有非常活跃的开发人员和用户社区。为强调开源及独立维护&#xff0c;Prometheus于2016年加入云原生云…

指标体系构建-03-交易型的数据指标体系

参考&#xff1a; 本文参考 1.接地气的陈老师的数据指标系列 2.科普 | 零售行业的数据指标体系及其含义、应用阶段 3.”人货场”模型搞懂没&#xff1f;数据分析大部分场景都能用&#xff01; 4.一分钟读懂广告投放各计费CPM、CPC等&#xff08;公式推导干货&#xff09; 5.AA…

mysql 数据编译安装以及参数说明 安装包下载

目录 MySQL 官网地址官网下载源码包安装步骤修改密码 MySQL 官网地址 https://dev.mysql.com/doc/ 官网下载源码包 安装步骤 # 所需要的依赖及安装mysql的包" [rootmysql_source ~]# yum -y install ncurses ncurses-devel openssl-devel bison libgcrypt gcc gcc-c ma…

前缀和+单调双队列+贪心:LeetCode2945:找到最大非递减数组的长度

本文涉及知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 单调双队列 贪心 题目 给你一个下标从 0 开始的整数数组 nums 。 你可以执行任意次操作。每次操作中&#xff0c;你需要选择一个 子数组 &#xff0c;并将这个子数组用它所…

AcWing 1238. 日志统计(双指针,滑动窗口)

题目&#xff1a; 1238. 日志统计 - AcWing题库 数据范围 输入样例&#xff1a; 7 10 2 0 1 0 10 10 10 10 1 9 1 100 3 100 3输出样例&#xff1a; 1 3 思路&#xff1a;双指针 代码&#xff1a; #include<iostream> #include<cstdio> #include<cmath>…