Redis实现分布式锁

Redis能做的事情有很多,不仅于缓存,如分布式锁,也有很多很好的实现;

什么是分布式锁

首先锁的作用是为了避免资源争夺或者资源被篡改导致程序错误,如synchronized、Lock和ReentrantLock都可以实现资源的锁定,给资源添加一把锁,其他程序再次访问时,发现有锁就等待锁释放后再访问;

而集群模式下,程序内部锁最多只能保证一个服务只有一个线程在操作,但两个服务就会有两个线程,对于资源,又会出现两个线程并发处理的情况,所以我们就用到了分布式锁;

分布式锁:通过外部的一个锁变量,来保证资源只能由获得锁的人来访问;

使用场景

存储系统中,库存数量存储在redis中,假如某个时刻,redis里面的某个商品库存为1,此时两个请求同时到来,先校验库存,然后做减库存操作;单体服务中通过普通锁即可解决,达到持有锁的线程单独访问;

然而在多节点部署的情况下,假设此时两个用户的请求同时到来,但是落在了不同的机器上,那么这两个请求是可以同时执行了,此时就出现了并发问题

(link:一文搞懂分布式锁及其业务场景_chunqiu3351的博客-优快云博客

如何实现分布式锁

1. set key value ex nx(推荐)

Redis中提供了如下的语法来帮我们实现分布式锁

set lock:key value ex 10 nx
del lock:key

这是Redis2.8之后提供的语法,指定锁名称lock:key,设置超时时间等,现在指定锁和设置超时时间都是原子性的了。

在释放锁的时候也会出现不同步问题,首先获取锁,判断锁是否存在,然后再释放,这时可以通过引入lua脚本,来实现语句的原子性

2. setnx + expire(不推荐)

2.8之前是通过两个命令

setnx lock:key true
expire key 10s
del lock:key

此时单纯的设置锁,

1. 可能会导致服务器宕机时锁未释放,进而发生死锁;

2. 添加过期时间之前服务器宕机,锁也不释放,导致死锁;

所以添加了上述的原子性可过期锁;

3. 通过lua脚本实现语法的原子性

public static void main(String[] args) {
    JedisPool pool = new JedisPool("localhost", 6379);
    Jedis jedis = pool.getResource();
    String lock_lua = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" +
            " redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end";
    Object result = jedis.eval(
            lock_lua,
            Collections.singletonList("lock:demo2"),
            Arrays.asList("zhangsan", "5"));
    //判断是否成功
    System.err.println(result);
    String del_lua = " if redis.call('get',KEYS[1]) == ARGV[1] then \n" +
                     "    return redis.call('del',KEYS[1]) \n" +
                     " else\n" +
                     "    return 0\n" +
                     " end;";
    Object result2 = jedis.eval(
            del_lua,
            Collections.singletonList("lock:demo2"),
            List.of("zhangsan"));
    System.err.println(result2);
}

分布式锁框架

Redisson看门狗框架

Redis学习笔记---Redis的分布式锁框架Redisson_馒头太帅了的博客-优快云博客_redisson笔记

RedLock实现分布式半数请求锁

Shedlock-spring实现分布式锁

Shedlock可以选择多种存储库来实现分布式锁,当然redis也是可以的,在使用redis实现分布式锁的时候也是通过set key value ex nx方式实现的;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值