From 36a255098282fa2c26051ffec0d1d148816aecef Mon Sep 17 00:00:00 2001 From: Rikako Wu <496063163@qq.com> Date: Wed, 8 Feb 2023 12:35:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90redisson=E5=88=86=E5=B8=83?= =?UTF-8?q?=E5=BC=8F=E9=94=81=E6=96=87=E6=A1=A3=E7=9A=84=E9=98=85=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring/redisson/redisson.md | 377 +++++++++++++++++++++++++++++++++++- 1 file changed, 376 insertions(+), 1 deletion(-) diff --git a/spring/redisson/redisson.md b/spring/redisson/redisson.md index 01cb68e..8f441c8 100644 --- a/spring/redisson/redisson.md +++ b/spring/redisson/redisson.md @@ -1,3 +1,87 @@ +- [Redisson](#redisson) + - [配置](#配置) + - [编程式配置](#编程式配置) + - [yml Configuration](#yml-configuration) + - [Common Settings](#common-settings) + - [codec](#codec) + - [connectionListener](#connectionlistener) + - [nettyThreads](#nettythreads) + - [transportMode](#transportmode) + - [threads](#threads) + - [lockWatchdogTimeout](#lockwatchdogtimeout) + - [Mode](#mode) + - [single instance mode](#single-instance-mode) + - [Operation Execution](#operation-execution) + - [Async方式](#async方式) + - [Redisson Object的公共操作](#redisson-object的公共操作) + - [分布式对象](#分布式对象) + - [object holder](#object-holder) + - [RBucket](#rbucket) + - [RBuckets](#rbuckets) + - [Binary Stream Holder](#binary-stream-holder) + - [BitSet](#bitset) + - [AtomicLong](#atomiclong) + - [AtomicDouble](#atomicdouble) + - [Topic](#topic) + - [Reliable Topic](#reliable-topic) + - [Topic Pattern](#topic-pattern) + - [Bloom Filter](#bloom-filter) + - [HyperLogLog](#hyperloglog) + - [LongAdder](#longadder) + - [DoubleAdder](#doubleadder) + - [id generator](#id-generator) + - [Json Object Holder](#json-object-holder) + - [local cache](#local-cache) + - [分布式集合](#分布式集合) + - [Map](#map) + - [eviction](#eviction) + - [local cache](#local-cache-1) + - [Map Persistence](#map-persistence) + - [read-through策略](#read-through策略) + - [write-through(sync)策略](#write-throughsync策略) + - [write-behind策略(async)](#write-behind策略async) + - [Map Listener](#map-listener) + - [LRU/LFU bounded Map](#lrulfu-bounded-map) + - [MultiMap](#multimap) + - [Set based MultiMap](#set-based-multimap) + - [List based MultiMap](#list-based-multimap) + - [MultiMap eviction](#multimap-eviction) + - [Set](#set) + - [eviction](#eviction-1) + - [SortedSet](#sortedset) + - [ScoredSortedSet](#scoredsortedset) + - [LexSortedSet](#lexsortedset) + - [List](#list) + - [Queue](#queue) + - [Deque](#deque) + - [Blocking Queue](#blocking-queue) + - [Bounded Blocking Queue](#bounded-blocking-queue) + - [Blocking Deque](#blocking-deque) + - [Blocking Fair Queue](#blocking-fair-queue) + - [Blocking Fair Deque](#blocking-fair-deque) + - [DelayedQueue](#delayedqueue) + - [PriorityQueue](#priorityqueue) + - [PriorityDeque](#prioritydeque) + - [PriorityBlockingQueue](#priorityblockingqueue) + - [PriorityBlockingDeque](#priorityblockingdeque) + - [Stream](#stream) + - [RingBuffer](#ringbuffer) + - [Transfer Queue](#transfer-queue) + - [Time Series](#time-series) + - [分布式锁和synchronizer](#分布式锁和synchronizer) + - [Lock](#lock) + - [Fair Lock](#fair-lock) + - [MultiLock](#multilock) + - [ReadWriteLock](#readwritelock) + - [Semaphore](#semaphore) + - [PermitExpirableSemaphore](#permitexpirablesemaphore) + - [CountDownLatch](#countdownlatch) + - [SpinLock](#spinlock) + - [FencedLock](#fencedlock) + - [Redisson整合Spring Cache](#redisson整合spring-cache) + - [spring cache yaml config](#spring-cache-yaml-config) + + # Redisson ## 配置 ### 编程式配置 @@ -1211,4 +1295,295 @@ ts.remove(201908110508); Collection values = ts.pollFirst(2); Collection range = ts.range(201908110501, 201908110508); -``` \ No newline at end of file +``` +## 分布式锁和synchronizer +### Lock +基于Redis的分布式ReentrantLock对象实现了java中的Lock接口。 +为了防止redisson再获取锁之后崩溃导致永远持有锁,redisson维护了watchdog,当持有锁的redisson实例处于活跃状态时,其会延长锁的时间。默认情况下,redisson的超时时间为30s。 +在获取锁时可以指定leaseTime,在经过指定时间后锁定的lock会自动被释放。 +> RLock的行为符合java lock规范,意味着只有锁的持有线程才能对锁进行解锁,否则会抛出IllegalMonitorStateException异常。 +> 如果想要多个线程对锁资源进行操作,可以考虑使用RSemaphore +RLock的使用示例如下: +```java +RLock lock = redisson.getLock("myLock"); + +// traditional lock method +lock.lock(); + +// or acquire lock and automatically unlock it after 10 seconds +lock.lock(10, TimeUnit.SECONDS); + +// or wait for lock aquisition up to 100 seconds +// and automatically unlock it after 10 seconds +boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS); +if (res) { + try { + ... + } finally { + lock.unlock(); + } +} +``` +### Fair Lock +fair lock会保证所有线程按请求锁的顺序获取锁,所有等待的线程会被排队,如果有线程died,那么redisson会等5s来等待其返回。 +fair lock使用如下所示: +```java +RLock lock = redisson.getFairLock("myLock"); + +// traditional lock method +lock.lock(); + +// or acquire lock and automatically unlock it after 10 seconds +lock.lock(10, TimeUnit.SECONDS); + +// or wait for lock aquisition up to 100 seconds +// and automatically unlock it after 10 seconds +boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS); +if (res) { + try { + ... + } finally { + lock.unlock(); + } +} +``` +### MultiLock +MultiLock允许对多个锁资源同时执行操作,将多个锁资源视作单个锁资源。 +MultiLock使用示例如下所示: +```java +RLock lock1 = redisson1.getLock("lock1"); +RLock lock2 = redisson2.getLock("lock2"); +RLock lock3 = redisson3.getLock("lock3"); + +RLock multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3); + +// traditional lock method +multiLock.lock(); + +// or acquire lock and automatically unlock it after 10 seconds +multiLock.lock(10, TimeUnit.SECONDS); + +// or wait for lock aquisition up to 100 seconds +// and automatically unlock it after 10 seconds +boolean res = multiLock.tryLock(100, 10, TimeUnit.SECONDS); +if (res) { + try { + ... + } finally { + multiLock.unlock(); + } +} +``` +### ReadWriteLock +基于Redis的ReadWriteLock实现了java中的ReadWriteLock接口,readlock允许有多个owner,writelock只允许有一个owner。 +ReadWriteLock的使用示例如下所示: +```java +RReadWriteLock rwlock = redisson.getReadWriteLock("myLock"); + +RLock lock = rwlock.readLock(); +// or +RLock lock = rwlock.writeLock(); + +// traditional lock method +lock.lock(); + +// or acquire lock and automatically unlock it after 10 seconds +lock.lock(10, TimeUnit.SECONDS); + +// or wait for lock aquisition up to 100 seconds +// and automatically unlock it after 10 seconds +boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS); +if (res) { + try { + ... + } finally { + lock.unlock(); + } +} +``` +### Semaphore +基于Redis的Semaphore和java中的Semaphore类似,可以在使用之前进行初始化,但是初始化不是必须的,可以通过trySetPermits方法初始化permit的数量。 +semaphore使用示例如下所示: +```java +RSemaphore semaphore = redisson.getSemaphore("mySemaphore"); + +// acquire single permit +semaphore.acquire(); + +// or acquire 10 permits +semaphore.acquire(10); + +// or try to acquire permit +boolean res = semaphore.tryAcquire(); + +// or try to acquire permit or wait up to 15 seconds +boolean res = semaphore.tryAcquire(15, TimeUnit.SECONDS); + +// or try to acquire 10 permit +boolean res = semaphore.tryAcquire(10); + +// or try to acquire 10 permits or wait up to 15 seconds +boolean res = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS); +if (res) { + try { + ... + } finally { + semaphore.release(); + } +} +``` +### PermitExpirableSemaphore +基于redis的分布式Semaphore对象,其支持在通过acquire获取信号量时添加lease time参数。 +对于带lease time的permit,每个permit都通过id标识,并且释放操作也是通过id释放。 +允许通过addPermits方法增加或减少permits数量。 +```java +RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore"); + +semaphore.trySetPermits(23); + +// acquire permit +String id = semaphore.acquire(); + +// or acquire permit with lease time in 10 seconds +String id = semaphore.acquire(10, TimeUnit.SECONDS); + +// or try to acquire permit +String id = semaphore.tryAcquire(); + +// or try to acquire permit or wait up to 15 seconds +String id = semaphore.tryAcquire(15, TimeUnit.SECONDS); + +// or try to acquire permit with least time 15 seconds or wait up to 10 seconds +String id = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS); +if (id != null) { + try { + ... + } finally { + semaphore.release(id); + } +} +``` +### CountDownLatch +基于Redis的分布式CountDownLatch对象和java中的CountDownLatch对象类似,在使用之前,应该通过trySetCount来进行初始化。 +CountDownLatch的使用示例如下所示: +```java +RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch"); + +latch.trySetCount(1); +// await for count down +latch.await(); + +// in other thread or JVM +RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch"); +latch.countDown(); +``` +### SpinLock +由于分布式锁是采用的pub/sub机制,故而当短时间内获取或释放大量的锁时,消息会通过pub/sub channel发送到redis集群中所有的节点。 +可以通过backoff策略来自旋尝试,从而代替pub/sub channel发送时间,这样可以降低redis集群的网络和cpu负载。 +```java +RLock lock = redisson.getSpinLock("myLock"); + +// traditional lock method +lock.lock(); + +// or acquire lock and automatically unlock it after 10 seconds +lock.lock(10, TimeUnit.SECONDS); + +// or wait for lock aquisition up to 100 seconds +// and automatically unlock it after 10 seconds +boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS); +if (res) { + try { + ... + } finally { + lock.unlock(); + } +} +``` +### FencedLock +FencedLock使用如下所示: +```java +RFencedLock lock = redisson.getFencedLock("myLock"); + +// traditional lock method +Long token = lock.lockAndGetToken(); + +// or acquire lock and automatically unlock it after 10 seconds +token = lock.lockAndGetToken(10, TimeUnit.SECONDS); + +// or wait for lock aquisition up to 100 seconds +// and automatically unlock it after 10 seconds +Long token = lock.tryLockAndGetToken(100, 10, TimeUnit.SECONDS); +if (token != null) { + try { + // check if token >= old token + ... + } finally { + lock.unlock(); + } +} +``` +## Redisson整合Spring Cache +Redisson提供了基于redis的spring cache实现,每个cache实例都有ttl和maxIdleTime两个参数,配置如下所示: +```java +@Configuration + @ComponentScan + @EnableCaching + public static class Application { + + @Bean(destroyMethod="shutdown") + RedissonClient redisson() throws IOException { + Config config = new Config(); + config.useClusterServers() + .addNodeAddress("redis://127.0.0.1:7004", "redis://127.0.0.1:7001"); + return Redisson.create(config); + } + + @Bean + CacheManager cacheManager(RedissonClient redissonClient) { + Map config = new HashMap(); + + // create "testMap" cache with ttl = 24 minutes and maxIdleTime = 12 minutes + config.put("testMap", new CacheConfig(24*60*1000, 12*60*1000)); + return new RedissonSpringCacheManager(redissonClient, config); + } + + } +``` +cache配置也能从yaml文件中进行读取,示例如下: +```java + @Configuration + @ComponentScan + @EnableCaching + public static class Application { + + @Bean(destroyMethod="shutdown") + RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException { + Config config = Config.fromYAML(configFile.getInputStream()); + return Redisson.create(config); + } + + @Bean + CacheManager cacheManager(RedissonClient redissonClient) throws IOException { + return new RedissonSpringCacheManager(redissonClient, "classpath:/cache-config.yaml"); + } + + } +``` +### spring cache yaml config +如下是通过yaml的格式来配置spring cache: +```java +testMap: + ttl: 1440000 + maxIdleTime: 720000 + localCacheOptions: + invalidationPolicy: "ON_CHANGE" + evictionPolicy: "NONE" + cacheSize: 0 + timeToLiveInMillis: 0 + maxIdleInMillis: 0 +``` + + + +