分布式锁的产生以及使用

这篇具有很好参考价值的文章主要介绍了分布式锁的产生以及使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

日常开发中,针对一些需要锁定资源的操作,例如商城的订单超卖问题、订单重复提交问题等。

都是为了解决在资源有限的情况限制客户端的访问,对应的是限流。

单节点锁问题

目前针对这种锁资源的情况采取的往往是互斥锁,例如 java 里的 synchronized 锁以及 ReentrantLock,其中 synchronized 的加锁操作在 jvm 层面实现,会有一个锁升级(偏向锁、轻量级锁、重量级锁)的问题,ReentrantLock 需要手写代码实现,底层是 AQS。但是 java 层面的锁有一个问题,就是只能在一个进程中使用,如果跨进程就无能为力了,例如应用的集群部署,客户端请求过来后通过负载均衡策略转发到对应的实例上。

分布式锁

鉴于以上单节点锁的问题,就需要通过一个中间介质来实现针对需要访问的资源进行一个资源加锁和释放操作的问题,目前有如下方式

数据库

将需要访问的数据可以放到数据库的表中,一般存储的是确保唯一性的业务主键,在访问资源时可将业务主键插入到表中,每次访问资源前先查询数据库判断数据是否存在,如果存在表明资源在被访问,否则就正常处理。

zookeeper

https://zookeeper.apache.org/doc/r3.9.1/recipes.html#sc_recipes_Locks

通过临时顺序节点(EPHEMERAL_SEQUENTIAL )来实现,这种类型的节点的好处是会话级别,如果会话结束节点会删除掉。

官方提供的是 curator 组件库,在项目的 pom.xml 中引入如下依赖

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

https://curator.apache.org/docs/getting-started#distributed-lock

内部提供了一个分布式锁接口 InterProcessLock,通过对应的实现类 InterProcessMutex 进行加锁和释放锁操作。

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.concurrent.TimeUnit;

public class DistributedLock {

    public static void main(String[] args) throws InterruptedException {

        RetryPolicy retryPolicy = new ExponentialBackoffRetry(10000, 3);

        for (int i = 1; i <= 1; i++) {
            new Thread(() -> {
                try (CuratorFramework client = CuratorFrameworkFactory.newClient(Constants.CONNECTION_URL, retryPolicy);){
                    client.start();
                    InterProcessLock lock1 = new InterProcessMutex(client, "/dlock");
                    try {
                        lock1.acquire(5, TimeUnit.SECONDS);
                        System.out.println("lock1获取");
                        TimeUnit.SECONDS.sleep(5);
                        lock1.release();
                        System.out.println("lock1释放");
                    } catch (Throwable e) {
                        e.printStackTrace();
                    }
                }
            }).start();

        }
    }
}

锁的组成如下

/父节点/_c_+UUID+-lock-+10位数(从0开始自增,不足10位用0补足)

如果在执行过程中进行了多次加锁,具体如下

/dlock/_c_0d4db7a9-5c21-4a57-9904-e42cd970d774-lock-0000000000
/dlock/_c_d3588ec1-981a-41aa-a420-89f7949f94d6-lock-0000000001

这样就会有一个问题,前面的前缀 PROTECTED_PREFIX 和 UUID 会对节点产生干扰。

分布式锁的产生以及使用,分布式,redis,分布式,zookeeper,数据库,redis

https://github.com/apache/curator/blob/apache-curator-5.5.0/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedUtils.java#L65

可以将 ProtectedUtils 整个类复制一遍在项目中,将 getProtectedPrefix() 的内容进行修改,如下

修改前

public static String getProtectedPrefix(final String protectedId)
{
	return PROTECTED_PREFIX + protectedId + PROTECTED_SEPARATOR;
}

修改后

public static String getProtectedPrefix(final String protectedId)
{
	return protectedId;
}

这样生成的节点格式为

/父节点/lock-+10位数(从0开始自增,不足10位用0补足)

最终生成的节点如下

/dlock/lock-0000000000

其中对应的节点值为当前请求的 ip

[zk: localhost:2181(CONNECTED) 2] get /dlock/lock-0000000000
192.168.106.109

如果有多个客户端针对同一个节点进行加锁请求,会按序创建多个节点,但是持有锁的只是最小的节点,后面的节点会向获取锁的节点注册 Watcher 来监听持有锁的节点是否存在。

redis

作为一个在内存层次的数据库,用处多多,其中可以用于分布式锁。

redis 提供了 lua 脚本支持,lua 脚本可以做到将操作进行打包,确保整个操作的原子性。其中分布式锁就用到了 lua 脚本。

redis 官方介绍

https://redis.io/docs/manual/patterns/distributed-locks/

该锁被命名为 Redlock,在不同的语言中有对应的实现,在 java 中对应的是 redisson。

在项目的 pom.xml 中引入如下依赖

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.26.0</version>
</dependency>  

github 项目链接

https://github.com/redisson/redisson

与 spring boot 整合

https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter#spring-boot-starter

区别

分布式锁建立在共享介质上,所以上面的三种方式都需要借助于其他组件来实现。

数据库层面不适合做高并发处理。

redis 依赖于全局时间,需要考虑到加锁时间的问题。

zookeeper 建立在创建节点的基础上,属于重操作,相对于 redis 内存操作慢一些。

