使用注意:要求JDK8及以上,redis版本至少为2.6
官方文档:https://lettuce.io/core/release/reference/index.html#getting-started.get-it
1、Lettuce简介
Lettuce是一个基于netty和Reactor的可伸缩线程安全Redis客户端。Lettuce提供了同步、异步、反应式API来与Redis进行交互。
2、基本使用
Lettuce使用的时候主要依赖于以下四个组件:
① redisURI:连接信息。
② redisClient:Redis客户端,如果是集群模式,集群连接有一个定制的RedisClusterClient。
③ connection:Redis的连接。
④ redisCommands:Redis命令API接口,基本上覆盖了Redis发行版本的所有命令,提供了同步(sync)、异步(async)、反应式(reative)的调用方式。
maven
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
2.1 单机模式
2.1.1 同步(sync)
入门案例:
/** 初始化四个组件 **/
RedisURI redisUri = RedisURI.builder()
.withHost("192.168.139.198")
.withPort(6379)
.withTimeout(Duration.of(10, ChronoUnit.SECONDS))
.build();
RedisClient redisClient = RedisClient.create(redisUri);
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> redisCommands = connection.sync();
/** API的使用 **/
String result = redisCommands.set("name", "gaojian");
System.out.println(result);
result = redisCommands.get("name");
System.out.println(result);
/** 关闭资源 **/
connection.close();
redisClient.shutdown();
可以通过如下配置设置超时时间
SetArgs timeout = SetArgs.Builder.nx().ex(5);
String result = redisCommands.set("name", "gaojian", timeout);
所有连接均从其RedisClient继承默认超时,超时默认为60秒,当非阻塞命令未能在超时到期之前返回结果时 ,抛出RedisException异常,可以在RedisClient或每个连接中更改(如上)。如果Redis响应错误,则同步方法将抛出RedisCommandExecutionException,异步连接不会引发异常。
Redis连接被设计为长期存在并且是线程安全的,如果连接丢失,将重新连接直到close()被调用。成功重新连接后,将(重新)发送尚未超时的未决命令,所以在应用程序的最后,才关闭连接,同时,关闭客户端实例以释放线程和资源。
2.1.2 异步(async)
异步方法可以更好的利用系统资源,而不是浪费线程等待网络或磁盘I / O。可以充分利用线程来执行其他工作。Lettuce通过在基于Netty的客户端 (多线程,事件驱动的I / O框架)上构建客户端来促进异步性。所有通信都是异步处理的。
/** 初始化四个组件 **/
RedisURI redisUri = RedisURI.builder()
.withHost("192.168.139.198")
.withPort(6379)
.withTimeout(Duration.of(10, ChronoUnit.SECONDS))
.build();
RedisClient redisClient = RedisClient.create(redisUri);
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisAsyncCommands<String, String> asyncCommands = connection.async();
/** API的使用 **/
RedisFuture<String> future = asyncCommands.set("age", "18");
future.get(10,TimeUnit.SECONDS);
future.thenAccept(new Consumer<String>() {
@Override
public void accept(String value) {
System.out.println(value);
}
});
RedisFuture<String> redisFuture = asyncCommands.get("age");
redisFuture.get(10,TimeUnit.SECONDS);
redisFuture.thenAccept(new Consumer<String>() {
@Override
public void accept(String value) {
System.out.println(value);
}
});
/** 关闭资源 **/
connection.close();
redisClient.shutdown();
对get()方法(拉式)的调用至少会阻塞调用线程,直到计算出值为止,但在最坏的情况下会无限期地阻塞该线程,为了防止无限期的阻塞该线程,建议使用超时配置。
2.1.3 响应式(reactor)
笔者暂不对该方式进行描述
2.2集群模式
连接到Redis集群需要一个或多个初始种子节点。完整的群集拓扑视图(分区)是在第一个连接上获得的,因此不需要指定所有群集节点。指定多个种子节点有助于提高弹性,因为即使种子节点不可用,Lettuce仍可以连接群集。
注意:群集连接本身会使用节点连接来执行群集操作,如果阻止一个连接,则群集连接的所有其他用户可能会受到影响。
2.2.1 同步(sync)
RedisURI node1 = RedisURI.create("192.168.139.172", 7000);
RedisURI node2 = RedisURI.create("192.168.139.172", 7001);
RedisURI node3 = RedisURI.create("192.168.139.172", 7002);
RedisURI node4 = RedisURI.create("192.168.139.172", 7003);
RedisURI node5 = RedisURI.create("192.168.139.172", 7004);
RedisURI node6 = RedisURI.create("192.168.139.172", 7005);
RedisClusterClient clusterClient = RedisClusterClient.create(Arrays.asList(node1,node2,node3,node4,node5,node6));
StatefulRedisClusterConnection<String, String> connection = clusterClient.connect();
RedisAdvancedClusterCommands<String, String> clusterCommands = connection.sync();
/** API的使用 **/
String set = clusterCommands.set("name", "gaojian");
System.out.println(set);
String name = clusterCommands.get("name");
System.out.println(name);
connection.close();
clusterClient.shutdown();
2.2.2 异步(async)
RedisURI node1 = RedisURI.create("192.168.139.172", 7000);
RedisURI node2 = RedisURI.create("192.168.139.172", 7001);
RedisURI node3 = RedisURI.create("192.168.139.172", 7002);
RedisURI node4 = RedisURI.create("192.168.139.172", 7003);
RedisURI node5 = RedisURI.create("192.168.139.172", 7004);
RedisURI node6 = RedisURI.create("192.168.139.172", 7005);
RedisClusterClient clusterClient = RedisClusterClient.create(Arrays.asList(node1,node2,node3,node4,node5,node6));
StatefulRedisClusterConnection<String, String> connection = clusterClient.connect();
RedisAdvancedClusterAsyncCommands<String, String> asyncCommands = connection.async();
/** API的使用 **/
RedisFuture<String> future = asyncCommands.set("name", "gaojian");
future.get(10,TimeUnit.SECONDS);
future.thenAccept(new Consumer<String>() {
@Override
public void accept(String value) {
System.out.println(value);
}
});
RedisFuture<String> redisFuture = asyncCommands.get("name");
redisFuture.get(10,TimeUnit.SECONDS);
redisFuture.thenAccept(new Consumer<String>() {
@Override
public void accept(String value) {
System.out.println(value);
}
});
connection.close();
clusterClient.shutdown();
2.2.3 反应式(reactor)
笔者暂不对该方式进行描述
2.3 连接池
Lettuce连接被设计为线程安全的,因此一个连接可以在多个线程之间共享,并且默认情况下,Lettuce连接会自动重新连接。在大多数情况下不需要连接池,但是Lettuce也是支持连接池的,连接池总会带来复杂性和维护成本。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.3</version>
</dependency>
RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.create("192.168.139.198", 6379));
GenericObjectPool<StatefulRedisClusterConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> clusterClient.connect(), new GenericObjectPoolConfig());
StatefulRedisClusterConnection<String, String> connection = pool.borrowObject();
String age = connection.sync().set("age", "123");
System.out.println(age);
connection.sync().blpop(10, "age");
String age1 = connection.sync().get("age");
System.out.println(age1);
pool.close();
clusterClient.shutdown();