Redisson是Redis服务器上的分布式可伸缩Java数据结构----驻内存数据网格(In-Memory Data Grid,IMDG)。底层使用netty框架,并提供了与java对象相对应的分布式对象、分布式集合、分布式锁和同步器、分布式服务等一系列的Redisson的分布式对象。
IMDG是什么
将内存作为存储介质,在对主存的使用上IMDG有以下特性:
数据是分布式存储在多台服务器上,可以根据需要增减服务器
IMDG需要克服的核心问题是容量限制和可靠性。通过水平扩展克服了内存容量的限制,通过复制保证可靠性
一般使用堆外内存降低垃圾回收压力
与Spring Boot集成
1、Maven依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.11.6</version>
</dependency>
2、添加配置文件redisson-xx.yml
# common spring boot settings
spring.redis.database=
spring.redis.host=
spring.redis.port=
spring.redis.password=
# Redisson settings
#path to config - redisson.yaml
spring.redis.redisson.config=classpath:redisson-xx.yaml
3、配置类创建RedissonClient
@Configuration
public class RedssonConfig {
@Bean(destroyMethod="shutdown")
public RedissonClient redisson() throws IOException {
RedissonClient redisson = Redisson.create(
Config.fromYAML(new ClassPathResource("redisson-xx.yml").getInputStream()));
return redisson;
}
}
之后通过@Autowired注入RedissonClient 就可以使用Redisson分布式应用了(例如秒杀系统)。
单个集合分片
自动分片功能是将单个数据结构拆分,根据分片算法分为若干片段(默认231,231个片段分到4个主节点,每个大约57个),均匀分布在整个集群。可以充分利用集群内存资源,可以提高读性能,读性能随集群扩张而提升。
分布式对象
每一个Redisson对象都有一个Redis数据实例相对应。
1、通用对象桶
Redisson分布式对象RBucket,可以存放任意类型对象
2、二进制流
Redisson分布式对象RBinaryStream,InputStream和OutoutStream接口实现
3、地理空间对象桶
Reddisson分布式RGo,储存于地理位置有关的对象桶
4、BitSet
Reddisson分布式RBitSet,是分布式的可伸缩位向量
通过实现RClusteredBitSet接口,可以在集群环境下数据分片
5、布隆过滤器
Reddisson利用Redis实现了java分布式的布隆过滤器RBloomFilter
public class BloomFilterExamples {
public static void main(String[] args) {
// connects to 127.0.0.1:6379 by default
RedissonClient redisson = Redisson.create();
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("bloomFilter");
bloomFilter.tryInit(100_000_000, 0.03);
bloomFilter.add("a");
bloomFilter.add("b");
bloomFilter.add("c");
bloomFilter.add("d");
bloomFilter.getExpectedInsertions();
bloomFilter.getFalseProbability();
bloomFilter.getHashIterations();
bloomFilter.contains("a");
bloomFilter.count();
redisson.shutdown();
}
}
实现RClusteredBloomFilter接口,可以分片。通过压缩未使用的比特位来释放集群内存空间
6、基数估计算法(RHyperLogLog)
可以在有限的空间通过概率算法统计大量数据
7、限流器(RRateLimiter )
可以用来在分布式环境下限制请求方的调用频率。适用于不同或相同的Reddisson实例的多线程限流。并不保证公平性
public class RateLimiterExamples {
public static void main(String[] args) throws InterruptedException {
// connects to 127.0.0.1:6379 by default
RedissonClient redisson = Redisson.create();
RRateLimiter limiter = redisson.getRateLimiter("myLimiter");
// one permit per 2 seconds
limiter.trySetRate(RateType.OVERALL, 1, 2, RateIntervalUnit.SECONDS);
CountDownLatch latch = new CountDownLatch(2);
limiter.acquire(1);
latch.countDown();
Thread t = new Thread(() -> {
limiter.acquire(1);
latch.countDown();
});
t.start();
t.join();
latch.await();
redisson.shutdown();
}
}
及原子整长形(RAtomicLong )、原子双精度浮点(RAtomicDouble )、话题(订阅分发)(RTopic )、整长型累加器(RLongAdder )、双精度浮点累加器(RLongDouble )等分布式对象
分布式集合
在Redis分布式的集合元素与java对象相对应。包括:映射、多值映射(Multimap)、集(Set)、有序集(SortedSet)、计分排序集(ScoredSortedSet)、字典排序集(LexSortedSet)、列表(List)、队列(Queue)、双端队列(Deque)、阻塞队列(Blocking Queue)
映射(RMap)
映射类型按照特性主要分为三类:元素淘汰、本地缓存、数据分片。
1、元素淘汰(Eviction)类:对映射中每个元素单独设置有效时间和最长闲置时间。保留了元素的插入顺序。不支持散列(hash)的元素淘汰,过期元素通过EvictionScheduler实例定期清理。实现类RMapCache
2、本地缓存(LocalCache)类:本地缓存也叫就近缓存,主要用在特定场景下。映射缓存上的高度频繁的读取操作,使网络通信被视为瓶颈的情况下。较分布式映射提高45倍。实现类RLocalCachedMap
3、数据分片(Sharding):利用分库的原理,将单一映射结构切分若干,并均匀分布在集群的各个槽里。可以突破Redis自身的容量限制,可以随集群的扩大而增长,也可以使读写性能和元素淘汰能力随之线性增长。主要实现类RClusteredMap
当然还有其他类型,比如映射监听器、LRU有界映射
映射监听器:监听元素的添加(EntryCreatedListener)、过期、删除、更新事件
LRU有界映射:根据时间排序,超过容量限制的元素会被删除
public class MapExamples {
public static void main(String[] args) throws IOException {
// connects to 127.0.0.1:6379 by default
RedissonClient redisson = Redisson.create();
RMap<String, Integer> map = redisson.getMap("myMap");
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
boolean contains = map.containsKey("a");
Integer value = map.get("c");
Integer updatedValue = map.addAndGet("a", 32);
Integer valueSize = map.valueSize("c");
Set<String> keys = new HashSet<String>();
keys.add("a");
keys.add("b");
keys.add("c");
Map<String, Integer> mapSlice = map.getAll(keys);
// use read* methods to fetch all objects
Set<String> allKeys = map.readAllKeySet();
Collection<Integer> allValues = map.readAllValues();
Set<Entry<String, Integer>> allEntries = map.readAllEntrySet();
// use fast* methods when previous value is not required
boolean isNewKey = map.fastPut("a", 100);
boolean isNewKeyPut = map.fastPutIfAbsent("d", 33);
long removedAmount = map.fastRemove("b");
redisson.shutdown();
}
}
映射持久化方式(缓存策略)
将映射中的数据持久化到外部存储服务的功能
主要场景:
1、作为业务和外部存储媒介之间的缓存
2、用来增加数据的持久性、增加已被驱逐的数据的寿命
3、用来缓存数据库、web服务或其他数据源的数据
Read-through策略:如果在映射中不存在,则通过Maploader对象加载
Write-through策略(数据同步写入):对映射数据的更改则会通过MapWriter写入到外部存储系统,然后更新redis里面的数据
Write-behind策略(数据异步写入):对映射数据的更改先写到redis,然后使用异步方式写入到外部存储
分布式锁和同步器
如果负责存储分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态,这时便会出现死锁。为了避免发生这种状况,提供了一个看门狗,它的作用是在Redisson实例被关闭之前,不断延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟。
分布式锁种类有:可重入锁(Reentrant Lock)、公平锁、联锁(MultiLock)
、红锁(RedLock)、 读写锁、信号量(Semaphore)、可过期性信号量(PermitExpirableSemaphore)、闭锁(CountDownLatch)
public class LockExamples {
public static void main(String[] args) throws InterruptedException {
// connects to 127.0.0.1:6379 by default
RedissonClient redisson = Redisson.create();
RLock lock = redisson.getLock("lock");
lock.lock(2, TimeUnit.SECONDS);
Thread t = new Thread() {
public void run() {
RLock lock1 = redisson.getLock("lock");
lock1.lock();
lock1.unlock();
};
};
t.start();
t.join();
lock.unlock();
redisson.shutdown();
}
}
红锁
public class RedLockExamples {
public static void main(String[] args) throws InterruptedException {
// connects to 127.0.0.1:6379 by default
RedissonClient client1 = Redisson.create();
RedissonClient client2 = Redisson.create();
RLock lock1 = client1.getLock("lock1");
RLock lock2 = client1.getLock("lock2");
RLock lock3 = client2.getLock("lock3");
Thread t1 = new Thread() {
public void run() {
lock3.lock();
};
};
t1.start();
t1.join();
Thread t = new Thread() {
public void run() {
RedissonMultiLock lock = new RedissonRedLock(lock1, lock2, lock3);
lock.lock();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
lock.unlock();
};
};
t.start();
t.join(1000);
lock3.forceUnlock();
RedissonMultiLock lock = new RedissonRedLock(lock1, lock2, lock3);
lock.lock();
lock.unlock();
client1.shutdown();
client2.shutdown();
}
}
分布式服务
分布式服务包括分布式远程服务(RRemoteService )、分布式实时对象服务(RLiveObjectService )、分布式执行服务(RExecutorService )、分布式调度任务服务(RScheduledExecutorService )、分布式映射归纳服务(MapReduce)
1、分布式远程服务:实现了java的RPC远程调用,可以通过共享接口执行另一个Redisson实例里的对象方法。
2、分布式实时对象(RLO):使用生成的代理类,将一个指定的普通java类的所有字段以及这些字段的操作(get set方法)全部映射到一个Redis Hash的数据结构。get和set方法被转义为hget和hset命令,从而使所有连接到同一个redis节点的客户端同时对一个指定对象操作。通过将这些值保存在一个像redis这样的远程共享的空间的过程,把这个对象强化成一个分布式对象。这个对象就叫RLO。
RLO使用方法:通过一系列注解@REntity(必选,类)、@RId(必选、主键字段)、@RIndex、@RObjectField、@RCascade(级联操作)
3、分布式执行服务:执行任务及取消任务
public class ExecutorServiceExamples {
public static class RunnableTask implements Runnable, Serializable {
@RInject
RedissonClient redisson;
@Override
public void run() {
RMap<String, String> map = redisson.getMap("myMap");
map.put("5", "11");
}
}
public static class CallableTask implements Callable<String>, Serializable {
@RInject
RedissonClient redisson;
@Override
public String call() throws Exception {
RMap<String, String> map = redisson.getMap("myMap");
map.put("1", "2");
return map.get("3");
}
}
public static void main(String[] args) {
Config config = new Config();
config.useClusterServers()
.addNodeAddress("127.0.0.1:7001", "127.0.0.1:7002", "127.0.0.1:7003");
RedissonClient redisson = Redisson.create(config);
RedissonNodeConfig nodeConfig = new RedissonNodeConfig(config);
nodeConfig.setExecutorServiceWorkers(Collections.singletonMap("myExecutor", 1));
RedissonNode node = RedissonNode.create(nodeConfig);
node.start();
RExecutorService e = redisson.getExecutorService("myExecutor");
e.execute(new RunnableTask());
e.submit(new CallableTask());
e.shutdown();
node.shutdown();
}
}
4、分布式调度任务服务:对计划任务的设定(可以通过CRON表达式)及去掉计划任务
public class SchedulerServiceExamples {
public static class RunnableTask implements Runnable, Serializable {
@RInject
RedissonClient redisson;
@Override
public void run() {
RMap<String, String> map = redisson.getMap("myMap");
map.put("5", "11");
}
}
public static class CallableTask implements Callable<String>, Serializable {
@RInject
RedissonClient redisson;
@Override
public String call() throws Exception {
RMap<String, String> map = redisson.getMap("myMap");
map.put("1", "2");
return map.get("3");
}
}
public static void main(String[] args) {
Config config = new Config();
config.useClusterServers()
.addNodeAddress("127.0.0.1:7001", "127.0.0.1:7002", "127.0.0.1:7003");
RedissonClient redisson = Redisson.create(config);
RedissonNodeConfig nodeConfig = new RedissonNodeConfig(config);
nodeConfig.setExecutorServiceWorkers(Collections.singletonMap("myExecutor", 5));
RedissonNode node = RedissonNode.create(nodeConfig);
node.start();
RScheduledExecutorService e = redisson.getExecutorService("myExecutor");
e.schedule(new RunnableTask(), 10, TimeUnit.SECONDS);
e.schedule(new CallableTask(), 4, TimeUnit.MINUTES);
e.schedule(new RunnableTask(), CronSchedule.of("10 0/5 * * * ?"));
e.schedule(new RunnableTask(), CronSchedule.dailyAtHourAndMinute(10, 5));
e.schedule(new RunnableTask(), CronSchedule.weeklyOnDayAndHourAndMinute(12, 4, Calendar.MONDAY, Calendar.FRIDAY));
e.shutdown();
node.shutdown();
}
}
5、分布式映射归纳服务:通过映射归纳处理存储在Redis环境里的大量数据。示例代码单词统计
参考文档:
redisson
总结:
Reddisson提供的都是分布式对象,用来操作redis集群。
操作的数据分布在集群之中
分布式锁可以解决redis缓存击穿问题