如何用Redis实现分布式锁的(含和Zookeeper分布式锁实现的对比)?

首先你得知道什么是分布式锁吧?,然后你得知道在什么场景下需要去用到分布式锁吧?,然后你应该知道如何在你的业务中去利用Redis的分布式锁吧?,最后你得知道Redis的分布式锁的实现方式和其他的Zookeeper或则数据库实现分布式锁有什么区别吧?,然后他们之间的优缺点和好处吧?

然后本文主要是围绕这几个问题逐一带你了解分布式锁的玩法,以及分布式锁的扩展知识点。

(1)什么是分布式锁?

  • 首先要想了解分布式锁,就必须得知道java中的lock锁、synchronize锁等,他们是用在当有多线程问题出现的时候(其实不就是并发吗),为了保证某个时间点只能有一个线程进来获取到资源,所以java中的lock锁这种他们是为了解决多线程之间的资源获取问题,并且他们都是运行在同一个JVM下的前提下。
  • 但是分布式锁其实你可以理解为如果有多个系统其实也就是同时启用多个JVM(比如说在springcloud中,每次启动一个服务就是启动一个JVM也就是启用一个进程),当多个JVM之间想要保证同一个时间点,只有一个JVM能够去获取对应的资源,其实分布式锁就是用来控制多进程之间的资源获取的问题,所以衍生出了分布式锁的概念

(2)在什么场景下需要去用到分布式锁?

  • 如果部署在不同机器节点上的系统在同一条数据上面操作,比如多个节点机器对同一个订单操作不同的流程有可能会导致该笔订单最后状态出现错误,造成损失。
  • 使用分布式锁可以避免不同节点重复相同的工作,这些工作会浪费资源。比如用户付了钱之后有可能不同节点会发出多封短信。

(3)如何在你的业务中去利用Redis的分布式锁?

  • 一般都是会在自己的业务中定义一个自己的RedisService,把需要用到的API都封装到这里,然后我们只需要在我们的系统中用到的时候直接去调用就行了
  • 使用 SET resource_name my_random_value NX PX 30000,这个命令是一个原子操作添加操作,my_random_value是由客户端生成的一个随机字符串,它要保证在足够长的一段时间内在所有客户端的所有获取锁的请求中都是唯一的其中NX(if not exist)这个表示只有当resource_name对应的key值不存在的时候才能SET成功,然后PX 30000表示这个锁有一个30秒的自动过期时间。当然,这里30秒只是一个例子,客户端可以选择合适的过期时间。,如果当你要set成功的话,就会返回一个“OK”
  • 其实那个随机中的value值其实是为了后面如果你想要去提前解锁的话也是可以通过这个的值来实现的
  • 完整的命令其实就是说:当前没有锁(key不存在),那么就进行加锁操作,并对锁设置个有效期,同时value表示加锁的客户端。2. 已有锁存在,不做任何操作。
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, my_random_value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
	return true;}return false;
}

}

解锁操作:

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;}

}

(4)这里先简单了解一下Zookeeper的是怎么实现枷锁的?
在这里插入图片描述
看了上面这个图,其实已经是很形象了,Zookeeper其实就是把他一些资源就跟计算机中的文件存储系统一样,把每一个资源都当成一个文件夹,文件夹下又可以继续放文件夹或者是文件(自己的电脑上首先文件夹不能重名吧,文件也不能重名吧,重名之后是不是也会有XXX副本(1),XXXX副本(2)的这种情况),然后你再把它想象为是一颗二叉树的形状,然后他还有一个机制就是可以进行watch,你可以理解为他可以时时刻刻在你要新建一个文件的时候是不是会重名

图二;
在这里插入图片描述
这里对上面的两张图来进行一个描述Zookeeper的加锁过程和原理的流程:

  1. 首先你如果把一个lock文件夹下的resource_name1作为你业务中需要用到的一个数据资源(可以比作是你的秒杀的一双AJ吧,只有一双限量的),那么现在大家都来去抢这双AJ
  2. 首先客户端A发起请求过来想要去抢这个AJ,然后他就是会在resource_name1下又新建一个临时文件xxxxxx_lock_0000001(这个名字在Zookeeper中叫做临时顺序节点),此时客户端A已经抢到AJ了,也已经下单了,其实在客户端A抢的同时,B也抢了,但是他没有抢到他还在一直抢,这个时候Zookeeper也会给B生成一个临时顺序节点xxxxxx_lock_0000002,其实这个时候B的这个临时节点一直在盯着A的临时节点xxxxxx_lock_0000001,如果他被删除了,此时的B生成的临时节点会立刻顶上
  3. 刚好客户端A他又不想要了,然后取消了订单,但是B想要啊,他一直在疯狂抢,然后就轮到B的临时节点了,所以说他抢到了,然后直接付款了,
  4. 其实就是说一个资源下只能有一个临时节点能持有获取资源的能力,刚好这种思想不就是分布式锁想要的结果吗,你拿到了别人都是老二,你不放手被人永远拿不到

大概流程:

在这里插入图片描述

(5)Redis的分布式锁的实现方式和其他的Zookeeper或则数据库实现分布式锁有什么区别?

  • List item

最后想说的:

  • 其实在Redis的分布式锁中还是有些不完美的,首先一般Redis都是集群部署吧,毕竟安全性比较高,至少得是主备两个节点吧,当机器master节点A不可用的时候,系统自动切到B机器Slave上,而且主备都是进行异步的进行备份的,那么这个时候其实是会出现一种情况的:
  • 如果有个用户1获取到了节点A资源中获取到了锁,但是此时突然服务器节点A宕机了,存储锁的key还没有来得及同步到B机器Slave上。机器BSlave升级为Master,此时又来一个用户2同样获取到了之前用户1获取的那个资源,但是由于A节点挂了,但是A节点的那个key还没来得及同步到B节点上,那么此时用户1和用户2都获取到了这个资源,那么其实这个时候分布式锁就没有起到作用。

参考文章:https://laijianfeng.org/2019/01/利用Zookeeper实现-分布式锁/

https://juejin.im/post/5c01532ef265da61362232ed
官方大牛翻译:http://zhangtielei.com/posts/blog-redlock-reasoning.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值