使用Redisson的Redis的指南
1.概述
Redisson是一个Java的Redis客户端。在这篇文章中,我们将探讨它的一些功能,并演示它如何促进构建分布式商业应用。
Redisson构成了一个内存数据网格,它提供了由Redis支持的分布式Java对象和服务。它的分布式内存数据模型允许跨应用程序和服务器共享领域对象和服务。
在这篇文章中,我们将看到设置Redisson的热度,了解它是如何运作的,并探索Redisson的一些对象和服务。
2.Maven的依赖性
让我们开始吧,将Redisson导入我们的项目,在我们的pom.xml中加入下面的部分:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.1</version>
</dependency>
该依赖性的最新版本可以在这里找到。
3.配置
在我们开始之前,我们必须确保我们有最新版本的Redis的设置和运行。如果你没有Redis,而且你使用Linux或Macintosh,你可以按照信息这里来设置它。如果你是一个Windows用户,你可以使用这个非官方的端口来设置Redis。
我们需要配置Redisson以连接到Redis。Redisson支持与下列Redis配置的连接:
- 单节点
- 主从节点
- 哨兵结节
- 集群节点
- 复制节点
Redisson支持亚马逊网络服务(AWS)的ElastiCache Cluster和Azure Redis Cache,用于集群和复制节点。
让我们连接到Redis的一个单节点实例。这个实例在本地运行,默认端口为6379:
RedissonClient client = Redisson.create();
你可以向Redisson对象的create方法传递不同的配置。这可能是让它连接到不同的端口的配置,或者是连接到Redis集群的配置。这个配置可以在Java代码中,或者从外部配置文件中加载。
3.1.Java配置
让我们在Java代码中配置Redisson吧:
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
RedissonClient client = Redisson.create(config);
我们在一个Config对象的实例中指定Redisson的配置,然后将其传递给create方法。上面,我们向Redisson指定我们要连接到Redis的单节点实例。为了做到这一点,我们使用了Config对象的useSingleServer方法。这将返回一个指向SingleServerConfig 对象的引用。
SingleServerConfig 对象有Redisson用来连接到Redis单节点实例的设置。这里,我们使用它的setAddress方法来配置address设置。这设置了我们要连接的节点的地址。其他一些设置包括retryAttempts、connectionTimeout和clientName。这些设置是使用它们相应的setter方法配置的。
我们可以使用Config对象的以下方法,以类似的方式为不同的Redis配置Redisson:
- useSingleServer – 用于单节点实例。在此处获取单节点设置
- useMasterSlaveServers – 用于主节点和从节点。在这里获取主从节点设置
- useSentinelServers – 用于哨兵节点。在此处获取哨兵节点设置
- useClusterServers – 用于集群节点。在此处获取集群节点设置
- useReplicatedServers –为复制的节点。在此处获取复制节点设置
3.2.文件配置
Redisson可以从外部的JSON或YAML文件中加载配置:
Config config = Config.fromJSON(new File("singleNodeConfig.json"));
RedissonClient client = Redisson.create(config);
Config object的fromJSON 方法可以从字符串、文件、输入流或URL中加载配置。
这里是singleNodeConfig.json文件中的配置样本:
{
"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": 10,
"connectionPoolSize": 64,
"database": 0,
"dnsMonitoringInterval": 5000
},
"threads": 0,
"nettyThreads": 0,
"codec": null
}
这是一个相应的 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: 10
connectionPoolSize: 64
database: 0
dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
我们可以用类似的方式从文件中配置其他Redis配置,使用该配置特有的设置。供你参考,这里是它们的JSON和YAML文件格式:
要将Java配置保存为JSON或YAML格式,我们可以使用Config对象的toJSON或toYAML方法:
Config config = new Config();
// ... we configure multiple settings here in Java
String jsonFormat = config.toJSON();
String yamlFormat = config.toYAML();
现在我们知道了如何配置Redisson,让我们看看Redisson是如何执行操作的。
4.操作
Redisson支持同步、异步和反应式接口。对这些接口的操作是线程安全的。
由RedissonClient生成的所有实体(对象、集合、锁和服务)都有同步和异步方法。同步方法有异步变体。这些方法的名称通常与它们的同步变体相同,并附加了“Async”。让我们看看RAtomicLong对象的一个同步方法:
RedissonClient client = Redisson.create();
RAtomicLong myLong = client.getAtomicLong('myLong');
同步compareAndSet方法的异步变体将是:
RFuture<Boolean> isSet = myLong.compareAndSetAsync(6, 27);
该方法的异步变量返回一个RFuture对象。我们可以在这个对象上设置监听器,以便在结果可用时取回它:
isSet.handle((result, exception) -> {
// handle the result or exception here.
});
为了生成反应式对象,我们将需要使用RedissonReactiveClient:
RedissonReactiveClient client = Redisson.createReactive();
RAtomicLongReactive myLong = client.getAtomicLong("myLong");
Publisher<Boolean> isSetPublisher = myLong.compareAndSet(5, 28);
该方法基于Java 9的Reactive Streams,返回反应式对象。
让我们来探讨一下Redisson提供的一些分布式对象。
5.对象
Redisson对象的单个实例被序列化并存储在支持Redisson的任何可用Redis节点中。这些对象可以分布在多个节点的集群中,可以由一个应用程序或多个应用程序/服务器访问。
这些分布式对象遵循java.util.concurrent.atomic 包的规范。它们支持对存储在Redis的对象进行无锁、线程安全和原子操作。应用程序/服务器之间的数据一致性得到了保证,因为当另一个应用程序正在读取该对象时,值不会被更新。
Redisson对象被绑定到Redis键。我们可以通过RKeys 接口来管理这些键。然后,我们使用这些键访问我们的Redisson对象。
我们有几个选项可以用来获取Redis的密钥。
我们可以简单地拿到所有的密钥:
RKeys keys = client.getKeys();
另外,我们也可以只提取名字:
Iterable<String> allKeys = keys.getKeys();
最后,我们能够获得符合模式的键:
Iterable<String> keysByPattern = keys.getKeysByPattern('key*')
RKeys接口还允许删除键,按模式删除键,以及其他有用的基于键的操作,我们可以用这些操作来管理我们的键和对象。
由Redisson提供的分布式对象包括:
- ObjectHolder
- BinaryStreamHolder
- GeospatialHolder
- BitSet
- AtomicLong
- AtomicDouble
- Topic
- BloomFilter
- HyperLogLog
让我们来看看其中的三个对象:ObjectHolder, AtomicLong, 和 Topic. 。
5.1. Object Holder
由 RBucket 类表示,此对象可以容纳任何类型的对象。此对象的最大大小为 512MB:
RBucket<Ledger> bucket = client.getBucket("ledger");
bucket.set(new Ledger());
Ledger ledger = bucket.get();
RBucket对象可以对其持有的对象进行原子操作,如compareAndSet和getAndSet等。
5.2. AtomicLong
这个对象由RAtomicLong类表示,它与java.util.concurrent.atomic.AtomicLong类非常相似,表示一个可以原子化更新的long值:
RAtomicLong atomicLong = client.getAtomicLong("myAtomicLong");
atomicLong.set(5);
atomicLong.incrementAndGet();
5.3. Topic
Topic对象支持Redis的“发布和订阅”机制。要监听发布的消息:
RTopic subscribeTopic = client.getTopic("baeldung");
subscribeTopic.addListener(CustomMessage.class,
(channel, customMessage) -> future.complete(customMessage.getMessage()));
上面,Topic被注册来监听来自“baeldung”频道的消息。然后我们给频道添加一个监听器,以处理来自该频道的传入消息。我们可以为一个频道添加多个监听器。
让我们把信息发布到“baeldung”频道:
RTopic publishTopic = client.getTopic("baeldung");
long clientsReceivedMessage
= publishTopic.publish(new CustomMessage("This is a message"));
这可能是由另一个应用程序或服务器发布的。CustomMessage对象将被监听器接收,并按照onMessage方法中的定义进行处理。
我们可以在这里了解更多关于其他Redisson对象的信息。
6.集合
我们以处理对象的方式来处理Redisson的集合。
由Redisson提供的分布式集合包括:
- Map
- Multimap
- Set
- SortedSet
- ScoredSortedSet
- LexSortedSet
- List
- Queue
- Deque
- BlockingQueue
- BoundedBlockingQueue
- BlockingDeque
- BlockingFairQueue
- DelayedQueue
- PriorityQueue
- PriorityDeque
让我们看一下其中的三个集合:Map, Set, 和 List.。
6.1. Map
基于Redisson的Map实现了java.util.concurrent.ConcurrentMap 和java.util.Map接口。Redisson有四个Map实现。它们是RMap、RMapCache、RLocalCachedMap和RClusteredMap。
让我们用Redisson创建一张Map吧:
RMap<String, Ledger> map = client.getMap("ledger");
Ledger newLedger = map.put("123", new Ledger());map
RMapCache支持Map条目逐出。RLocalCachedMap允许对Map条目进行本地缓存。RClusteredMap允许单个Map的数据在Redis集群主节点之间分割。
我们可以在这里了解更多关于Redisson Map的信息。
6.2. Set
基于Redisson的Set实现了java.util.Set接口。
Redisson有三个Set的实现,RSet、RSetCache和RClusteredSet,其功能与对应的Map类似。
让我们用Redisson创建一个Set吧:
RSet<Ledger> ledgerSet = client.getSet("ledgerSet");
ledgerSet.add(new Ledger());
我们可以在这里了解更多关于Redisson Set的信息。
6.3. List
基于Redisson的List实现了java.util.List接口。
让我们用Redisson创建一个List吧:
RList<Ledger> ledgerList = client.getList("ledgerList");
ledgerList.add(new Ledger());
我们可以在这里了解更多关于其他Redisson集合的信息。
7.锁和同步器
Redisson的分布式锁允许跨应用程序/服务器进行线程同步。Redisson的锁和同步器列表包括:
- Lock
- FairLock
- MultiLock
- ReadWriteLock
- Semaphore
- PermitExpirableSemaphore
- CountDownLatch
让我们看看Lock和MultiLock.的情况。
7.1. Lock
Redisson的Lock实现了java.util.concurrent.locks.Lock接口。
让我们来实现一个锁,由RLock类来代表:
RLock lock = client.getLock("lock");
lock.lock();
// perform some long operations...
lock.unlock();
7.2. MultiLock
Redisson的RedissonMultiLock将多个RLock对象分组,并将其作为一个单一的锁来处理:
RLock lock1 = clientInstance1.getLock("lock1");
RLock lock2 = clientInstance2.getLock("lock2");
RLock lock3 = clientInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
lock.lock();
// perform long running operation...
lock.unlock();
我们可以在这里了解更多关于其他锁具的信息。
8.服务
Redisson暴露了4种类型的分布式服务。这些服务是:远程服务,实时对象服务,执行者服务和预定执行者服务。让我们来看看远程服务和实时对象服务。
8.1.远程服务
该服务提供由Redis促进的Java远程方法调用。Redisson远程服务由服务器端(工作者实例)和客户端的实现组成。服务器端的实现执行由客户端调用的远程方法。远程服务的调用可以是同步或异步的。
服务器端注册了一个用于远程调用的接口:
RRemoteService remoteService = client.getRemoteService();
LedgerServiceImpl ledgerServiceImpl = new LedgerServiceImpl();
remoteService.register(LedgerServiceInterface.class, ledgerServiceImpl);
客户端调用已注册的远程接口的一个方法:
RRemoteService remoteService = client.getRemoteService();
LedgerServiceInterface ledgerService
= remoteService.get(LedgerServiceInterface.class);
List<String> entries = ledgerService.getEntries(10);
我们可以在这里了解更多关于远程服务的信息。
8.2.实时对象服务
Redisson Live Objects将只能从单个JVM访问的标准Java对象的概念扩展为可在不同机器的不同JVM之间共享的增强型Java对象。这是通过将一个对象的字段映射到Redis哈希上实现的。这种映射是通过运行时构建的代理类进行的。字段的获取器和设置器被映射到Redis的hget/hset命令。
由于Redis的单线程特性,Redisson Live Objects支持原子字段的访问。
创建一个真实对象是很简单的:
@REntity
public class LedgerLiveObject {
@RId
private String name;
// getters and setters...
}
我们用@REntity来注解我们的类,用@RId来注解一个独特的或可识别的字段。一旦我们完成了这些,我们就可以在我们的应用程序中使用我们的Live对象:
RLiveObjectService service = client.getLiveObjectService();
LedgerLiveObject ledger = new LedgerLiveObject();
ledger.setName("ledger1");
ledger = service.persist(ledger);
我们使用new 关键字像标准Java对象一样创建我们的Live对象。然后我们使用RLiveObjectService的实例,使用其persist方法将该对象保存到Redis。
如果该对象之前已经被持久化到Redis中,我们就可以检索该对象:
LedgerLiveObject returnLedger
= service.get(LedgerLiveObject.class, "ledger1");
我们使用RLiveObjectService 来获取我们的实时对象,使用带有@RId注解的字段。
在这里我们可以找到更多关于Redisson Live Objects的信息,而其他Redisson服务的描述在这里。。
9.流水线
Redisson支持流水作业。多个操作可以作为一个单一的原子操作分批进行。这是由RBatch类促成的。在执行之前,多个命令被聚合到一个RBatch对象实例上:
RBatch batch = client.createBatch();
batch.getMap("ledgerMap").fastPutAsync("1", "2");
batch.getMap("ledgerMap").putAsync("2", "5");
BatchResult<?> batchResult = batch.execute();
10.脚本
Redisson支持LUA脚本。我们可以针对Redis执行LUA脚本:
client.getBucket("foo").set("bar");
String result = client.getScript().eval(Mode.READ_ONLY,
"return redis.call('get', 'foo')", RScript.ReturnType.VALUE);
11.低级客户端
我们有可能想执行Redisson还不支持的Redis操作。Redisson提供了一个低级别的客户端,允许执行本地Redis命令:
RedisClientConfig redisClientConfig = new RedisClientConfig();
redisClientConfig.setAddress("localhost", 6379);
RedisClient client = RedisClient.create(redisClientConfig);
RedisConnection conn = client.connect();
conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0);
conn.closeAsync();
client.shutdown();
低级别的客户端也支持异步操作。
12.结语
这篇文章展示了Redisson和一些使其成为开发分布式应用理想的功能。我们探讨了它的分布式对象、集合、锁和服务。我们还探讨了它的一些其他功能,如流水线、脚本和它的低级客户端。
Redisson 还提供与其他框架的集成,例如 JCache API、Spring Cache、Hibernate Cache 和 Spring Sessions。我们可以在此处了解更多关于它与其他框架的集成。
你可以在GitHub项目中找到代码样本。