iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > html >如何理解分布式锁的场景
  • 851
分享到

如何理解分布式锁的场景

2024-04-02 19:04:59 851人浏览 八月长安
摘要

本篇内容主要讲解“如何理解分布式锁的场景”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解分布式锁的场景”吧!秒杀场景案例对于商品秒杀的场景,我们需要防止库

本篇内容主要讲解“如何理解分布式的场景”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解分布式锁的场景”吧!

秒杀场景案例

对于商品秒杀的场景,我们需要防止库存超卖或者重复扣款等并发问题,我们通常需要使用分布式锁,来解决共享资源竞争导致数据不一致的问题。

以手机秒杀的场景为例子,在抢购的过程中通常我们有三个步骤:

扣掉对应商品的库存;2. 创建商品的订单;3. 用户支付。

对于这样的场景我们就可以采用分布式锁的来解决,比如我们在用户进入秒杀 “下单“  链接的过程中,我们可以对商品库存进行加锁,然后完成扣库存和其他操作,操作完成后。释放锁,让下一个用户继续进入保证库存的安全性;也可以减少因为秒杀失败,导致 DB  回滚的次数。整个流程如下图所示:

 如何理解分布式锁的场景

注:对于锁的粒度要根据具体的场景和需求来权衡。

三种分布式锁

对于 ZooKeeper 的分布式锁实现,主要是利用 Zookeeper 的两个特征来实现:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. Zookeeper 的一个节点不能被重复创建

  3. Zookeeper 的 Watcher 监听机制

非公平锁

对于非公平锁,我们在加锁的过程如下图所示。

如何理解分布式锁的场景

优点和缺点

其实上面的实现有优点也有缺点:

优点:

实现比较简单,有通知机制,能提供较快的响应,有点类似 ReentrantLock 的思想,对于节点删除失败的场景由 Session  超时保证节点能够删除掉。

缺点:

重量级,同时在大量锁的情况下会有 “惊群” 的问题。

“惊群” 就是在一个节点删除的时候,大量对这个节点的删除动作有订阅 Watcher  的线程会进行回调,这对Zk集群是十分不利的。所以需要避免这种现象的发生。

解决“惊群”:

为了解决“惊群“问题,我们需要放弃订阅一个节点的策略,那么怎么做呢?

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. 我们将锁抽象成目录,多个线程在此目录下创建瞬时的顺序节点,因为 Zookeeper 会为我们保证节点的顺序性,所以可以利用节点的顺序进行锁的判断。

  3. 首先创建顺序节点,然后获取当前目录下最小的节点,判断最小节点是不是当前节点,如果是那么获取锁成功,如果不是那么获取锁失败。

  4. 获取锁失败的节点获取当前节点上一个顺序节点,对此节点注册监听,当节点删除的时候通知当前节点。

  5. 当unlock的时候删除节点之后会通知下一个节点。

公平锁

基于非公平锁的缺点,我们可以通过一下的方案来规避。

如何理解分布式锁的场景

优点和缺点

优点: 如上借助于临时顺序节点,可以避免同时多个节点的并发竞争锁,缓解了服务端压力。

缺点: 对于读写场景来说,无法解决一致性的问题,如果读的时候也去获取锁的话,这样会导致性能下降,对于这样的问题,我们可以通过读写锁来实现如类似 jdk  中的 ReadWriteLock

读写锁实现

对于读写锁的特点:读写锁在如果多个线程都是在读的时候,是可以并发读的,就是一个无锁的状态,如果有写锁正在操作的时候,那么读锁需要等待写锁。在加写锁的时候,由于前面的读锁都是并发,所以需要监听最后一个读锁完成后执行写锁。步骤如下:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. read 请求, 如果前面是读锁,可以直接读取,不需要监听。如果前面是一个或者多个写锁那么只需要监听最后一个写锁。

  3. write 请求,只需要对前面的节点监听。Watcher 机制和互斥锁一样。

