redis实现分布式锁|数据库实现分布式锁|zookeeper实现分布式锁

0、使用场景

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

有这样一个情境,线程A和线程B都共享某个变量X。

如果是单机情况下(单JVM),线程之间共享内存,只要使用线程锁就可以解决并发问题。

如果是分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。

再例如火车站抢票问题,也可以使用分布式锁,大量线程进来抢票,使用分布式锁,来达到每张票只有一个人能抢到,购买到票后就立即释放锁。

1、redis实现分布式锁的条件

为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

  • List item互斥性。在任意时刻,只有一个客户端能持有锁。
  • 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  • 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
  • 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

加锁:

String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

第一条通过设置lockKey唯一来实现加锁;
第二条通过set_if_not_exist和set_with_expire_time来实现即使程序崩溃,过期了也会释放锁而达到解锁的目的,从而不会发生死锁;
第三条要使用到集群部署的选举机制,当一个节点死亡则其他节点自动执行加锁和解锁,保证程序的正常运行;
第四条传requestId可以知道是哪个客户端请求过来的(使用uuid保证唯一性)。

解锁:

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

解锁方法,具体可以关注一下jedis的set方法和eval方法。

2、实现的方法

数据库实现分布式锁

有乐观锁和悲观锁实现机制:
乐观锁是使用版本号来实现,拿到锁,版本号加一,证明该票已经别抢了,其他请求进来,版本号不一样,不让拿锁。
悲观锁是使用FOR UPDATE来进行锁表操作,执行完后mysql执行commit后释放锁,所以mysql设置自动提交。

核心:就是插入数据来获取锁,当要释放锁时就删除数据。

redis实现分布式锁1
redis实现分布式锁2

核心:执行业务是加锁,业务结束后调用脚本方法来删除redis的数据来达到释放锁的目的。

zookeeper实现分布式锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值