redis 的客户端有jedis、lettuce、redission;我个人比较推荐的是redission,因为它的分布式锁和缓存实在是太优秀了。 Redisson采用了基于NIO的Netty框架,封装了大家常用的集合类以及原子类、锁等工具。
本章节主要介绍redission 中重要的两个点:数据结构和锁
本章节主要介绍redission 中重要的两个点:数据结构和锁
map
基于Redis的Redisson的分布式映射结构的RMap Java对象实现了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。与HashMap不同的是,RMap保持了元素的插入顺序。
在特定的场景下,映射缓存(Map)上的高度频繁的读取操作,使网络通信都被视为瓶颈时,可以使用Redisson提供的带有本地缓存功能的映射。
代码示例:
1 | RMap<String, SomeObject> map = redisson.getMap("anyMap"); |
map本身也是可以上锁的:
1 | RMap<MyKey, MyValue> map = redisson.getMap("anyMap"); |
map中还有元素淘汰,本地缓存和数据分片等机制相关类:
元素淘汰(Eviction) 类 – 带有元素淘汰(Eviction)机制的映射类允许针对一个映射中每个元素单独设定 有效时间 和 最长闲置时间 。
本地缓存(LocalCache) 类 – 本地缓存(Local Cache)也叫就近缓存(Near Cache)。这类映射的使用主要用于在特定的场景下,映射缓存(MapCache)上的高度频繁的读取操作,使网络通信都被视为瓶颈的情况。Redisson与Redis通信的同时,还将部分数据保存在本地内存里。这样的设计的好处是它能将读取速度提高最多 45倍 。 所有同名的本地缓存共用一个订阅发布话题,所有更新和过期消息都将通过该话题共享。
数据分片(Sharding) 类 – 数据分片(Sharding)类仅适用于Redis集群环境下,因此带有数据分片(Sharding)功能的映射也叫集群分布式映射。它利用分库的原理,将单一一个映射结构切分为若干个小的映射,并均匀的分布在集群中的各个槽里。这样的设计能使一个单一映射结构突破Redis自身的容量限制,让其容量随集群的扩大而增长。在扩容的同时,还能够使读写性能和元素淘汰处理能力随之成线性增长。
map 类:
Redisson的分布式的RMapCache Java对象在基于RMap的前提下实现了针对单个元素的淘汰机制,这种功能是其他两个redis客户端所不能具备的。
Redis自身并不支持散列(Hash)当中的元素淘汰,因此所有过期元素都是通过org.redisson.EvictionScheduler实例来实现定期清理的。为了保证资源的有效利用,每次运行最多清理300个过期元素。任务的启动时间将根据上次实际清理数量自动调整,间隔时间趋于1秒到1小时之间。比如该次清理时删除了300条元素,那么下次执行清理的时间将在1秒以后(最小间隔时间)。一旦该次清理数量少于上次清理数量,时间间隔将增加1.5倍。
1 | RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap"); |
本地缓存功能充分的利用了JVM的自身内存空间,对部分常用的元素实行就地缓存,这样的设计让读取操作的性能较分布式映射相比提高最多 45倍 。以下配置参数可以用来创建这个实例:
1 | LocalCachedMapOptions options = LocalCachedMapOptions.defaults() |
RClusteredMap 分片map使用示例:
1 | RClusteredMap<String, SomeObject> map = redisson.getClusteredMap("anyMap"); |
映射监听器(Map Listener)可以监听map的活动,代码示例:
1 | RMapCache<String, Integer> map = redisson.getMapCache("myMap"); |
Set
代码示例:
1 | RSet<SomeObject> set = redisson.getSet("anySet"); |
基于Redis的Redisson的分布式RSetCache Java对象在基于RSet的前提下实现了针对单个元素的淘汰机制。和map 一样,所有过期元素都是通过org.redisson.EvictionScheduler实例来实现定期清理的。代码示例:
1 | RSetCache<SomeObject> set = redisson.getSetCache("anySet"); |
分布式RClusteredSet:
1 | RClusteredSet<SomeObject> set = redisson.getClusteredSet("anySet"); |
有序集(SortedSet):
1 | RSortedSet<Integer> set = redisson.getSortedSet("anySet"); |
计分排序集(ScoredSortedSet)是一个可以按插入时指定的元素评分排序的集合:
1 | RScoredSortedSet<SomeObject> set = redisson.getScoredSortedSet("simple"); |
List
RList 示例:
1 | RList<SomeObject> list = redisson.getList("anyList"); |
Queue
无界队列Queue:
1 | RQueue<SomeObject> queue = redisson.getQueue("anyQueue"); |
双端队列(Deque):
1 | RDeque<SomeObject> queue = redisson.getDeque("anyDeque"); |
阻塞队列(Blocking Queue):
1 | RBlockingQueue<SomeObject> queue = redisson.getBlockingQueue("anyQueue"); |
有界阻塞队列(Bounded Blocking Queue):
1 | RBoundedBlockingQueue<SomeObject> queue = redisson.getBoundedBlockingQueue("anyQueue"); |
阻塞双端队列(Blocking Deque):
1 | RBlockingDeque<Integer> deque = redisson.getBlockingDeque("anyDeque"); |
阻塞公平队列(Blocking Fair Queue):
1 | RBlockingFairQueue queue = redisson.getBlockingFairQueue("myQueue"); |
阻塞公平双端队列(Blocking Fair Deque):
1 | RBlockingFairDeque deque = redisson.getBlockingFairDeque("myDeque"); |
延迟队列(Delayed Queue):
1
2
3
4
5
6
7
8
9 RQueue<String> distinationQueue = ...
RDelayedQueue<String> delayedQueue = getDelayedQueue(distinationQueue);
// 10秒钟以后将消息发送到指定队列
delayedQueue.offer("msg1", 10, TimeUnit.SECONDS);
// 一分钟以后将消息发送到指定队列
delayedQueue.offer("msg2", 1, TimeUnit.MINUTES);
// 在该对象不再需要的情况下,应该主动销毁。仅在相关的Redisson对象也需要关闭的时候可以不用主动销毁。
delayedQueue.destroy();
优先队列(Priority Queue),可以通过比较器(Comparator)接口来对元素排序:
1 | RPriorityQueue<Integer> queue = redisson.getPriorityQueue("anyQueue"); |
看门狗
如果负责储存分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期,默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。
可重入锁(Reentrant Lock)
1 | RLock lock = redisson.getLock("anyLock"); |
Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开:
1 | // 加锁以后10秒钟自动解锁 |
异步执行:
1
2
3
4
5 RLock lock = redisson.getLock("anyLock");
lock.lockAsync();
lock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);
公平锁(Fair Lock)
当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程,所有请求线程会在一个队列中排队。当某个线程出现宕机,Redisson会等待5秒后继续下一个线程:
1
2
3 RLock fairLock = redisson.getFairLock("anyLock");
// 最常见的使用方法
fairLock.lock();
联锁(MultiLock)
基于Redis的Redisson分布式联锁RedissonMultiLock对象可以将多个RLock对象关联为一个联锁,每个RLock对象实例可以来自于不同的Redisson实例:
1 | RLock lock1 = redissonInstance1.getLock("lock1"); |
红锁(RedLock)
红锁RedissonRedLock对象可以用来将多个RLock对象关联为一个红锁,每个RLock对象实例可以来自于不同的Redisson实例:
1 | RLock lock1 = redissonInstance1.getLock("lock1"); |
信号量(Semaphore)
同JDK中的信号量:
1 | RSemaphore semaphore = redisson.getSemaphore("semaphore"); |
可过期信号量,是在RSemaphore对象的基础上,为每个信号增加了一个过期时间:
1 | RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore"); |
闭锁(CountDownLatch)
同jdk中的闭锁:
1 | RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch"); |