如何理解分布式锁的场景

分布式锁实战

本文源码中使用环境:JDK 1.8 、Zookeeper 3.6.x

Curator 组件实现

POM 依赖

<dependency>   <groupId>org.apache.curator</groupId>   <artifactId>curator-framework</artifactId>   <version>2.13.0</version> </dependency> <dependency>   <groupId>org.apache.curator</groupId>   <artifactId>curator-recipes</artifactId>   <version>2.13.0</version> </dependency>

互斥锁运用

由于 Zookeeper 非公平锁的 “惊群” 效应,非公平锁在 Zookeeper 中其实并不是最好的选择。下面是一个模拟秒杀的例子来使用  Zookeeper 分布式锁。

public class MutexTest {     static ExecutorService executor = Executors.newFixedThreadPool(8);     static AtomicInteger stock = new AtomicInteger(3);     public static void main(String[] args) throws InterruptedException {         CuratorFramework client = getZkClient();         String key = "/lock/lockId_111/111";         final InterProceSSMutex mutex = new InterProcessMutex(client, key);         for (int i = 0; i < 99; i++) {             executor.submit(() -> {                 if (stock.get() < 0) {                     System.err.println("库存不足, 直接返回");                     return;                 }                 try {                     boolean acquire = mutex.acquire(200, TimeUnit.MILLISECONDS);                     if (acquire) {                         int s = stock.decrementAndGet();                         if (s < 0) {                             System.err.println("进入秒杀,库存不足");                         } else {                             System.out.println("购买成功, 剩余库存: " + s);                         }                     }                 } catch (Exception e) {                     e.printStackTrace();                 } finally {                     try {                         if (mutex.isAcquiredInThisProcess())                             mutex.release();                     } catch (Exception e) {                         e.printStackTrace();                     }                 }             });         }         while (true) {             if (executor.isTerminated()) {                 executor.shutdown();                 System.out.println("秒杀完毕剩余库存为:" + stock.get());             }             TimeUnit.MILLISECONDS.sleep(100);         }     }     private static CuratorFramework getZkClient() {         String zkServerAddress = "127.0.0.1:2181";         ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);         CuratorFramework zkClient = CuratorFrameworkFactory.builder()                 .connectString(zkServerAddress)                 .sessionTimeoutMs(5000)                 .connectionTimeoutMs(5000)                 .retryPolicy(retryPolicy)                 .build();         zkClient.start();         return zkClient;     } }

读写锁运用

读写锁可以用来保证缓存双写的强一致性的,因为读写锁在多线程读的时候是无锁的, 只有在前面有写锁的时候才会等待写锁完成后访问数据。

public class ReadWriteLockTest {     static ExecutorService executor = Executors.newFixedThreadPool(8);     static AtomicInteger stock = new AtomicInteger(3);     static InterProcessMutex readLock;     static InterProcessMutex writeLock;     public static void main(String[] args) throws InterruptedException {         CuratorFramework client = getZkClient();         String key = "/lock/lockId_111/1111";         InterProcessReadWriteLock readWriteLock = new InterProcessReadWriteLock(client, key);         readLock = readWriteLock.readLock();         writeLock = readWriteLock.writeLock();         for (int i = 0; i < 16; i++) {             executor.submit(() -> {                 try {                     boolean read = readLock.acquire(2000, TimeUnit.MILLISECONDS);                     if (read) {                         int num = stock.get();                         System.out.println("读取库存,当前库存为: " + num);                         if (num < 0) {                             System.err.println("库存不足, 直接返回");                             return;                         }                     }                 } catch (Exception e) {                     e.printStackTrace();                 }finally {                     if (readLock.isAcquiredInThisProcess()) {                         try {                             readLock.release();                         } catch (Exception e) {                             e.printStackTrace();                         }                     }                 }                 try {                     boolean acquire = writeLock.acquire(2000, TimeUnit.MILLISECONDS);                     if (acquire) {                         int s = stock.get();                         if (s <= 0) {                             System.err.println("进入秒杀,库存不足");                         } else {                             s = stock.decrementAndGet();                             System.out.println("购买成功, 剩余库存: " + s);                         }                     }                 } catch (Exception e) {                     e.printStackTrace();                 } finally {                     try {                         if (writeLock.isAcquiredInThisProcess())                             writeLock.release();                     } catch (Exception e) {                         e.printStackTrace();                     }                 }             });         }         while (true) {             if (executor.isTerminated()) {                 executor.shutdown();                 System.out.println("秒杀完毕剩余库存为:" + stock.get());             }             TimeUnit.MILLISECONDS.sleep(100);         }     }     private static CuratorFramework getZkClient() {         String zkServerAddress = "127.0.0.1:2181";         ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);         CuratorFramework zkClient = CuratorFrameworkFactory.builder()                 .connectString(zkServerAddress)                 .sessionTimeoutMs(5000)                 .connectionTimeoutMs(5000)                 .retryPolicy(retryPolicy)                 .build();         zkClient.start();         return zkClient;     } }

