Redis哨兵模式在Spring Boot项目中的使用与实践

Redis哨兵模式在Spring Boot项目中的使用与实践

什么是Redis哨兵模式?

Redis Sentinel(哨兵)是Redis官方提供的高可用性解决方案,主要用于管理Redis主从架构,实现自动故障转移监控通知。在没有哨兵模式之前,当Redis主节点宕机时,需要手动进行主从切换并更新应用程序配置,这对运维人员来说是极大的负担。有了哨兵模式,这些操作全部自动化,对客户端透明无缝切换,大大提高了系统的可靠性。

哨兵模式主要功能包括:

  • 监控:持续检查主节点和从节点是否正常运行
  • 通知:当监控的Redis实例出现问题时,向其他哨兵和客户端发送警报
  • 自动故障转移:主节点故障时自动选择一个从节点升级为主节点,并调整其他从节点指向新主节点

Spring Boot中配置Redis哨兵模式

添加依赖

pom.xml中添加Spring Boot Data Redis依赖,默认使用Lettuce客户端:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

如果需要使用Jedis客户端,还需添加:

xml 复制代码
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

配置文件设置

application.yml中配置Redis哨兵相关信息:

yaml 复制代码
spring:
  redis:
    password: your-redis-password  # Redis认证密码
    sentinel:
      master: mymaster  # Redis主节点名称
      nodes:  # 哨兵节点列表
        - 192.168.1.110:26379
        - 192.168.1.111:26379
        - 192.168.1.112:26379
    lettuce:
      pool:  # 连接池配置(可选)
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 5000ms

或者在application.properties中配置:

properties 复制代码
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.1.110:26379,192.168.1.111:26379,192.168.1.112:26379
spring.redis.password=your-redis-password

自定义配置类

如果需要更精细的控制,可以创建自定义配置类:

java 复制代码
@Configuration
public class RedisConfig {
    
    @Value("${spring.redis.sentinel.nodes}")
    private String sentinelNodes;
    
    @Value("${spring.redis.sentinel.master}")
    private String sentinelMaster;
    
    @Bean
    public RedisSentinelConfiguration redisSentinelConfiguration() {
        RedisSentinelConfiguration config = new RedisSentinelConfiguration();
        config.setMaster(sentinelMaster);
        config.setSentinels(Arrays.stream(sentinelNodes.split(","))
                .map(hostAndPort -> {
                    String[] args = hostAndPort.split(":");
                    return new RedisNode(args[0], Integer.parseInt(args[1]));
                })
                .collect(Collectors.toSet()));
        return config;
    }
    
    @Bean
    public LettuceConnectionFactory lettuceConnectionFactory(RedisSentinelConfiguration redisSentinelConfiguration) {
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .readFrom(ReadFrom.MASTER_PREFERRED)  // 优先从主节点读取
                .build();
        
        return new LettuceConnectionFactory(redisSentinelConfiguration, clientConfig);
    }
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(lettuceConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

使用RedisTemplate操作Redis

配置完成后,可以在服务中使用RedisTemplate来操作Redis:

java 复制代码
@Service
public class UserService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    public void saveUser(String username, String password) {
        redisTemplate.opsForHash().put("users", username, password);
    }
    
    public String findUser(String username) {
        return (String) redisTemplate.opsForHash().get("users", username);
    }
    
    // 更多操作方法...
}

创建Controller提供API接口:

java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @PostMapping("/add")
    public String addUser(String username, String password) {
        userService.saveUser(username, password);
        return "用户添加成功";
    }
    
    @GetMapping("/{username}")
    public String getUser(@PathVariable String username) {
        return userService.findUser(username);
    }
}

读写分离配置

Lettuce客户端支持读写分离策略,可以在配置中指定:

java 复制代码
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
    .readFrom(ReadFrom.MASTER_PREFERRED)  // 优先从主节点读
    .build();

可选读策略包括:

  • MASTER:只从主节点读取
  • MASTER_PREFERRED:优先从主节点读取,主节点不可用时从副本读取
  • REPLICA:只从副本读取
  • REPLICA_PREFERRED:优先从副本读取,副本不可用时从主节点读取

常见问题与解决方案

  1. 认证失败错误:如果出现"NOAUTH HELLO must be called with the client already HELLO"错误,可能需要配置哨兵密码:
yaml 复制代码
spring:
  redis:
    sentinel:
      password: your-sentinel-password
  1. 域名解析问题:如果哨兵返回的是域名而不是IP,需要在本地hosts文件中配置域名解析。

  2. 连接池配置:根据应用需求合理配置连接池参数,以提高性能并避免资源耗尽:

yaml 复制代码
lettuce:
  pool:
    max-active: 8    # 最大连接数
    max-idle: 8      # 最大空闲连接数
    min-idle: 0      # 最小空闲连接数
    max-wait: 5000ms # 最大等待时间

最佳实践

  1. 哨兵节点数量:生产环境至少部署3个哨兵节点,以确保哨兵集群自身的高可用性。

  2. 网络规划:尽量让应用程序节点和Redis节点在相同的网络环境下,减少网络延迟。

  3. 监控告警:监控Redis实例和哨兵进程的状态,设置适当的告警机制。

  4. 定期演练:定期进行故障转移演练,验证系统的可靠性。

  5. 客户端兼容性:确保使用的客户端版本与Redis服务器版本兼容。

总结

Redis哨兵模式为Spring Boot应用程序提供了高可用的Redis解决方案,实现了自动故障转移和监控功能。通过合理的配置和使用,可以大大提升系统的稳定性和可靠性。在实际项目中,应根据业务需求选择合适的配置参数,并遵循最佳实践,才能充分发挥Redis哨兵模式的优势。

相关推荐
夜影风2 小时前
Redis集群创建时出现“Node xxx.xxx is not empty”问题处理
数据库·redis·缓存
utf8mb4安全女神3 小时前
【Redis数据库】哨兵集群/redis集群/安装配置/主从复制/数据持久化操作/数据结构/安全限制/PHP redis/
linux·服务器·数据结构·数据库·redis·缓存
豆瓣鸡3 小时前
封装 API 请求日志切面——从注解定义到 Starter 自动装配
java·开发语言·spring boot
烤代码的吐司君5 小时前
Redis IO 多路复用原理与引入原因深度解析
数据库·redis·php
无小道6 小时前
Redis——redis和mysql的数据同步
数据库·redis·mysql
正儿八经的少年6 小时前
Spring Boot
java·spring boot·后端
豆瓣鸡7 小时前
封装 Jackson 配置 Starter:统一解决 LocalDateTime 请求解析和响应格式化问题
java·spring boot
宠友信息7 小时前
资源权限与钱包流水在即时通讯源码后端架构中的设计
java·spring boot·redis·websocket·缓存
_Jimmy_7 小时前
Redis.from_url()连接redis时,redis密码带有#号报错
redis
霸道流氓气质7 小时前
Spring Boot 接入阿里云 RocketMQ 完整指南
spring boot·阿里云·java-rocketmq