上方蓝色“程序员追风”,选择“设为星标”
回复“资料”获取整理好的面试资料
原文:blog.csdn.net/Ascend1977/article/details/131373419
之前我们讲解了如何用 Redis 实现分布式锁的方案,它提供了简单的原语来实现基于Redis的分布式锁。然而,Redis作为分布式锁的实现方式也存在一些缺点。本文将引入Redisson来实现分布式锁。
传送门:https://blog.csdn.net/Ascend1977/article/details/131221941
1、Redisson是什么
Redisson是一个基于Redis的分布式Java框架。它提供了丰富的功能和工具,帮助开发者在分布式系统中解决数据共享、并发控制和任务调度等问题。通过使用Redisson,开发者可以轻松地操作Redis的分布式对象(如集合、映射、队列等),实现可靠的分布式锁机制,以及管理和调度分布式环境中的任务和服务。
Redisson提供的功能
分布式对象:
-
分布式集合(Set、SortedSet、List) -
分布式映射(Map) -
分布式队列(Queue、Deque) -
分布式锁(Lock) -
分布式计数器(AtomicLong)
分布式限流:
-
令牌桶算法(Rate Limiter) -
漏桶算法(Rate Limiter)
分布式发布订阅:
-
发布订阅模式(Pub-Sub) -
消息监听器容器(Message Listener Container)
分布式锁和同步:
-
可重入锁(ReentrantLock) -
公平锁(FairLock) -
联锁(MultiLock) -
红锁(RedLock) -
读写锁(ReadWriteLock) -
信号量(Semaphore) -
闭锁(CountDownLatch) -
栅栏(CyclicBarrier)
分布式服务和任务调度:
-
远程服务(Remote Service) -
分布式任务调度器(Task Scheduler) -
分布式延迟队列(Delayed Queue)
分布式地理空间索引(Geospatial Index):
-
地理位置存储 -
地理位置搜索
分布式布隆过滤器(Bloom Filter)和可布隆过滤器(Bloom Filter)。
分布式缓存:
-
对Redis进行本地缓存 -
Spring缓存注解支持
分布式连接池:
-
支持连接池管理和维护
Redis集群和哨兵支持:
-
支持Redis集群模式 -
支持Redis哨兵模式 -
对于使用Redis集群部署的场景,Redisson可以自动识别和操作集群中的多个节点,保证数据的高可用性和扩展性。而对于使用Redis哨兵模式部署的场景,Redisson可以监控并切换到可用的主从节点,实现高可靠性和容错能力。
Spring集成:
-
与Spring框架的无缝集成 -
支持Spring缓存注解
2、Redisson分布式锁
Redisson的分布式锁的特点
线程安全:分布式锁可以确保在多线程和多进程环境下的数据一致性和可靠性。
-
可重入性: 同一个线程可以多次获取同一个锁,避免死锁的问题。
-
锁超时: 支持设置锁的有效期,防止锁被长时间占用而导致系统出现问题。
-
阻塞式获取锁: 当某个线程尝试获取锁时,如果锁已经被其他线程占用,则该线程可以选择等待直到锁释放。
-
无阻塞式获取锁: 当某个线程尝试获取锁时,如果锁已经被其他线程占用,则该线程不会等待,而是立即返回获取锁失败的信息。
Redisson的分布式锁的缺点
单点故障: Redisson的分布式锁依赖于Redis集群,如果Redis集群出现故障或不可用,可能导致分布式锁的可靠性和可用性受到影响。因此,在使用Redisson分布式锁时,需要特别关注Redis集群的稳定性和高可用性。
锁竞争: 当多个线程同时请求获取分布式锁时,可能出现锁竞争的情况。如果锁竞争较为激烈,可能会导致性能下降和请求超时等问题。此外,由于Redisson分布式锁是基于Redis进行实现的,如果Redis节点的处理能力无法满足高并发的锁请求,可能会导致锁请求被延迟或阻塞。
死锁风险: 分布式环境下,由于网络通信、节点故障等因素,可能导致锁无法正常释放,从而引发死锁问题。需要合理设计和使用锁的超时时间、自动释放机制等来降低死锁风险。
锁粒度管理: 在分布式环境下,锁的粒度管理是一个重要的问题。过于细粒度的锁可能导致并发性能下降,而过于粗粒度的锁可能会影响系统的可伸缩性和并发性能。需要根据具体的业务场景和并发访问模式合理选择锁的粒度。
数据一致性: 使用分布式锁保证多个操作的原子性是很常见的应用场景之一。然而,分布式锁通常只能提供粗粒度的互斥访问,不能保证数据的完全一致性。在一些特定的应用场景中,可能需要额外的措施来确保数据的最终一致性。
Redisson分布式锁源码分析
importorg.redisson.api.RLock;importorg.redisson.api.RedissonClient;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;@ServicepublicclassSomeService{@AutowiredprivateRedissonClientredissonClient;publicvoiddoSomething(){StringlockKey="myLock";//锁的keyRLocklock=redissonClient.getLock(lockKey);try{lock.lock();//获取锁//在这里执行需要加锁保护的代码}finally{lock.unlock();//释放锁}}}
RLock.lock()
使用Rlock.lock() 方法时 ,如果当前没有其他线程或进程持有该锁,那么调用线程将立即获得锁定,并继续执行后续的代码。如果其他线程或进程已经持有了该锁,那么调用线程将被阻塞,直到该锁被释放为止。
此外,Rlock.lock() 方法还具有以下特点:
-
可重入性: 同一个线程可以多次调用 Rlock.lock() 方法而不会造成死锁,只需确保每次 lock() 调用都有相应的 unlock() 调用与之匹配。 -
超时机制: 可以通过 lock() 方法中的参数设置等待锁的超时时间,避免因为无法获得锁而一直等待。 -
自动续期: 当线程持有锁的时间超过设置的锁的过期时间时,Redisson 会自动延长锁的有效期,避免因为业务执行时间过长而导致锁过期。 -
防止死锁: Redisson 通过唯一标识锁的 ID 来区分不同的锁,防止发生死锁。
lock() 方法加锁流程

RLock.unlock()
RLock.unlock()方法用于释放由Redission分布式锁所保护的资源。它允许持有锁的线程主动释放锁,从而允许其他线程获取该锁并访问共享资源。
注意事项:
RLock.unlock()方法应该在保护的临界区代码执行完毕后进行调用,以确保锁的及时释放。
在多线程环境下,释放锁的顺序应该与获取锁的顺序相对应,以避免死锁或资源争用的问题。
如果当前线程没有持有锁,调用RLock.unlock()方法不会抛出异常,也不会影响其他线程。
如果Redisson客户端刚加锁成功,并且未指定leaseTime,后台会启动一个定时任务watchdog每隔10s检查key,key如果存在就为它⾃动续命到30s;在watchdog定时任务存在的情况下,如果不是主动释放锁,那么key将会⼀直的被watchdog这个定时任务维持加锁。但是如果客户端宕机了,定时任务watchdog也就没了,也就没有锁续约机制了,那么过完30s之后,key会⾃动被删除、key对应的锁也自动被释放了。
unlock()方法解锁流程

你在看吗
本篇文章来源于微信公众号: 程序员追风
微信扫描下方的二维码阅读本文

Comments NOTHING