打印结果如下,一开始会有 8 个输出结果为 读取库存,当前库存为: 3 然后在写锁中回去顺序的扣减少库存。

读取库存,当前库存为: 3 读取库存,当前库存为: 3 读取库存,当前库存为: 3 读取库存,当前库存为: 3 读取库存,当前库存为: 3 读取库存,当前库存为: 3 读取库存,当前库存为: 3 读取库存,当前库存为: 3 购买成功, 剩余库存: 2 购买成功, 剩余库存: 1 购买成功, 剩余库存: 0 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 读取库存,当前库存为: 0 读取库存,当前库存为: 0 读取库存,当前库存为: 0 读取库存,当前库存为: 0 读取库存,当前库存为: 0 读取库存,当前库存为: 0 读取库存,当前库存为: 0 读取库存,当前库存为: 0 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足 进入秒杀,库存不足

分布式锁的选择

咱们最常用的就是 Redis 的分布式锁和 Zookeeper 的分布式锁,在性能方面 Redis 的每秒钟 TPS  可以上轻松上万。在大规模的高并发场景我推荐使用 Redis 分布式锁来作为推荐的技术方案。如果对并发要求不是特别高的场景可以使用 Zookeeper  分布式来处理。

到此,相信大家对“如何理解分布式锁的场景”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 如何理解分布式锁的场景

