前言
Lettuce客户端是一个线程安全的客户端,通信方式上基于netty,保证多个线程共享一个连接对象也不会存在线程安全问题,并且连接实例数量上支持可伸缩设计,一个连接达到上限后会按需增加连接实例。另外Lettuce客户端还支持异步请求方式、全局命令超时设置等特性。
注意: 使用Lettuce客户端,Redis的版本至少2.6
1.依赖
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> <version>5.1.8.RELEASE</version> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.3</version> </dependency>
|
Lettuce客户端因为不存在单个连接对象的线程安全问题,因此在连接池使用方面没有强制要求。如果请求频率不是很高,完全可以创建单个连接对象,毕竟Redis服务端处理命令是单线程执行,创建多个物理连接也是无意义的消耗资源。
2.单机版配置
2.1 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| # IP地址 spring.lettuce.host=127.0.0.1
# 端口 spring.lettuce.port=6379
# 连接密码 spring.lettuce.password=123456
# 连接超时时间 spring.lettuce.timeout=2000
# 连接池最大连接数(使用负值表示没有限制) spring.lettuce.pool.max-total=200
# 连接池最大空闲连接 spring.lettuce.pool.max-idle=10
# 连接池最小空闲连接 spring.lettuce.max-idle=5
|
2.2 Java配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| @Configuration public class LettuceConfig{
@Value("${spring.lettuce.host}") private String host;
@Value("${spring.lettuce.port}") private int port;
@Value("${spring.lettuce.password}") private String password;
@Value("${spring.lettuce.timeout}") private int timeout;
@Value("${spring.lettuce.pool.min-idle}") private int minIdle;
@Value("${spring.lettuce.pool.max-idle}") private int maxIdle;
@Value("${spring.lettuce.pool.max-total}") private int maxTotal;
@Bean public StatefulRedisConnection<String, String> statefulRedisConnection(){
RedisURI redisUri = RedisURI.builder() .withHost(host) .withPort(port) .withPassword(password) .withTimeout(Duration.of(timeout, ChronoUnit.SECONDS)) .build();
RedisClient redisClient = RedisClient.create(redisUri);
return client.connect(); }
@Bean public GenericObjectPool<StatefulRedisConnection<String, String>> genericObjectPool(){
RedisURI redisUri = RedisURI.builder() .withHost(host) .withPort(port) .withPassword(password) .withTimeout(Duration.of(timeout, ChronoUnit.SECONDS)) .build();
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); genericObjectPoolConfig.setMinIdle(minIdle); genericObjectPoolConfig.setMaxIdle(maxIdle); genericObjectPoolConfig.setMaxTotal(maxTotal);
RedisClient redisClient = RedisClient.create(redisUri);
return ConnectionPoolSupport.createGenericObjectPool(() -> client.connect(), poolConfig); } }
|
3.主从版配置
3.1 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| # IP地址 spring.lettuce.host=127.0.0.1
# 端口 spring.lettuce.port=6379
# 连接密码 spring.lettuce.password=123456
# 连接超时时间 spring.lettuce.timeout=2000
# 连接池最大连接数(使用负值表示没有限制) spring.lettuce.pool.max-total=200
# 连接池最大空闲连接 spring.lettuce.pool.max-idle=10
# 连接池最小空闲连接 spring.lettuce.max-idle=5
|
3.2 Java配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| @Configuration public class LettuceConfig{
@Value("${spring.lettuce.host}") private String host;
@Value("${spring.lettuce.port}") private int port;
@Value("${spring.lettuce.password}") private String password;
@Value("${spring.lettuce.timeout}") private int timeout;
@Value("${spring.lettuce.pool.min-idle}") private int minIdle;
@Value("${spring.lettuce.pool.max-idle}") private int maxIdle;
@Value("${spring.lettuce.pool.max-total}") private int maxTotal;
@Bean public StatefulRedisMasterSlaveConnection<String, String> statefulRedisConnection(){
RedisURI redisUri = RedisURI.builder() .withHost(host) .withPort(port) .withPassword(password) .withTimeout(Duration.of(timeout, ChronoUnit.SECONDS)) .build();
RedisClient redisClient = RedisClient.create(redisUri);
StatefulRedisMasterSlaveConnection<String, String> connection = MasterSlave.connect(redisClient, new Utf8StringCodec(), redisUri);
connection.setReadFrom(ReadFrom.MASTER);
return connection; }
@Bean public GenericObjectPool<StatefulRedisMasterSlaveConnection<String, String>> genericObjectPool(){ } }
|
如果不想通过任意节点获取所有主从节点信息,可以通过代码固定设置要连接的节点集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public StatefulRedisMasterSlaveConnection<String, String> statefulRedisConnection(){
List<RedisURI> uris = new ArrayList<>(); uris.add(RedisURI.builder().withHost(host1).withPort(port1).build()); uris.add(RedisURI.builder().withHost(host2).withPort(port2).build()); uris.add(RedisURI.builder().withHost(host3).withPort(port3).build());
RedisClient redisClient = RedisClient.create();
StatefulRedisMasterSlaveConnection<String, String> connection = MasterSlave.connect(redisClient, new Utf8StringCodec(), uris);
connection.setReadFrom(ReadFrom.MASTER);
return connection; }
|
4.哨兵版配置
4.1 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| # 哨兵IP地址 spring.lettuce.sentinel.host=127.0.0.1
# 哨兵端口 spring.lettuce.sentinel.port=26379
# masterId spring.lettuce.sentinel.master.id=master
# 连接密码 spring.lettuce.password=123456
# 连接超时时间 spring.lettuce.timeout=2000
# 连接池最大连接数(使用负值表示没有限制) spring.lettuce.pool.max-total=200
# 连接池最大空闲连接 spring.lettuce.pool.max-idle=10
# 连接池最小空闲连接 spring.lettuce.max-idle=5
|
4.2 Java配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @Configuration public class LettuceConfig{
@Value("${spring.lettuce.sentinel.host}") private String sentinelHost;
@Value("${spring.lettuce.sentinel.port}") private int sentinelPort;
@Value("${spring.lettuce.password}") private String password;
@Value("${spring.lettuce.timeout}") private int timeout;
@Value("${spring.lettuce.pool.min-idle}") private int minIdle;
@Value("${spring.lettuce.pool.max-idle}") private int maxIdle;
@Value("${spring.lettuce.pool.max-total}") private int maxTotal;
@Bean public StatefulRedisMasterSlaveConnection<String, String> statefulRedisConnection(){
RedisURI redisUri = RedisURI.builder() .withPassword(password) .withSentinel(sentinelHost, sentinelPort); .withSentinelMasterId(masterId); .build();
RedisClient redisClient = RedisClient.create(); StatefulRedisMasterSlaveConnection<String, String> connection = MasterSlave.connect(redisClient, new Utf8StringCodec(), redisUri);
connection.setReadFrom(ReadFrom.SLAVE); return connection; }
@Bean public GenericObjectPool<StatefulRedisMasterSlaveConnection<String, String>> genericObjectPool(){ } }
|
5.集群版配置
5.1 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 集群节点 spring.lettuce.cluster.nodes=127.0.0.1:7001,127.0.0.2:7001,127.0.0.3:7001
# 连接密码 spring.lettuce.password=123456
# 连接超时时间 spring.lettuce.timeout=2000
# 连接池最大连接数(使用负值表示没有限制) spring.lettuce.pool.max-total=200
# 连接池最大空闲连接 spring.lettuce.pool.max-idle=10
# 连接池最小空闲连接 spring.lettuce.max-idle=5
|
5.2 Java配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| @Configuration public class LettuceConfig{
@Value("#{'${spring.lettuce.cluster.nodes}'.split(',')}") private List<String> clusterList;
@Value("${spring.lettuce.password}") private String password;
@Value("${spring.lettuce.timeout}") private int timeout;
@Value("${spring.lettuce.pool.min-idle}") private int minIdle;
@Value("${spring.lettuce.pool.max-idle}") private int maxIdle;
@Value("${spring.lettuce.pool.max-total}") private int maxTotal;
@Bean public StatefulRedisClusterConnection<String, String> statefulRedisConnection(){
ArrayList<RedisURI> redisUriList = new ArrayList<>(); for(String cluster : clusterList){ String[] hostPort = cluster.split(":"); String host = hostPort[0]; Integer port = Integer.valueOf(hostPort[1]); redisUriList.add(RedisURI.builder().withHost(host).withPort(port).withPassword(password).build()); }
RedisClusterClient redisClusterClient = RedisClusterClient.create(redisUriList);
ClusterTopologyRefreshOptions options = ClusterTopologyRefreshOptions .builder() .enablePeriodicRefresh(Duration.of(10, ChronoUnit.MINUTES)) .build();
redisClusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(options).build());
StatefulRedisClusterConnection<String, String> connection = redisClusterClient.connect();
connection.setReadFrom(ReadFrom.SLAVE);
return connection; }
@Bean public GenericObjectPool<StatefulRedisClusterConnection<String, String>> genericObjectPool(){ } }
|
6.基本使用
6.1 同步使用
同步的使用方式就和普通的方法调用一样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Component public class LettuceCommands{
@Autowired private StatefulRedisClusterConnection clusterConnection;
private static RedisAdvancedClusterCommands<String, String> commands;
@PostConstruct public void initRedisCommands(){ commands = clusterConnection.sync(); }
public static void set(String key, String value){ commands.set(key, value); }
public static void set(String key, String value){ SetArgs setArgs = SetArgs.Builder.nx().ex(5); commands.set(key, value, setArgs); }
public static String get(String key){ return commands.get(key); } }
|
6.2 异步使用
异步调用就像使用Java自带的线程FutureTask一样,调用后立即返回RedisFuture对象,并通过调用get()方法阻塞获取返回值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Component public class LettuceCommands{
@Autowired private StatefulRedisClusterConnection clusterConnection;
private static RedisAdvancedClusterAsyncCommands<String, String> commands;
@PostConstruct public void initRedisCommands(){ commands = clusterConnection.async(); }
public static RedisFuture<String> set(String key, String value){ return commands.set(key, value); }
public static RedisFuture<String> set(String key, String value){ return commands.set(key, value); }
public static RedisFuture<String> get(String key){ return commands.get(key); } }
|
6.3 反应式使用
Lettuce的反应式基于编程框架Project Reactor,暂时没看懂。