阅读redisson相关文档阅读redisson相关文档
This commit is contained in:
428
spring/redisson/redisson.md
Normal file
428
spring/redisson/redisson.md
Normal file
@@ -0,0 +1,428 @@
|
||||
# Redisson
|
||||
## 配置
|
||||
### 编程式配置
|
||||
可以通过创建Config对象来显式配置redisson,配置示例如下:
|
||||
```java
|
||||
Config config = new Config();
|
||||
config.setTransportMode(TransportMode.EPOLL);
|
||||
config.useClusterServers()
|
||||
// use "rediss://" for SSL connection
|
||||
.addNodeAddress("perredis://127.0.0.1:7181");
|
||||
|
||||
RedissonClient redisson = Redisson.create(config);
|
||||
```
|
||||
### yml Configuration
|
||||
也可以通过yml文件格式来对redisson进行配置:
|
||||
```java
|
||||
Config config = Config.fromYAML(new File("config-file.yaml"));
|
||||
RedissonClient redisson = Redisson.create(config);
|
||||
```
|
||||
可以通过config.toYAML方法将config转化为yaml格式:
|
||||
```java
|
||||
Config config = new Config();
|
||||
// ... many settings are set here
|
||||
String yamlFormat = config.toYAML();
|
||||
```
|
||||
yml格式中可以引入环境变量
|
||||
```yml
|
||||
singleServerConfig:
|
||||
address: "redis://127.0.0.1:${REDIS_PORT}"
|
||||
```
|
||||
### Common Settings
|
||||
如下设置用于配置config对象,并且适用于各种redis模式
|
||||
#### codec
|
||||
默认值:org.redisson.codec.Kryo5Codec
|
||||
#### connectionListener
|
||||
默认值:null
|
||||
connection listener,当redisson连接到redis-server或与redis-server断开连接时被触发
|
||||
#### nettyThreads
|
||||
默认值:32
|
||||
redisson所有redis client共享的线程总数。netty thread用于redis相应的解码和命令的发送。
|
||||
#### transportMode
|
||||
默认值:TransportMode.NIO
|
||||
可选的值如下:
|
||||
- TransportMode.NIO(默认)
|
||||
- TransportMode.EPOLL
|
||||
- TransportMode.KQUEUE
|
||||
#### threads
|
||||
由Rtopic object listener所共享的线程数量
|
||||
#### lockWatchdogTimeout
|
||||
默认值:30000
|
||||
RLock watchdog timeout,单位为ms。该参数仅当RLock在获取时没有指定leaseTimeout时使用。当watchdog没有延长持有锁时间到下一个watchdogTimeout间隔时,当前watchdogTimeout到期后锁会过期。watchdog避免了由于客户端崩溃或其他原因造成一直持有锁的情况。
|
||||
### Mode
|
||||
#### single instance mode
|
||||
可以通过如下方式来配置单实例模式:
|
||||
```java
|
||||
// connects to 127.0.0.1:6379 by default
|
||||
RedissonClient redisson = Redisson.create();
|
||||
|
||||
Config config = new Config();
|
||||
config.useSingleServer().setAddress("redis://myredisserver:6379");
|
||||
RedissonClient redisson = Redisson.create(config);
|
||||
```
|
||||
yml配置单实例模式如下:
|
||||
```yaml
|
||||
singleServerConfig:
|
||||
idleConnectionTimeout: 10000
|
||||
connectTimeout: 10000
|
||||
timeout: 3000
|
||||
retryAttempts: 3
|
||||
retryInterval: 1500
|
||||
password: null
|
||||
subscriptionsPerConnection: 5
|
||||
clientName: null
|
||||
address: "redis://127.0.0.1:6379"
|
||||
subscriptionConnectionMinimumIdleSize: 1
|
||||
subscriptionConnectionPoolSize: 50
|
||||
connectionMinimumIdleSize: 24
|
||||
connectionPoolSize: 64
|
||||
database: 0
|
||||
dnsMonitoringInterval: 5000
|
||||
threads: 16
|
||||
nettyThreads: 32
|
||||
codec: !<org.redisson.codec.Kryo5Codec> {}
|
||||
transportMode: "NIO"
|
||||
```
|
||||
## Operation Execution
|
||||
redisson支持自动重试策略,并且在每次尝试时都会发送命令。重试策略通过retryAttempts(默认情况下为3)、retryInterval(默认情况下为1000ms)来设置。多次尝试之间间隔retryInterval。
|
||||
redisson实例是线程安全的,如下是RAtomicLong对象的使用示例:
|
||||
```java
|
||||
RedissonClient client = Redisson.create(config);
|
||||
RAtomicLong longObject = client.getAtomicLong('myLong');
|
||||
// sync way
|
||||
longObject.compareAndSet(3, 401);
|
||||
// async way
|
||||
RFuture<Boolean> result = longObject.compareAndSetAsync(3, 401);
|
||||
|
||||
RedissonReactiveClient client = Redisson.createReactive(config);
|
||||
RAtomicLongReactive longObject = client.getAtomicLong('myLong');
|
||||
// reactive way
|
||||
Mono<Boolean> result = longObject.compareAndSet(3, 401);
|
||||
|
||||
RedissonRxClient client = Redisson.createRx(config);
|
||||
RAtomicLongRx longObject= client.getAtomicLong("myLong");
|
||||
// RxJava2 way
|
||||
Flowable<Boolean result = longObject.compareAndSet(3, 401);
|
||||
```
|
||||
### Async方式
|
||||
大多数redisson object继承了异步接口,可以调用异步方法实现异步操作,如下:
|
||||
```java
|
||||
// RAtomicLong extends RAtomicLongAsync
|
||||
RAtomicLongAsync longObject = client.getAtomicLong("myLong");
|
||||
RFuture<Boolean> future = longObject.compareAndSetAsync(1, 401);
|
||||
```
|
||||
RFuture对象继承了Future接口和CompletionStage接口,可以像CompleteableFuture一样使用:
|
||||
```java
|
||||
future.whenComplete((res, exception) -> {
|
||||
|
||||
// handle both result and exception
|
||||
|
||||
});
|
||||
|
||||
|
||||
// or
|
||||
future.thenAccept(res -> {
|
||||
|
||||
// handle result
|
||||
|
||||
}).exceptionally(exception -> {
|
||||
|
||||
// handle exception
|
||||
|
||||
});
|
||||
```
|
||||
因该避免在future listener中使用同步方法,这样可能会造成redis请求/相应处理时的错误,应使用如下方式执行:
|
||||
```java
|
||||
future.whenCompleteAsync((res, exception) -> {
|
||||
|
||||
// handle both result and exception
|
||||
|
||||
}, executor);
|
||||
|
||||
|
||||
// or
|
||||
future.thenAcceptAsync(res -> {
|
||||
|
||||
// handle result
|
||||
|
||||
}, executor).exceptionallyAsync(exception -> {
|
||||
|
||||
// handle exception
|
||||
|
||||
}, executor);
|
||||
```
|
||||
## Redisson Object的公共操作
|
||||
所有redisson object都实现了RObject和RExpiration接口,使用示例如下:
|
||||
```java
|
||||
RObject object = redisson.get...()
|
||||
|
||||
object.sizeInMemory();
|
||||
|
||||
object.delete();
|
||||
|
||||
object.rename("newname");
|
||||
|
||||
object.isExists();
|
||||
|
||||
// catch expired event
|
||||
object.addListener(new ExpiredObjectListener() {
|
||||
...
|
||||
});
|
||||
|
||||
// catch delete event
|
||||
object.addListener(new DeletedObjectListener() {
|
||||
...
|
||||
});
|
||||
```
|
||||
redisson object的name属性即是在redis中的key:
|
||||
```java
|
||||
RMap map = redisson.getMap("mymap");
|
||||
map.getName(); // = mymap
|
||||
```
|
||||
和redis key相关的所有操作都通过RKeys接口暴露,使用示例如下:
|
||||
```java
|
||||
RKeys keys = redisson.getKeys();
|
||||
|
||||
Iterable<String> allKeys = keys.getKeys();
|
||||
|
||||
Iterable<String> foundedKeys = keys.getKeysByPattern('key*');
|
||||
|
||||
long numOfDeletedKeys = keys.delete("obj1", "obj2", "obj3");
|
||||
|
||||
long deletedKeysAmount = keys.deleteByPattern("test?");
|
||||
|
||||
String randomKey = keys.randomKey();
|
||||
|
||||
long keysAmount = keys.count();
|
||||
|
||||
keys.flushall();
|
||||
|
||||
keys.flushdb();
|
||||
```
|
||||
## 分布式对象
|
||||
### object holder
|
||||
#### RBucket
|
||||
RBucket的java实现类是一个hodler,可以持有任何类型的java对象。RBucket的大小限制为512MB.
|
||||
RBucket的使用示例如下所示:
|
||||
```java
|
||||
RBucket<AnyObject> bucket = redisson.getBucket("anyObject");
|
||||
|
||||
bucket.set(new AnyObject(1));
|
||||
AnyObject obj = bucket.get();
|
||||
|
||||
bucket.trySet(new AnyObject(3));
|
||||
bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
|
||||
bucket.getAndSet(new AnyObject(6));
|
||||
```
|
||||
#### RBuckets
|
||||
可以通过RBuckets对象来操作多个RBucket对象,RBuckets使用示例如下:
|
||||
```java
|
||||
RBuckets buckets = redisson.getBuckets();
|
||||
|
||||
// get all bucket values
|
||||
Map<String, V> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("myBucket1", new MyObject());
|
||||
map.put("myBucket2", new MyObject());
|
||||
|
||||
// sets all or nothing if some bucket is already exists
|
||||
buckets.trySet(map);
|
||||
// store all at once
|
||||
buckets.set(map);
|
||||
```
|
||||
### Binary Stream Holder
|
||||
RBinaryStream类型的对象用于存储字节序列。RBinaryStream实现了RBucket接口,并且其大小限制也是512MB.
|
||||
RBinaryStream的使用示例如下:
|
||||
```java
|
||||
RBinaryStream stream = redisson.getBinaryStream("anyStream");
|
||||
|
||||
byte[] content = ...
|
||||
stream.set(content);
|
||||
stream.getAndSet(content);
|
||||
stream.trySet(content);
|
||||
stream.compareAndSet(oldContent, content);
|
||||
```
|
||||
RBinaryStream可以和InputStream与OutputStream混用,使用如下:
|
||||
```java
|
||||
RBinaryStream stream = redisson.getBinaryStream("anyStream");
|
||||
|
||||
InputStream is = stream.getInputStream();
|
||||
byte[] readBuffer = ...
|
||||
is.read(readBuffer);
|
||||
|
||||
OutputStream os = stream.getOuputStream();
|
||||
byte[] contentToWrite = ...
|
||||
os.write(contentToWrite);
|
||||
```
|
||||
### BitSet
|
||||
RBitSet实现提供了和java中BitSet类似的api,其大小限制是4 294 967 295 bits.
|
||||
RBitSet使用如下所示:
|
||||
```java
|
||||
RBitSet set = redisson.getBitSet("simpleBitset");
|
||||
|
||||
set.set(0, true);
|
||||
set.set(1812, false);
|
||||
|
||||
set.clear(0);
|
||||
|
||||
set.and("anotherBitset");
|
||||
set.xor("anotherBitset");
|
||||
```
|
||||
### AtomicLong
|
||||
RAtomicLong实现提供了和java中AtomicLong类似的api,其使用类似如下:
|
||||
```java
|
||||
RAtomicLong atomicLong = redisson.getAtomicLong("myAtomicLong");
|
||||
atomicLong.set(3);
|
||||
atomicLong.incrementAndGet();
|
||||
atomicLong.get();
|
||||
```
|
||||
### AtomicDouble
|
||||
RAtomicDouble实现提供了和java中AtomicDouble类似的api,其使用示例如下:
|
||||
```java
|
||||
RAtomicDouble atomicDouble = redisson.getAtomicDouble("myAtomicDouble");
|
||||
atomicDouble.set(2.81);
|
||||
atomicDouble.addAndGet(4.11);
|
||||
atomicDouble.get();
|
||||
```
|
||||
### Topic
|
||||
RTopic实现提供了发布/订阅机制,其允许订阅由同名RTopic对象发布的事件。
|
||||
当重新连接到redis或redis错误切换之后,listener会被重新订阅,在重新订阅之前,所有被发布的消息都会丢失。
|
||||
RTopic的使用如下所示:
|
||||
```java
|
||||
RTopic topic = redisson.getTopic("myTopic");
|
||||
int listenerId = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
|
||||
@Override
|
||||
public void onMessage(String channel, SomeObject message) {
|
||||
//...
|
||||
}
|
||||
});
|
||||
|
||||
// in other thread or JVM
|
||||
RTopic topic = redisson.getTopic("myTopic");
|
||||
long clientsReceivedMessage = topic.publish(new SomeObject());
|
||||
```
|
||||
### Reliable Topic
|
||||
RRelieableTopic在实现发布/订阅模式的情况下,还实现了消息的可靠传输。当redis连接断开的情况下,所有消息都会被存储,当重新连接到redis时,消息会被重新传送。
|
||||
每个RReliableTopic对象实例都由一个watchdog,当第一个listener注册之后,watchdog就会被启用。当订阅者超过reliableTopicWatchdogTimeout之后,且watchdog没有为其延续过期时间,那么订阅将会超时。(该机制是为了防止client长时间崩溃之后存储的消息持续增长)。
|
||||
**当重新连接到redis之后,listener会被重新注册**
|
||||
```java
|
||||
RReliableTopic topic = redisson.getReliableTopic("anyTopic");
|
||||
topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
|
||||
@Override
|
||||
public void onMessage(CharSequence channel, SomeObject message) {
|
||||
//...
|
||||
}
|
||||
});
|
||||
|
||||
// in other thread or JVM
|
||||
RReliableTopic topic = redisson.getReliableTopic("anyTopic");
|
||||
long subscribersReceivedMessage = topic.publish(new SomeObject());
|
||||
```
|
||||
|
||||
### Topic Pattern
|
||||
RPatternTopic允许订阅多个Rtopic,在重新连接到redis或redis错误切换之后,listener会被重新订阅。
|
||||
Pattern使用如下:
|
||||
- topic?: subscribes to topic1, topicA ...
|
||||
- topic?_my: subscribes to topic_my, topic123_my, topicTEST_my ...
|
||||
- topic[ae]: subscribes to topica and topice only
|
||||
|
||||
使用示例如下:
|
||||
```java
|
||||
// subscribe to all topics by `topic*` pattern
|
||||
RPatternTopic patternTopic = redisson.getPatternTopic("topic*");
|
||||
int listenerId = patternTopic.addListener(Message.class, new PatternMessageListener<Message>() {
|
||||
@Override
|
||||
public void onMessage(String pattern, String channel, Message msg) {
|
||||
//...
|
||||
}
|
||||
});
|
||||
```
|
||||
### Bloom Filter
|
||||
RBloomFilter中最多含有2^32个bit。
|
||||
在使用之前,必须通过tryInit(expectedInsertions, falseProbability)来初始化capacity。
|
||||
RBloomFilter使用示例如下:
|
||||
```java
|
||||
RBloomFilter<SomeObject> bloomFilter = redisson.getBloomFilter("sample");
|
||||
// initialize bloom filter with
|
||||
// expectedInsertions = 55000000
|
||||
// falseProbability = 0.03
|
||||
bloomFilter.tryInit(55000000L, 0.03);
|
||||
|
||||
bloomFilter.add(new SomeObject("field1Value", "field2Value"));
|
||||
bloomFilter.add(new SomeObject("field5Value", "field8Value"));
|
||||
|
||||
bloomFilter.contains(new SomeObject("field1Value", "field8Value"));
|
||||
bloomFilter.count();
|
||||
```
|
||||
### HyperLogLog
|
||||
RHyperLogLog能以较低的空间维护大数量的项目,计算其去重后的数量,其使用如下所示:
|
||||
```java
|
||||
RHyperLogLog<Integer> log = redisson.getHyperLogLog("log");
|
||||
log.add(1);
|
||||
log.add(2);
|
||||
log.add(3);
|
||||
|
||||
log.count();
|
||||
```
|
||||
### LongAdder
|
||||
RLongAdder提供了java中LongAdder的实现,其在client端维护了LongAdder,增加和减少的性能较AtomicLong来说都有极大的提升(至多可提升12000倍)。其使用如下所示:
|
||||
```java
|
||||
RLongAdder atomicLong = redisson.getLongAdder("myLongAdder");
|
||||
atomicLong.add(12);
|
||||
atomicLong.increment();
|
||||
atomicLong.decrement();
|
||||
atomicLong.sum();
|
||||
```
|
||||
当LongAdder不再使用之后,应该调用destroy方法手动进行销毁:
|
||||
```java
|
||||
RLongAdder atomicLong = ...
|
||||
atomicLong.destroy();
|
||||
```
|
||||
### DoubleAdder
|
||||
RDoubleAdder提供了java中DoubleAdder的分布式实现,其性能相对于AtomicDouble也有很大提升。
|
||||
其使用如下所示:
|
||||
```java
|
||||
RLongDouble atomicDouble = redisson.getLongDouble("myLongDouble");
|
||||
atomicDouble.add(12);
|
||||
atomicDouble.increment();
|
||||
atomicDouble.decrement();
|
||||
atomicDouble.sum();
|
||||
```
|
||||
### id generator
|
||||
RIdGenerator实现允许产生唯一的id,但其生成算法不是简单的递增,而是在第一次请求时,一系列id就已经被分配并且缓存到java端,直到其用完。该方法能够减少和redis的通信次数,产生id的速率比RAtomicLong快。
|
||||
默认情况下allocate size是2000,并且值从0开始。
|
||||
RIdGenerator的使用如下所示:
|
||||
```java
|
||||
RIdGenerator generator = redisson.getIdGenerator("generator");
|
||||
|
||||
// Initialize with start value = 12 and allocation size = 20000
|
||||
generator.tryInit(12, 20000);
|
||||
|
||||
long id = generator.nextId();
|
||||
```
|
||||
### Json Object Holder
|
||||
RJsonBucket类型用于存储json数据,通过redis 的JSON.*命令来实现。Json数据通过JsonCodec来进行编码和解码。可用的实现是org.redisson.codec.JacksonCodec。
|
||||
#### local cache
|
||||
redisson提供了带有本地缓存的json object holder版本。
|
||||
local cache用于加速读取操作从而较少网络请求次数,其将整个json对象缓存在redisson侧,执行读取操作比无缓存快45倍。
|
||||
| redission client method name | local cache | Ultra-fast read/write |
|
||||
| :-: | :-: | :-: |
|
||||
| getJsonBucket() open-source version | false | false |
|
||||
| getJsonBucket() Redisson PRO version | false | true |
|
||||
| getLocalCachedJsonBucket() Redisson PRO version | true | true |
|
||||
|
||||
RJsonBucket使用如下所示:
|
||||
```java
|
||||
RJsonBucket<AnyObject> bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
|
||||
|
||||
bucket.set(new AnyObject(1));
|
||||
AnyObject obj = bucket.get();
|
||||
|
||||
bucket.trySet(new AnyObject(3));
|
||||
bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
|
||||
bucket.getAndSet(new AnyObject(6));
|
||||
|
||||
List<String> values = bucket.get(new JacksonCodec<>(new TypeReference<List<String>>() {}), "values");
|
||||
long aa = bucket.arrayAppend("$.obj.values", "t3", "t4");
|
||||
```
|
||||
Reference in New Issue
Block a user