1、项目中的分布式锁
- redis分布式锁:
- 获取锁:SETNX
- 为避免死锁设置过期时间()
- key过期,业务却未处理完
- 在锁将要过期的时候,如果服务还没有处理完业务,那么将这个锁再续一段时间。比如设置key在10s后过期,那么再开启一个守护线程,在第8s的时候检测服务是否处理完,如果没有,则将这个key再续10s后过期。
- Redisson已实现,这个自动续时的我们称其为”看门狗”。
- 释放锁:del
- SETNX底层原理
- Redis的SETNX命令底层原理是通过单线程模型和事务支持来实现原子性操作。当客户端发送SETNX命令到Redis服务器时,Redis会将该命令加入到命令队列中进行排队。当Redis从队列中取出该命令时,先检查指定的key是否已经存在,如果不存在则使用SETNX命令为其设置新值,并返回1表示设置成功;如果key已经存在,则不执行任何操作并返回0表示设置失败。这个过程是原子性的,可以保证在并发环境下同一时刻只有一个客户端能够成功地为一个key设定值。
- 项目中具体实现
- 加锁
- 尝试获取锁
//NX:表示仅当键不存在时才设置该键。这是实现锁的关键,因为它确保了多个客户端不会同时获取到锁。 //PX:这个选项用于设置键的过期时间,单位是毫秒。这个过期时间是为了防止因为某些原因(如程序崩溃)导致锁无法被释放,从而发生死锁的情况。当锁到达过期时间后,Redis 会自动删除这个键,这样其他客户端就可以尝试获取锁了。 redisTemplate.opsForValue().set(key, value, "NX", "PX", expire);
- 尝试获取锁
- 释放锁:
//释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期, //此时有可能已经被另外一个线程持有锁,所以不能直接删除 //使用lua脚本删除redis中匹配value的key /** * 解锁脚本 */ "if redis.call(\"get\",KEYS[1]) == ARGV[1] " + "then " + " redis.call(\"del\",KEYS[1]) " + "else " + " return 0 " + "end ";
- 加锁
- 获取锁:SETNX
- zk分布式锁:
-
zookeeper就是通过临时节点和节点有序来实现分布式锁的。
-
每个获取锁的线程会在zk创建一个临时有序的节点。
-
节点创建成功后,判断当前线程创建的节点的序号是否是最小的。
-
如果序号是最小的,那么获取锁成功。
-
如果序号不是最小的,则对自己创建节点的前一节点进行监听。如果前一个节点被删了(锁被释放了),那么就会唤醒当前节点,成功获取锁。
-
-
-
2、分布式事务
- CAP
- CAP 模型是说,在一个分布式系统里面,不可能同时满足三个点
- CAP 模型是说,在一个分布式系统里面,不可能同时满足三个点