Lettuce是一款基于Java的高性能Redis客户端,专为高并发、分布式场景设计。它凭借非阻塞I/O模型、线程安全性和丰富的功能支持,成为Spring Boot默认的Redis驱动框架,并在企业级应用中广泛使用。
Spring Boot集成Lettuce
在pom.xml
中添加Spring Boot默认的Lettuce依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
Spring Boot 2.x及以上版本默认集成Lettuce,无需额外引入。
在application.yml
中配置Redis基础参数:
spring:
data:
redis:
# Redis单机配置
host: 127.0.0.1
port: 6379
lettuce:
pool:
enabled: true
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: 5000ms # 最大等待时间
支持连接池参数调优以应对高并发场景。
自定义序列化器避免JDK序列化问题:
package com.morris.redis.demo.lettuce;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(factory);
return template;
}
}
通过StringRedisSerializer
和Jackson2JsonRedisSerializer
支持JSON格式存储。
RedisTemplate的使用:
package com.morris.redis.demo.lettuce;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
/**
* RedisTemplate的使用
*/
@SpringBootApplication
public class LettuceSpringBootDemo {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(LettuceSpringBootDemo.class, args);
RedisTemplate redisTemplate = (RedisTemplate) applicationContext.getBean("redisTemplate");
redisTemplate.opsForValue().set("oo", "xx");
System.out.println(redisTemplate.opsForValue().get("oo"));
applicationContext.close();
}
}
哨兵模式(Sentinel)
在application.yml
中指定哨兵节点及主节点名称:
spring:
data:
redis:
# redis哨兵模式
sentinel:
master: mymaster
nodes: 127.0.0.1:16380,127.0.0.1:16381,127.0.0.1:16382
lettuce:
pool:
enabled: true
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: 5000ms # 最大等待时间
哨兵模式自动处理主节点故障转移。
集群模式(Cluster)
在application.yml
中声明集群节点:
spring:
data:
redis:
# redis集群模式
cluster:
nodes: 127.0.0.1:3001,127.0.0.1:3002,127.0.0.1:3003
max-redirects: 5
lettuce:
pool:
enabled: true
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: 5000ms # 最大等待时间
Lettuce自动感知集群拓扑变化并路由请求。
Lettuce是典型的Smart客户端,尤其在Redis集群模式下,其设计充分体现了智能路由、本地缓存和动态更新的核心特性。
Lettuce在初始化时通过CLUSTER SLOTS获取集群拓扑,并缓存槽位与节点的映射关系。后续操作直接基于本地缓存定位目标节点,避免频繁查询服务端。
当遇到MOVED或ASK错误时,Lettuce自动触发拓扑刷新,重新获取最新节点信息,并更新本地缓存。
基于Netty的NIO模型,Lettuce的StatefulRedisConnection是线程安全的,多线程可共享同一连接,通过管道(Pipelining)非阻塞发送命令,提升吞吐量。
利用TCP的全双工特性,异步发送请求并批量接收响应,减少网络延迟影响。
Lettuce哨兵模式的读写分离实现
Lettuce在Redis哨兵模式中默认不启用读写分离,但可以通过自定义配置实现读写分离。
默认行为如下:
- 写操作:所有请求(包括读写)默认路由到主节点(Master)。
- 读操作:默认从主节点读取,无法自动分发到从节点(Slave)。
哨兵模式下,Lettuce默认仅通过主节点处理所有请求,未利用从节点的读能力,可能造成主节点负载过高。
通过自定义 LettuceClientConfiguration
,强制将读操作分发到从节点:
package com.morris.redis.demo.lettuce;
import io.lettuce.core.ReadFrom;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LettuceClientConfig {
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer() {
return clientConfigurationBuilder ->
clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED); // 优先从从节点读取
}
}
策略选项:
ReadFrom.MASTER
:仅从主节点读(默认)。ReadFrom.REPLICA
:仅从从节点读。ReadFrom.REPLICA_PREFERRED
:优先从从节点读,失败时降级到主节点。
通过RedisTemplate
执行读写操作,观察日志中的节点地址:
redisTemplate.opsForValue().set("oo", "xx");// 写操作(主节点)
System.out.println(redisTemplate.opsForValue().get("oo"));// 读操作(从节点)
启用Lettuce的 DEBUG
日志,验证命令是否路由到不同节点:
logging:
level:
io.lettuce.core: DEBUG