持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情
Redission 分布式集合 MAP
映射(Map)
分布式映射结构的 RMap 对象实现了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。与HashMap不同的是,RMap保持了元素的插入顺序。该对象的最大容量受Redis限制,最大元素数量是4 294 967 295个。
基本使用
put返回值:先前关联值putIfAbsent不存在就插入,返回值:如果键是哈希中的新键并且设置了值,则为null。如果键已存在于哈希中且尚未进行更改,则返回上一个值remove移除键fastPut工作速度比put(Object,Object)快,但不返回与键关联的前一个值fastRemove工作速度比put(Object,Object)快,但不返回与键关联的值
@Test
public void test16(){
RMap<String, Object> map = redisson.getMap("anyMap");
// put 返回值:先前关联值
Object prevObject = map.put("123", 11);
System.out.println(prevObject); // null
// putIfAbsent 不存在就插入,返回值:如果键是哈希中的新键并且设置了值,则为null。如果键已存在于哈希中且尚未进行更改,则返回上一个值
Object currentObject = map.putIfAbsent("123", 11);
System.out.println(currentObject); // 11
// remove 移除键
Object obj = map.remove("123");
System.out.println(obj);
// 在不需要旧值的情况下可以使用fast为前缀的类似方法
// fastPut 工作速度比put(Object,Object)快,但不返回与键关联的前一个值
map.fastPut("321", 22);
// fastRemove 工作速度比put(Object,Object)快,但不返回与键关联的值
map.fastRemove("321");
}
普通字段锁&读写锁
getLock获取锁lock上锁unlock解锁getReadWriteLock获取读写锁readLock().lock()上读锁readLock().unlock()解读锁
@Test
public void test17() throws InterruptedException {
RMap<String, Object> map = redisson.getMap("anyMap");
// getLock 获取锁
String k = "kk";
RLock keyLock = map.getLock(k);
// lock 上锁
keyLock.lock();
try {
Object v = map.get(k);
// 其他业务逻辑
} finally {
// unlock 解锁
keyLock.unlock();
}
// getReadWriteLock 获取读写锁
RReadWriteLock rwLock = map.getReadWriteLock(k);
// readLock().lock() 上读锁
rwLock.readLock().lock();
try {
Object v = map.get(k);
// 其他业务逻辑
} finally {
// readLock().unlock() 解读锁
rwLock.readLock().unlock();
}
}
元素淘汰(Eviction)
元素淘汰(Eviction)机制的映射类允许针对一个映射中每个元素单独设定 有效时间 和 最长闲置时间 。
RMapCache Java对象在基于RMap的前提下实现了针对单个元素的淘汰机制。同时仍然保留了元素的插入顺序。由于RMapCache是基于RMap实现的,使它同时继承了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。Redisson提供的Spring Cache整合以及JCache正是基于这样的功能来实现的。
目前的Redis自身并不支持散列(Hash)当中的元素淘汰,因此所有过期元素都是通过org.redisson.EvictionScheduler实例来实现定期清理的。为了保证资源的有效利用,每次运行最多清理300个过期元素。任务的启动时间将根据上次实际清理数量自动调整,间隔时间趋于1秒到1小时之间。比如该次清理时删除了300条元素,那么下次执行清理的时间将在1秒以后(最小间隔时间)。一旦该次清理数量少于上次清理数量,时间间隔将增加1.5倍。
ttlkey\value条目的生存时间。如果0则无限存储maxIdleTime键\值输入的最大空闲时间。如果为0,则最大空闲时间不会影响条目过期
@Test
public void test18(){
RMapCache<String, Object> map = redisson.getMapCache("anyMap");
// ttl key\value条目的生存时间。如果0则无限存储
// maxIdleTime 键\值输入的最大空闲时间。如果为0,则最大空闲时间不会影响条目过期
// 有效时间 ttl = 10分钟
map.put("key1", "a", 10, TimeUnit.MINUTES);
// 有效时间 ttl = 10分钟, 最长闲置时间 maxIdleTime = 10秒钟
map.put("key1", "b", 10, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);
// 有效时间 = 3 秒钟
map.putIfAbsent("key2", "a", 3, TimeUnit.SECONDS);
// 有效时间 ttl = 40秒钟, 最长闲置时间 maxIdleTime = 10秒钟
map.putIfAbsent("key2", "b", 40, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);
}
本地缓存(LocalCache)
本地缓存(Local Cache)也叫就近缓存(Near Cache)。这类映射的使用主要用于在特定的场景下,映射缓存(MapCache)上的高度频繁的读取操作,使网络通信都被视为瓶颈的情况。Redisson与Redis通信的同时,还将部分数据保存在本地内存里。这样的设计的好处是它能将读取速度提高最多 45倍 。 所有同名的本地缓存共用一个订阅发布话题,所有更新和过期消息都将通过该话题共享。
LocalCachedMapOptions options = LocalCachedMapOptions.defaults()
// 用于淘汰清除本地缓存内的元素
// 共有以下几种选择:
// LFU - 统计元素的使用频率,淘汰用得最少(最不常用)的。
// LRU - 按元素使用时间排序比较,淘汰最早(最久远)的。
// SOFT - 元素用Java的WeakReference来保存,缓存元素通过GC过程清除。
// WEAK - 元素用Java的SoftReference来保存, 缓存元素通过GC过程清除。
// NONE - 永不淘汰清除缓存元素。
.evictionPolicy(EvictionPolicy.NONE)
// 如果缓存容量值为0表示不限制本地缓存容量大小
.cacheSize(1000)
// 以下选项适用于断线原因造成了未收到本地缓存更新消息的情况。
// 断线重连的策略有以下几种:
// CLEAR - 如果断线一段时间以后则在重新建立连接以后清空本地缓存
// LOAD - 在服务端保存一份10分钟的作废日志
// 如果10分钟内重新建立连接,则按照作废日志内的记录清空本地缓存的元素
// 如果断线时间超过了这个时间,则将清空本地缓存中所有的内容
// NONE - 默认值。断线重连时不做处理。
.reconnectionStrategy(ReconnectionStrategy.NONE)
// 以下选项适用于不同本地缓存之间相互保持同步的情况
// 缓存同步策略有以下几种:
// INVALIDATE - 默认值。当本地缓存映射的某条元素发生变动时,同时驱逐所有相同本地缓存映射内的该元素
// UPDATE - 当本地缓存映射的某条元素发生变动时,同时更新所有相同本地缓存映射内的该元素
// NONE - 不做任何同步处理
.syncStrategy(SyncStrategy.INVALIDATE)
// 每个Map本地缓存里元素的有效时间,默认毫秒为单位
.timeToLive(10000)
// 或者
.timeToLive(10, TimeUnit.SECONDS)
// 每个Map本地缓存里元素的最长闲置时间,默认毫秒为单位
.maxIdle(10000)
// 或者
.maxIdle(10, TimeUnit.SECONDS);
RLocalCachedMap<String, Object> map = redisson.getLocalCachedMap("test", options);
Object prevObject = map.put("123", 1);
Object currentObject = map.putIfAbsent("323", 2);
Object obj = map.remove("123");
// 在不需要旧值的情况下可以使用fast为前缀的类似方法
map.fastPut("a", 1);
map.fastPutIfAbsent("d", 32);
map.fastRemove("b");
map.clearLocalCache();
数据分片(Sharding)
数据分片(Sharding)类仅适用于Redis集群环境下,因此带有数据分片(Sharding)功能的映射也叫集群分布式映射。它利用分库的原理,将单一一个映射结构切分为若干个小的映射,并均匀的分布在集群中的各个槽里。这样的设计能使一个单一映射结构突破Redis自身的容量限制,让其容量随集群的扩大而增长。在扩容的同时,还能够使读写性能和元素淘汰处理能力随之成线性增长。
| 接口名称 中文名称 | RedissonClient 对应的构造方法 | 本地缓存功能 Local Cache | 数据分片功能 Sharding | 元素淘汰功能 Eviction |
|---|---|---|---|---|
| RMap 映射 | getMap() | No | No | No |
| RMapCache 映射缓存 | getMapCache() | No | No | Yes |
| RLocalCachedMap 本地缓存映射 | getLocalCachedMap() | Yes | No | No |
| RLocalCachedMap Cache 本地缓存映射缓存 仅限于Redisson PRO版本 | getLocalCachedMapCache() | Yes | No | Yes |
| RClusteredMap 集群分布式映射存 仅限于Redisson PRO版本 | getClusteredMap() | No | Yes | No |
| RClusteredMapCache 集群分布式映射缓存存 仅限于Redisson PRO版本 | getClusteredMapCache() | No | Yes | Yes |
| RClusteredLocal CachedMap 集群分布式本地缓存映射存 仅限于Redisson PRO版本 | getClusteredLocal CachedMap() | Yes | Yes | No |
| RClusteredLocal CachedMapCache 集群分布式本地缓存映射缓存存 仅限于Redisson PRO版本 | getClusteredLocal CachedMapCache() | Yes | Yes | Yes |
映射监听器(Map Listener)
为所有实现了RMapCache或RLocalCachedMapCache接口的对象提供了监听以下事件的监听器:
事件 | 监听器
元素 添加 事件 | org.redisson.api.map.event.EntryCreatedListener
元素 过期 事件 | org.redisson.api.map.event.EntryExpiredListener
元素 删除 事件 | org.redisson.api.map.event.EntryRemovedListener
元素 更新 事件 | org.redisson.api.map.event.EntryUpdatedListener
@Test
public void test21(){
RMapCache<String, Integer> map = redisson.getMapCache("myMap");
int updateListener = map.addListener(new EntryUpdatedListener<Integer, Integer>() {
@Override
public void onUpdated(EntryEvent<Integer, Integer> event) {
event.getKey(); // 字段名
event.getValue(); // 新值
event.getOldValue(); // 旧值
// ...
}
});
int createListener = map.addListener(new EntryCreatedListener<Integer, Integer>() {
@Override
public void onCreated(EntryEvent<Integer, Integer> event) {
event.getKey(); // 字段名
event.getValue(); // 值
// ...
}
});
int expireListener = map.addListener(new EntryExpiredListener<Integer, Integer>() {
@Override
public void onExpired(EntryEvent<Integer, Integer> event) {
event.getKey(); // 字段名
event.getValue(); // 值
// ...
}
});
int removeListener = map.addListener(new EntryRemovedListener<Integer, Integer>() {
@Override
public void onRemoved(EntryEvent<Integer, Integer> event) {
event.getKey(); // 字段名
event.getValue(); // 值
// ...
}
});
map.removeListener(updateListener);
map.removeListener(createListener);
map.removeListener(expireListener);
map.removeListener(removeListener);
}
LRU有界映射
以LRU为驱逐策略的分布式LRU有界映射对象。顾名思义,分布式LRU有界映射允许通过对其中元素按使用时间排序处理的方式,主动移除超过规定容量限制的元素。
RMapCache<String, String> map = redisson.getMapCache("map");
// 尝试将该映射的最大容量限制设定为10
map.trySetMaxSize(10);
// 将该映射的最大容量限制设定或更改为10
map.setMaxSize(10);
map.put("1", "2");
map.put("3", "3", 1, TimeUnit.SECONDS);