👀Redis 哨兵模式 (Sentinel)
✍1. 作用
Redis Sentinel 是一个分布式系统,它为 Redis 服务器提供高可用性。其主要功能有:
- 监控 (Monitoring): Sentinel 会不断地检查你的 Redis 主服务器和从服务器是否按预期正常工作。
- 通知 (Notification): 当被监控的某个 Redis 实例出现问题时,Sentinel 可以通过 API 向管理员或其他应用程序发送通知。
- 自动故障转移 (Automatic failover): 如果一个主服务器不工作了,Sentinel 可以开始故障转移过程,选举一个从服务器成为新的主服务器,并由其他从服务器开始复制新的主服务器。
- 配置提供者 (Configuration provider): 客户端可以使用 Sentinel 来发现当前 Redis 集群的主服务器或从服务器的地址。
✍2. 使用场景
- 高可用性需求: 当你的应用需要 Redis 数据库具有高可用性时,使用 Sentinel。
- 故障自动恢复: 当 Redis 主服务器出现故障时,系统需要自动恢复。
- 动态服务发现: 当你想知道主服务器和从服务器的地址时,可以询问 Sentinel。
✍3. 优缺点
优点:
- 高可用性: 通过自动故障转移,Sentinel 可以确保 Redis 的高可用性。
- 动态服务发现: Sentinel 提供了服务发现的功能,允许客户端自动发现主服务器和从服务器的地址。
缺点:
- 网络分区: 在分布式系统中,网络分区可能会导致选举多个主服务器。
- 配置复杂性: Sentinel 的配置和维护可能比单个 Redis 实例复杂。
✍4. 示例代码
🎷1. application.yml
配置:
# 配置 Redis Sentinel 属性
spring:
redis:
sentinel:
master: mymaster # 主节点名称
nodes: 127.0.0.1:26379, 127.0.0.1:26380 # Sentinel 节点地址
username: sentineluser # Sentinel 用户名 (Redis 6及以上版本)
password: sentinelpassword # Sentinel 密码
🎷2. Redis 配置类:
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
@Configuration
public class RedisConfig {
// 从 application.yml 获取 Sentinel 配置属性
@Value("${spring.redis.sentinel.master}")
private String master;
@Value("${spring.redis.sentinel.nodes}")
private String nodes;
@Value("${spring.redis.sentinel.username}")
private String username;
@Value("${spring.redis.sentinel.password}")
private String password;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
// 创建 Sentinel 配置对象
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master(master) // 设置主节点名称
.sentinel(nodes.split(",")[0].split(":")[0], Integer.parseInt(nodes.split(",")[0].split(":")[1])) // 添加第一个 Sentinel 节点
.sentinel(nodes.split(",")[1].split(":")[0], Integer.parseInt(nodes.split(",")[1].split(":")[1])); // 添加第二个 Sentinel 节点
sentinelConfig.setDatabase(0); // 设置数据库索引
sentinelConfig.setPassword(RedisPassword.of(password)); // 设置密码
return new LettuceConnectionFactory(sentinelConfig); // 创建连接工厂
}
@Bean
public StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory); // 设置连接工厂
return template;
}
}
🎷3. Service 类:
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class RedisService {
// 注入 StringRedisTemplate
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 注入 RedisTemplate
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 存储字符串数据到 Redis
*
* @param key 键
* @param value 值
*/
public void setStringData(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}
/**
* 从 Redis 获取字符串数据
*
* @param key 键
* @return 值
*/
public String getStringData(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
/**
* 存储对象数据到 Redis
*
* @param key 键
* @param value 值
*/
public void setObjectData(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 从 Redis 获取对象数据
*
* @param key 键
* @return 值
*/
public Object getObjectData(String key) {
return redisTemplate.opsForValue().get(key);
}
}
🎷4. Controller 类:
package com.example.demo.controller;
import com.example.demo.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RedisController {
// 注入 RedisService
@Autowired
private RedisService redisService;
/**
* 存储数据到 Redis
*
* @param key 键
* @param value 值
* @return 响应消息
*/
@GetMapping("/set")
public String set(@RequestParam String key, @RequestParam String value) {
redisService.setStringData(key, value);
return "Data set successfully";
}
/**
* 从 Redis 获取数据
*
* @param key 键
* @return 值
*/
@GetMapping("/get")
public String get(@RequestParam String key) {
return redisService.getStringData(key);
}
}