redis sentinel搭建之后,在spring-boot项目中集成。
配置
在pom.xml文件中添加如下依赖配置(这里spring-boot版本2.2.5),这个版本中,默认使用lettuce作为redis连接池。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
在application.yml添加如下redis sentinel、lettuce配置,对应的配置类是RedisProperties
spring:
redis:
# host: 127.0.0.1
# port: 6380
# 连接redis节点和sentinel的密码,
password: passwd@190
lettuce:
pool:
max-active: 20
max-wait: -1
max-idle: 10
min-idle: 2
sentinel:
# redis主库别名配置,需要与哨兵配置中的主库别名一致
master: master_node
# 哨兵集群
nodes:
- 127.0.0.1:6390
- 127.0.0.1:6391
- 127.0.0.1:6393
集成
自动装配
在进行RedisProperties配置后,Spring Boot有一个自动装配的机制,步骤如下
- 配置Redis Connection Factory,用于管理Redis连接池。详见LettuceConnectionConfiguration
- 通过Redis Connection配置RedisTemplate,用于访问Redis。详见RedisAutoConfiguration
自动装配的方式适合在Redis单实例时使用,切换为sentinel架构后,在配置Redis Connection Factory中没有配置sentinel的访问密码,如果sentinel开启密码访问,会无法连接到sentinel集群。
在sentinel没有进行密码验证时,也只会对主库进行读写操作,无法做到主从库多节点访问。源码可见LettuceConnectionConfiguration.createLettuceConnectionFactory。
Redis Connection Factory
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
LettuceConnectionFactory redisConnectionFactory(
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
ClientResources clientResources) throws UnknownHostException {
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(builderCustomizers, clientResources,
getProperties().getLettuce().getPool());
return createLettuceConnectionFactory(clientConfig);
}
Redis Template
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
手动装配
自动装配模式下创建的RedisConnectionFactory无法满足我们的需求,那么只能由我们自己自定义配置了。
创建一个RedisConnectionFactory Bean,并重写sentinel配置和lettuce client配置。
@Bean
public RedisConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties) {
// 读取sentinel配置
String masterName = redisProperties.getSentinel().getMaster();
List<String> sentinelNodeList = redisProperties.getSentinel().getNodes();
RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration(masterName, new HashSet<>(sentinelNodeList));
// 设置节点和哨兵访问密码
sentinelConfiguration.setPassword(redisProperties.getPassword());
sentinelConfiguration.setSentinelPassword(redisProperties.getPassword());
// lettuce client配置,在进行读取时,访问任意一个节点,默认读写都只从主节点进行
LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration
.builder().readFrom(ReadFrom.ANY).build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(sentinelConfiguration, clientConfig);
// 在获取连接时,先验证连接是否已经中断,如果已经中断则创建一个新的连接
factory.setValidateConnection(true);
return factory;
}
验证
启动spring-boot项目后,Lettuce Connection通过Sentinel获取到主从库节点信息,并与之进行连接。在创建连接时,根据lettuce pool配置,会对主从节点做负载均衡,让连接均衡分配到各个节点。我们主要测试的项目是
- 写操作是否走的主库,读操作是否为任意主从库
- 主库宕机后,是否可以正常工作,能不能从Sentinel获取主从切换信息,进行主库的重新设定
而要知道这些信息,就得查看lettuce的日志,而日志级别为logging.level.root=info时,是看不到这些信息的。
在application.yml中添加如下配置,将lettuce包的日志级别设置为debug。
logging:
level:
io.lettuce.core: debug
在配置好后重启项目,通过RedisTemplate做两个类型的操作,一个是Set、一个是Get。
验证写操作
连续执行多个Set操作,查看Lettuce日志,发现请求始终是发给主库的,符合预期。
验证读操作
连续执行多个Get操作,查看Lettuce日志,发现请求是发给任一主从库的,符合预期。
验证主从切换
将主库宕机后,哨兵检测到主库下线,然后重新选主后进行主从切换,这个过程正常的话几秒内完成。客户端从哨兵获取新的主从库信息,重新配置主从库节点。
- 立即进行写操作,报无法连接redis的异常,符合预期
- 立即进行读操作,可以正常响应,符合预期
- 等待几秒后,进行读写操作,均可正常响应,符合预期。