本文链接: https://www.lsjlt.com/news/83154.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何理解分布式锁的场景
    本篇内容主要讲解“如何理解分布式锁的场景”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解分布式锁的场景”吧!秒杀场景案例对于商品秒杀的场景,我们需要防止库...
    99+
    2024-04-02
  • 分布式面试分布式锁实现及应用场景
    目录引言1、面试官:你有遇到需要使用分布式锁的场景吗?事件A:事件B: 2、面试官:Redis分布式锁实现方法1、基于Redis的分布式锁3、面试官: 那解锁操作...
    99+
    2024-04-02
  • Redis中如何实现支持几乎所有加锁场景的分布式锁
    小编给大家分享一下Redis中如何实现支持几乎所有加锁场景的分布式锁,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!实战部分1、引...
    99+
    2024-04-02
  • Spring Boot整合Zookeeper实现分布式锁的场景分析
    目录一、Java当中关于锁的概念1.1.什么是锁1.2.锁的使用场景1.3.什么是分布式锁1.4.分布式锁的使用场景二、zk实现分布式锁2.1.zk中锁的种类:2.2.zk如何上读锁...
    99+
    2024-04-02
  • 如何理解分布式锁的封装
    本篇内容主要讲解“如何理解分布式锁的封装”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解分布式锁的封装”吧!分布式锁通常有很多选择,基于 Redis 的,...
    99+
    2024-04-02
  • 如何理解Redisson分布式锁的源码
    本篇内容介绍了“如何理解Redisson分布式锁的源码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Red...
    99+
    2024-04-02
  • 如何理解分布式系统下基于Redis的分布式锁
    这篇文章主要介绍“如何理解分布式系统下基于Redis的分布式锁”,在日常操作中,相信很多人在如何理解分布式系统下基于Redis的分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大...
    99+
    2024-04-02
  • 如何深入理解Redis分布式锁
    这篇文章主要介绍“如何深入理解Redis分布式锁”,在日常操作中,相信很多人在如何深入理解Redis分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何深入理解Redi...
    99+
    2024-04-02
  • 利用consul在spring boot中实现分布式锁场景分析
    因为在项目实际过程中所采用的是微服务架构,考虑到承载量基本每个相同业务的服务都是多节点部署,所以针对某些资源的访问就不得不用到用到分布式锁了。 这里列举一个最简单的场景,假如有一个智...
    99+
    2024-04-02
  • 分布式数据库如何玩转HTAP场景
    这篇文章给大家介绍分布式数据库如何玩转HTAP场景,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。传统数据库架构面临的痛点1. 集群分散不利于整合,数据结构同步工作量大第一招:...
    99+
    2024-04-02
  • 基于Zookeeper的分布式锁该如何理解
    今天就跟大家聊聊有关基于Zookeeper的分布式锁该如何理解,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。实现分布式锁目前有三种流行方案,分别为基于数据库、Redis、Zookee...
    99+
    2023-06-04
  • 如何理解C#.NET分布式锁服务
    本篇文章给大家分享的是有关如何理解C#.NET分布式锁服务,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。背  景分布式锁服务在大家的项目中或许用的不多,因为大家都把排...
    99+
    2023-06-17
  • Redis分布式锁怎么实现及应用场景是什么
    本篇内容介绍了“Redis分布式锁怎么实现及应用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!引言锁是开发过程中十分常见的工具,你...
    99+
    2023-06-29
  • 深入理解:分布式之抉择分布式锁
    前言:目前网上大部分的基于zookpeer,和redis的分布式锁的文章都不够全面。要么就是特意避开集群的情况,要么就是考虑不全,读者看着还是一脸迷茫。坦白说,这种老题材,很难写出新创意,博主内心战战兢兢,如履薄冰,文中有什么不严谨之处,欢...
    99+
    2023-06-05
  • DBA_2PC_PENDING中的分布式锁-解锁
     运行shell脚本后,会生成 roll.sql文件。...
    99+
    2023-06-06
  • 怎么理解Redis分布式锁
    这篇文章主要讲解了“怎么理解Redis分布式锁”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么理解Redis分布式锁”吧!你真的需要分布式锁吗用到分布式锁...
    99+
    2024-04-02
  • 分布式锁的原理及Redis怎么实现分布式锁
    这篇文章主要介绍“分布式锁的原理及Redis怎么实现分布式锁”,在日常操作中,相信很多人在分布式锁的原理及Redis怎么实现分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2023-02-02
    redis
  • 分析MySQL锁的适用场景
    MySQL 锁的应用场景分析在开发应用程序时,常常需要对数据库进行读取和写入操作。然而,当多个用户同时对数据库进行操作时,就会出现并发访问的问题。为了保证数据的一致性和完整性,MySQL 提供了锁机制来控制对数据库的并发操作。本文将分析 M...
    99+
    2023-12-21
    MySQL 分析
  • 如何解决redis分布式锁的问题
    这篇文章主要为大家展示了“如何解决redis分布式锁的问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决redis分布式锁的问题”这篇文章吧。分布式锁在...
    99+
    2024-04-02
  • 如何理解互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
    本篇内容主要讲解“如何理解互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解互斥锁、自旋锁、读写锁、悲观锁、...
    99+
    2024-04-02
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作