由于 zookeeper 使用了 zab 协议,针对写请求会转发到领导者,如果领导者节点宕机,会从跟随者节点中选举出数据最完整的节点晋升为领导者,不会出现类似 redis 异步同步数据丢失的问题。

对于一些并发请求大的应用,使用 zookeeper 可能出现锁获取失败的情况,使用 redis 集群不会因为,因为 redis 的单线程高并发处理一般情况下难以达到,一般瓶颈在网卡带宽上。

之前自己写的文章

https://blog.csdn.net/zlpzlpzyd/article/details/132716450

参考链接

https://www.jianshu.com/p/31335efec309

https://www.cnblogs.com/xuwc/p/14019932.html

https://juejin.cn/post/6844903729406148622

https://www.cnblogs.com/crazymakercircle/p/14504520.html

https://blog.csdn.net/qq_26709459/article/details/112770526

https://zhuanlan.zhihu.com/p/639756647

https://zhuanlan.zhihu.com/p/383512946

https://www.cnblogs.com/zwj-199306231519/articles/17411947.html

https://baijiahao.baidu.com/s?id=1784900642230670850文章来源地址https://www.toymoban.com/news/detail-810790.html

到了这里,关于分布式锁的产生以及使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ZooKeeper分布式锁的实现与应用

    ZooKeeper是一种分布式应用程序协调服务,它可以管理大规模的集群,并提供可靠的、有序的、高效的数据通信。其中,ZooKeeper提供的分布式锁是一种常见的分布式锁实现,本文将对其进行详细介绍。 在分布式系统中,多个进程或节点可能需要同时访问共享资源。为了确保数据

    2024年02月02日
    浏览(39)
  • Zookeeper分布式锁的概念及原理

    分布式锁的概念图如下:一种演变过程。 在我们进行单机应用程序开发时,往往会涉及到并发同步的问题,一般都会采用synchronized或者Lock锁的方式来解决多线程间的代码同步问题,这些多线程都是运行在同一个JVM之下,是没有任何问题的。 场景:当有一个请求数据的线程进

    2024年02月12日
    浏览(41)
  • 【Redis】Redis分布式锁的10个坑

    日常开发中,经常会碰到秒杀抢购等业务。为了避免并发请求造成的库存超卖等问题,我们一般会用到Redis分布式锁。但是使用Redis分布式锁,很容易踩坑哦~ 本文将给大家分析阐述,Redis分布式锁的10个坑~ 一说到实现Redis的分布式锁,很多小伙伴马上就会想到setnx+ expire命令。

    2024年02月05日
    浏览(39)
  • 分布式锁的实现(redis)

    1、单机锁 考虑在并发场景并且存在竞态的状况下,我们就要实现同步机制了,最简单的同步机制就是加锁。 加锁可以帮我们锁住资源,如内存中的变量,或者锁住临界区(线程中的一段代码),使得同一个时刻只有一个线程能访问某一个区域。 如果是单实例(单进程部署),那

    2024年02月12日
    浏览(49)
  • redis分布式锁的9种实现方式

    1.为什么要用分布式锁 如果是单机情况下(单JVM),线程之间共享内存,只要使用线程锁就可以解决并发问题。但如果是分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。分布式锁其实就是,控制

    2024年02月15日
    浏览(49)
  • Redis——》Redis的部署方式对分布式锁的影响

    推荐链接:     总结——》【Java】     总结——》【Mysql】     总结——》【Redis】     总结——》【Kafka】     总结——》【Spring】     总结——》【SpringBoot】     总结——》【MyBatis、MyBatis-Plus】     总结——》【Linux】     总结——》【MongoDB】    

    2024年02月10日
    浏览(49)
  • 分别使用Redis、MySQL、ZooKeeper构建分布式锁

    本文使用Java构建三种中间件的分布式锁,下面介绍下三种分布式锁的优缺点, 使用MySQL构建分布式锁 ,因为数据库数据存储在磁盘中,所以IO速率相对较慢,因此构建出来的分布式锁不适合用在高并发场景,对于一些对并发要求不高的系统中可以使用,进一步提高系统的安全

    2024年02月06日
    浏览(45)
  • 深入理解PHP+Redis实现分布式锁的相关问题

    PHP使用分布式锁,受语言本身的限制,有一些局限性。 通俗理解单机锁问题:自家的锁锁自家的门,只能保证自家的事,管不了别人家不锁门引发的问题,于是有了分布式锁。 分布式锁概念:是针对多个节点的锁。避免出现数据不一致或者并发冲突的问题,让每个节点确保

    2024年03月23日
    浏览(68)
  • 【征服redis15】分布式锁的功能与整体设计方案

    目录  1. 分布式锁的概念 2.基于数据库做分布式锁 2.1 基于表主键唯一做分布式锁 2.2 基于表字段版本号做分布式锁 2.3 基于数据库排他锁做分布式锁 3.使用Redis做分布式锁 3.1 redis实现分布式锁的基本原理 3.2 问题一:增加超时机制,防止长期持有的情况 3.3 问题2:重入的问题

    2024年01月22日
    浏览(38)
  • 高并发缓存问题分析以及分布式锁的实现

    在高并发的环境下,比如淘宝,京东不定时的促销活动,大量的用户访问会导致数据库的性能下降,进而有可能数据库宕机从而不能产生正常的服务,一般一个系统最大的性能瓶颈,就是数据库的io操作,如果发生大量的io那么他的问题也会随之而来。从数据库入手也是调优性价比最高

    2024年01月19日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包