Redis哨兵高可用架构
- sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。
- 哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过 sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis 主节点通知给client端(这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)
redis哨兵架构搭建步骤:
//1、复制一份sentinel.conf文件
cp sentinel.conf sentinel‐26379.conf
//2、将相关配置修改为如下值:
port 26379
daemonize yes
pidfile "/var/run/redis‐sentinel‐26379.pid"
logfile "26379.log"
dir "/usr/local/redis‐5.0.3/data"
//sentinel monitor <master‐name> <ip> <redis‐port> <quorum>
//quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效
sentinel monitor mymaster 192.168.0.60 6379 2
//3、启动sentinel哨兵实例
src/redis‐sentinel sentinel‐26379.conf
//4、查看sentinel的info信息
src/redis‐cli ‐p 26379
127.0.0.1:26379>info
//可以看到Sentinel的info里已经识别出了redis的主从
//5、可以自己再配置两个sentinel,端口26380和26381,注意上述配置文件里的对应数字都要修改
哨兵的Spring Boot整合Redis连接代码见示例项目:
1、引入相关依赖:
<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>
springboot项目核心配置:
server:
port: 8080
spring:
redis:
database: 0
timeout: 3000
lettuce:
pool:
max‐idle: 50
min‐idle: 10
max‐active: 100
max‐wait: 1000
sentinel: //哨兵模式
master: mymaster //主服务器所在集群名称
nodes: 192.168.0.60:26379,192.168.0.60:26380,192.168.0.60:26381
访问代码:
@RestController
public class IndexController {
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 测试节点挂了哨兵重新选举新的master节点,客户端是否能动态感知到
* * 新的master选举出来后,哨兵会把消息发布出去,客户端实际上是实现了一个消息监听机制,
* * 当哨兵把新master的消息发布出去,客户端会立马感知到新master的信息,从而动态切换访问的maste rip
* *
* * @throws InterruptedException
* */
@RequestMapping("/test_sentinel")
public void testSentinel() throws InterruptedException {
int i = 1;
while (true){
try {
stringRedisTemplate.opsForValue().set("zhuge"+i, i+"");
System.out.println("设置key:"+ "zhuge" + i);
i++;
Thread.sleep(1000);
}catch (Exception e){
logger.error("错误:", e);
}
}
}
}
StringRedisTemplate与RedisTemplate
spring 封装了 RedisTemplate 对象来进行对redis的各种操作,它支持所有的 redis 原生的 api。在 RedisTemplate中提供了几个常用的接口方法的使用,分别是:
private ValueOperations<K, V> valueOps;
private HashOperations<K, V> hashOps;
private ListOperations<K, V> listOps;
private SetOperations<K, V> setOps;
private ZSetOperations<K, V> zSetOps;
RedisTemplate中定义了对5种数据结构操作
redisTemplate.opsForValue(); //操作字符串
redisTemplate.opsForHash(); //操作hash
redisTemplate.opsForList(); //操作list
redisTemplate.opsForSet(); //操作set
redisTemplate.opsForZSet(); //操作有序set
StringRedisTemplate继承自RedisTemplate,也一样拥有上面这些操作。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
Redis客户端命令对应的RedisTemplate中的方法列表:
String类型结构
Redis | RedisTemplate rt |
---|---|
set key value | rt.opsForValue().set(“key”,“value”) |
get key | rt.opsForValue().get(“key”) |
del key | rt.delete(“key”) |
strlen key | rt.opsForValue().size(“key”) |
getset key value | rt.opsForValue().getAndSet(“key”,“value”) |
getrange key start end | rt.opsForValue().get(“key”,start,end) |
append key value | rt.opsForValue().append(“key”,“value”) |
Hash结构
hmset key field1 value1 field2 value2… | rt.opsForHash().putAll(“key”,map) //map是一 个集合对象 |
---|---|
hset key field value | rt.opsForHash().put(“key”,“field”,“value”) |
hexists key field | rt.opsForHash().hasKey(“key”,“field”) |
hgetall key | rt.opsForHash().entries(“key”) //返回Map对象 |
hvals key | rt.opsForHash().values(“key”) //返回List对象 |
hkeys key | rt.opsForHash().keys(“key”) //返回List对象 |
hmget key field1 field2… | rt.opsForHash().multiGet(“key”,keyList) |
hsetnx key field value | rt.opsForHash().putIfAbsent(“key”,“field”,“value” |
hdel key field1 field2 | rt.opsForHash().delete(“key”,“field1”,“field2”) |
hget key field | rt.opsForHash().get(“key”,“field”) |
List结构
lpush list node1 node2 node3… | rt.opsForList().leftPush(“list”,“node”) |
---|---|
rt.opsForList().leftPushAll(“list”,list) //list是集合对象 | |
rpush list node1 node2 node3… | rt.opsForList().rightPush(“list”,“node”) |
rt.opsForList().rightPushAll(“list”,list) //list是集 合对象 | |
lindex key index | rt.opsForList().index(“list”, index) |
llen key | rt.opsForList().size(“key”) |
lpop key | rt.opsForList().leftPop(“key”) |
rpop key | rt.opsForList().rightPop(“key”) |
lpushx list node | rt.opsForList().leftPushIfPresent(“list”,“node”) |
rpushx list node | rt.opsForList().rightPushIfPresent(“list”,"node ") |
lrange list start end | rt.opsForList().range(“list”,start,end) |
lrem list count value | rt.opsForList().remove(“list”,count,“value”) |
lset key index value | rt.opsForList().set(“list”,index,“value”) |
Set结构
sadd key member1 member2… | rt.boundSetOps(“key”).add(“member1”,“me mber2”,…) |
---|---|
rt.opsForSet().add(“key”, set) //set是一个集合 对象 | |
scard key | rt.opsForSet().size(“key”) |
sidff key1 key2 | rt.opsForSet().difference(“key1”,“key2”) //返 回一个集合对象 |
sinter key1 key2 | rt.opsForSet().intersect(“key1”,“key2”)//同上 |
sunion key1 key2 | rt.opsForSet().union(“key1”,“key2”)//同上 |
sdiffstore des key1 key2 | rt.opsForSet().differenceAndStore(“key1”,“ke y2”,“des”) |
sinter des key1 key2 | rt.opsForSet().intersectAndStore(“key1”,"key2 ",“des”) |
sunionstore des key1 key2 | rt.opsForSet().unionAndStore(“key1”,“key2”," des") |
sismember key member | rt.opsForSet().isMember(“key”,“member”) |
smembers key | rt.opsForSet().members(“key”) |
spop key | rt.opsForSet().pop(“key”) |
srandmember key count | rt.opsForSet().randomMember(“key”,count) |
srem key member1 member2… | rt.opsForSet().remove(“key”,“member1”,“member2”,…) |