专业的JAVA编程教程与资源

网站首页 > java教程 正文

分布式锁的实现原理与应用场景详解

temp10 2024-11-22 20:54:02 java教程 12 ℃ 0 评论

在很多场景中,我们为了保证数据的一致性,需要很多的技术方案来支持,比如:之前谈过的分布式事务、本篇继续谈谈分布式锁的实现与应用@mikechen


分布式锁的实现原理与应用场景详解

01 什么是分布式锁

分布式锁是一种用于在分布式系统中实现协作和同步的机制。

在分布式系统中,由于存在多个节点和进程,为了确保数据的一致性和正确性,需要对共享资源进行协调和同步。

常见的分布式锁实现包括:基于ZooKeeper、Redis等的实现。


02 为什么需要分布式锁

首先在传统单机部署的情况下,在Java多线程并发竞争资源场景,可以使用ReentrantLcok 、Synchronized进行互斥控制,用于解决单机并发共享资源问题。

如下图所示:

当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段,线程锁只在同一JVM中有效果。

但是在分布式系统后,由于分布式系统是分布在不同机器上,这将使原单机并发控制锁策略失效。

为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁的来源。


分布式锁的应用场景

在传统单体应用单机部署的情况下,可以使用Java并发处理相关,比如:ReentrantLcok、或者synchronized进行互斥控制。

分布式锁应用场景大都是用在高并发,大流量场景。

当多个进程不在同一个系统中,就需要用分布式锁控制多个进程对资源的访问。


分布式锁的实现

分布式锁一般有三种实现方式,如下图所示:


主要就是:Redis的分布式锁、ZooKeeper的分布式锁、以及数据库乐观锁。

Redis使用比较多,这里我就主要结合Redis来谈分布式锁的实现。

分布式锁的实现原理可以归纳为以下几个步骤:

1.获取锁

当一个节点或进程需要访问共享资源时,它首先向分布式锁服务请求获取锁。

在这个过程中,分布式锁服务会检查当前是否已经有其他节点或进程持有该锁,如果没有,则会将锁授予当前请求的节点或进程,并返回获取锁成功的消息。

public class RedisTool {

private static final String LOCK_SUCCESS = "OK";

private static final String SET_IF_NOT_EXIST = "NX";

private static final String SET_WITH_EXPIRE_TIME = "PX";

/**

* 尝试获取分布式锁

* @param jedis Redis客户端

* @param lockKey 锁

* @param requestId 请求标识

* @param expireTime 超期时间

* @return 是否获取成功

*/

public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
               return true;}return false;}

}


2.访问共享资源

当一个节点或进程获得了分布式锁后,它可以访问共享资源。

在这个过程中,其他节点或进程无法访问该共享资源,因为它们没有获得分布式锁。


3.释放锁

当一个节点或进程完成对共享资源的访问后,它会向分布式锁服务请求释放锁。

在这个过程中,分布式锁服务会将该锁授予其他等待获取锁的节点或进程。

public class RedisTool {

private static final Long RELEASE_SUCCESS = 1L;

/**

* 释放分布式锁

* @param jedis Redis客户端

* @param lockKey 锁

* @param requestId 请求标识

* @return 是否释放成功

*/

public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {return true;}return false;}

}


那么这段Redis释放锁的Lua代码的功能是什么呢?其实很简单,首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。

那么为什么要使用Lua语言来实现呢,留给大家讨论探索。

以上


更多分布式架构系列、阿里架构师进阶系列,请查看以下文章:

阿里架构师进阶从0到1全部合集(建议收藏)

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表