分布式锁1-分布式锁实现的三种方式

分布式锁概念

为什么使用分布式锁

假设有这样一个场景,双十一抢iphone15ProMax手机场景,可以抢多台。操作数据库接口如下:

	void reduceInventory(Long id,int count) {//1.拿到数量信息Product product = mapper.selectById(id);//2.修改数量信息int newCount = product.getProductCount() - count;product.setProductCount(newCount);int i = mapper.updateById(product);System.out.println("修改成功!->" +i);}

在单个应用情况下可以使用synchronized或者lock锁解决并发问题,因为只有这一个应用可以调用这个接口。那么在微服务应用下呢?多个请求
同时访问这个接口,步骤1是可以同时执行的,在同一时间可能拿到的数量是相同的;假设A服务和B服务各有一个请求访问这个接口,那么A应用要抢
5个,B应用要抢1个,这样就导致A应用要更新数据库的时候数量是95,B应用要更新的数量是99,不管谁先拿到数据库的锁,都会后拿到数据库锁的
覆盖掉前面的数据,导致数据不正确。那么如何解决这个问题呢?答案就是分布式锁。

加分布式锁的本质就是保证步骤1和步骤2这个逻辑,或者说这块代码无论有多少个并发请求必须保证同步执行。而且,无论多少个服务都能通过
一个公用的组件来控制代码同步执行,比如MySQL、Redis、zookeeper。任何一个服务都能访问到它,而不是通过synchronized或者lock锁,
因为每个服务的synchronized或者lock锁都是只有当前服务能访问,不能实现服务之间的排他性。

分布式锁有三种实现方式

1. MySQL实现分布式锁

原理:

在数据库层面加锁处理,在一个线程修改数据查询数据的时候进行for update处理。这样其他线程在查询数据的时候就会阻塞,必须等当前
线程处理完才能执行for update查询语句。

步骤:

  1. 开启事务
  2. 执行select * from table where id = ? for update语句
  3. 提交事务

问题:

一旦有某个线程处理逻辑时开启了事务,但是抛出异常了,那么就会导致事务无法提交,其他线程永远拿不到数据库锁,导致死锁问题。

2.Redis+RUA脚本实现分布式锁

原理:

  1. redis中有nx 和 ex操作,其中nx表示当前key不存在时才执行成功,返回0表示失败,返回1表示成功;ex表示过期时间。
  2. 当加锁的时候执行nx操作,如果当前有线程持有锁则设置失败返回0,否则成功返回1.
  3. 释放锁的时候执行del操作。
  4. ex可以防止死锁问题,如果有个线程执行setnx操作了由于异常不执行del释放锁操作,那么其他线程永远无法拿到锁。

要解决的问题:

  1. 如何避免死锁问题:

设置ex过期时间。

  1. 如何保证锁不会被其他线程释放:

通过redis存储的value来控制,将value作为线程的唯一标识,只有当前线程的解锁标识和设置的value相同时才能删除当前key。

  1. 如何保证在释放锁时如何保证查询value值、必对value值、删除key操作的原子性

使用RUA脚本:f(redis.call(‘get’, KEYS[1]) == ARGV[1]) then return redis.call(‘del’, KEYS[1]) end return 0;传入
客户端的唯一标识和redis拿到的value对比,如果相同则删除key,否则不删除。

  1. 如何评估redis中key的过期时间

使用守护线程:

  1. 守护线程的特点是,当主线程销毁时,守护线程随机销毁
  2. 在加锁的时候,开启一个守护线程。
  3. 守护线程的操作是,在key将要失效的时候进行续期操作。
  4. 这样做的好处是在解决了死锁问题的同时,如果业务逻辑执行比较慢的话也不会导致锁自动失效的问题
  1. Redis宕机问题

假设一个客户端在加锁的时候,master实例突然宕机,没有向slave同步数据,其中一个slave升级为master,另一个实例重新获取锁,这种情况下锁的安全性被打破。

redis作者提出RedLock概念:

  1. 客户端记录当前时间戳T1,并设置锁的TTL时间
  2. 在服务器创建5个redis实例,非集群,不存在数据同步问题。
  3. 依次从5个redis实例去获取锁,相同的key-value,获取锁时要设置网络连接和响应的超时时间,该时间要小于锁TTL时间,避免客户端死等。
  4. 客户端记录最后一个获取锁成功的时间戳(因为有可能在五个Redis中有宕机发生就获取锁失败了)T2,和获取锁成功的个数n,其中n要大于等于3(半数以上节点获取重构)且T2-T1要小于TTL才算获取成功。
  5. 锁的时间为TTL - 取锁的时间;
  6. 如果加锁失败,客户端向所有Redis实例发送解锁请求。

其中有三个要解决的问题(NPC):

  1. Network Delay: 网络延迟问题
  2. Process Pause: 进程暂停问题
  3. Clock Drift: 时钟漂移问题(客户端服务器和Redis服务器时间不一致)

3. Zookeeper实现分布式锁

Zookeeper分布式锁时基于临时顺序节点实现的.
要解决的问题:

  1. 如何实现互斥性:Zookeeper中的节点类似文件系统的目录结构,当对其中一个节点加锁,其他线程就不能再创建了。
  2. 如何加锁解锁:当客户端连接Zookeeper后创建节点,断开连接删除节点
  3. 如何解决高可用问题:使用顺序节点+watch机制,当客户端加锁时会在目录下创建一个字子点并记录创建顺序节点,然后判断创建的顺序节点是否为第一个节点,如果是,加锁成功,如果不是watch上一个节点以此类推,
    如果加锁成功的客户端断开连接,那么监听该顺序节点的客户端就可以去获取锁,这样就减轻了高并发下的zookeeper压力,实现高可用。

实现原理:

  1. 创建临时顺序节点:每个客户端访问zk会创建临时节点,(例如/locks)下创建一个临时顺序节点。
  2. 获取所有子节点并排序:客户端通过getChildren获取/locks下的所有子节点,并对这些子节点按照它们的序号进行排序。
  3. 判断锁的拥有者:客户端检查它创建的节点是不是排序后的第一个节点,如果是,则获取到锁;如果不是,则监视排序后的前一个节点。
  4. 等待或者阻塞:如果这个节点不是第一个,客户端就会注册对前一个节点的监视器,并进入等待状态,直到前一个节点被删除释放锁。
  5. 释放锁:当客户端完成操作,释放锁时,会删除它创建的临时节点,然后通知监视器上的等待节点。

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

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

相关文章

2024.05.24|生信早报【AI测试版】

植物再生领域重大突破 山农大团队发现植物“再生指挥官”REF1:中国科学院院士种康高度评价,认为这一发现对细胞分化与再生领域的基础科学研究和生物技术应用具有重大意义。 生物医药专业园区建设\n- 卫光生命科学园聚焦合成生物学、脑科学&#xff1a…

学习通项目总结:

1.字体大小和按钮的大小不统一导致很难看 2.只是做了基础的功能点没有自己的想法(没有创新) 3.使用了很多的线程不安全的集合,对于线程安全的认识还需要加强 4.对数据库的认识太少了,就只使用了最简单的增删改查,相…

详细介绍一下Votenet的工作原理及流程

Votenet是一种基于深度学习的三维目标检测和实例分割方法,其工作原理主要包括两个步骤:候选框生成和目标分类与分割。 1.候选框生成: 首先,Votenet通过将三维点云数据转化为连续的坐标网格,将三维目标检测问题转化为二…

【openlayers系统学习】1.6下载要素,将要素数据序列化为 GeoJSON并下载

六、下载要素 下载要素 上传数据并编辑后&#xff0c;我们想让用户下载结果。为此&#xff0c;我们将要素数据序列化为 GeoJSON&#xff0c;并创建一个带有 download​ 属性的 <a>​ 元素&#xff0c;该属性会触发浏览器的文件保存对话框。同时&#xff0c;我们将在地图…

Linux--07---查看CPU、内存、磁盘

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 常用命令1.查看CPU使用率1.1 top 命令第一行是任务队列信息&#xff1a; top第二行为进程的信息 Tasks第三行为CPU的信息Mem:Swap 1.2 vmstat命令参数详解每个参数的…

Axios配置中的请求响应拦截器

在 Axios 中&#xff0c;你可以配置请求拦截器&#xff08;Request Interceptors&#xff09;和响应拦截器&#xff08;Response Interceptors&#xff09;来处理在请求发送到服务器之前和服务器响应返回客户端之后的逻辑。 请求拦截器 请求拦截器可以在请求被发送到服务器之…

在 Visual Studio Code(VS Code)中调试 .NET Core 程序详细步骤

在 Visual Studio Code 中调试 .NET Core 程序 在 Visual Studio Code (VS Code) 中调试 .NET Core 程序需要配置和安装一些必要的扩展和调试配置。以下是详细步骤&#xff1a; 1. 安装必要的扩展 首先&#xff0c;确保已安装 Visual Studio Code&#xff0c;并添加必要的扩…

CentOS部署NFS

NFS服务端 部署NFS服务端 sudo yum install -y nfs-utils挂载目录 给 NFS 指定一个存储位置&#xff0c;也就是网络共享目录。一般来说&#xff0c;应该建立一个专门的 /data 目录&#xff0c;方便起见使用临时目录 /tmp/nfs&#xff1a; mkdir -p /tmp/nfs #修改权限 chmo…

响应式处理-一篇打尽

纯pc端响应式 pc端平常用到的响应式布局 大致就如下三种&#xff0c;当然也会有其他方法&#xff0c;欢迎评论区补充 将div height、width设置成100% flex布局 flex布局主要是将flex-wrap: wrap&#xff0c; 最后&#xff0c;你可以通过给子元素设置 flex 属性来控制它们的…

Leecode热题100---45:跳跃游戏②

题目&#xff1a; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。 返回到达 nums[n - 1] 的最小跳跃次数。 思路&#xff1a; 如果某一个作为 起跳点 的格子可以跳跃的距离是 3&#xff0c;那么表示后面…

最新Adaptive特征融合策略,涨点又高效,想发表论文可以参考

自适应特征融合是一种非常高效的数据处理方法&#xff0c;它比传统的特征更能适应不同的数据和任务需求&#xff0c;也因此拥有广泛的应用前景&#xff0c;是深度学习领域的研究热点。 这种方法通过动态选择和整合来自不同层次或尺度的特征信息&#xff0c;不仅显著提升了模型…

4月空调行业线上市场销售数据分析

随着生活品质的提升&#xff0c;消费者对家用空调的诉求不仅仅满足于基本制冷制热功能&#xff0c;而是在环保节能、功能升维、舒适送风、智能科技、焕新设计等多维度提出需求。这种多样化的需求推动了空调产品的创新和升级&#xff0c;这不仅提高了空调的市场竞争力&#xff0…

如何改变echo在Linux下的输出颜色

文章目录 问题回答常规输出字体加粗斜体字带下划线闪烁效果 参考 问题 我正在尝试使用 echo 命令在终端中打印文本。 我想把文本打印成红色。我该怎么做&#xff1f; 回答 你可以使用 ANSI escape codes 定义控制输出颜色的变量。 ANSI escape codes是一种用于在文本中设置…

STM32 MAP文件结合固件文件分析

文章目录 加载域的结束地址并不是固件的结束地址&#xff1f;ROM中执行域的描述RAM中执行域的描述问题分析 中断向量表在固件中的存储位置代码段在固件中的位置只读数据Regin$$Table RW Data段其中的内部机理 总结 MAP 文件分析可以参考之前的文章 程序代码在未运行时在存储器…

Git学习和使用指南简单篇

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

element-ui手机区号+手机号

需求场景 项目开发中对方要求手机号带上全球区号 需求分析 项目使用的是若依前端框架&#xff0c;element-ui的框架。尝试使用已经网上的组件vue-country-intl等发现不怎么适配element-ui的样式等。这还不是关键的&#xff0c;关键的是弹窗中使用这些组件发现区号的下拉展示框…

C++,LeetCode算法题的字符串输入处理

文章目录 24. 算法24.1. 二叉树输入处理&#xff0c;包括建树、打印树、释放树。24.2. 单链表输入处理&#xff0c;包括建链&#xff08;头插、尾插&#xff09;、打印链、释放链。24.3. 一维矩阵输入处理。24.4. 二维矩阵输入处理。24.5. 调用函数输入处理。 24. 算法 24.1. …

一文了解基于ITIL的运维管理体系框架

本文来自腾讯蓝鲸智云社区用户&#xff1a;CanWay ITIL&#xff08;Information Technology Infrastructure Library&#xff09;是全球最广泛使用的 IT 服务管理方法&#xff0c;旨在帮助组织充分利用其技术基础设施和云服务来实现增长和转型。优化IT运维&#xff0c;作为企业…

Docker 容器间通讯

1、虚拟ip/访问 同一网络 安装docker时&#xff0c;docker会默认创建一个内部的桥接网络docker0&#xff0c;每创建一个容器分配一个虚拟网卡&#xff0c;容器之间(包括宿主机)可以根据分配的ip互相访问(ps:其他主机(包括其他主机的容器)无法ping通docker容器ip无法访问&#…

安卓手机APP开发__蓝牙功能概述

安卓手机&#xff21;&#xff30;&#xff30;开发&#xff3f;&#xff3f;蓝牙功能概述 目录 概述 基本内容 关键的类和接口 概述 安卓平台支持了蓝牙网络栈&#xff0c;它允许一个设备和其它的蓝牙设备进行无线的交换数据。 &#xff21;&#xff30;&#xff30;的框架…