介绍

Redis 目前被广泛应用,缓存、限流、PubSub、分布式锁、分布式数据结构等等许多场景都十分实用,Redis 的高可用(High Available) 自然是必不可少。

Redis 单机有单点故障,Master-Slave 无法做自动故障转移,可以使用官方推荐的 Sentinel 实现Redis高可用方案。

Sentinel 负责监控 Redis Master,同时 Sentinel 集群之间通过 Master 进行通讯。Sentinel 以集群保障自身的可靠性,官方建议 Sentinel 至少保持3个节点。

Sentinel 提供以下特性(来自官网):

  • 监控(Monitoring):持续检查 master、slave 健康状况
  • 提醒(Notification):当Redis实例出问题时,可以通过系统管理员或以API形式通知其他应用。
  • 自动故障转移(Automatic failover):当master发生故障时,Sentinel 会开启故障处理流程,将一个slave晋升为master,并将其他slave重新配置到新的master。当应用进行连接时,Sentinel会将新的master告知应用。
  • 配置提供者(Configuration provider):Sentinel 为客户端提供master节点的地址,当发生故障时,负责报告新的master节点给客户端。

Sentinel HA 搭建

实验环境:CentOS 7、Docker 1.13.1

搭建Redis Master-Slave

运行3个redis实例,设置一主两从。

docker run -it --name redis-master -d redis redis-server
docker run -it --name redis-slave1 -d redis redis-server
docker run -it --name redis-slave2 -d redis redis-server

使用下面命令拿到 redis-master 的IP: 172.17.0.4

docker inspect --format='{{.NetworkSettings.IPAddress}}' redis-master

为两个slave节点分别执行下面命令,将自己设置为slave.

docker exec -it redis-slave1 redis-cli -p 6379
127.0.0.1:6379> slaveof 172.17.0.4 6379

服从复制已搭建好,可以在master看看主从复制的状态,此时已经检测到两个连接上来的slave.

docker exec -it redis-master redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.5,port=6379,state=online,offset=546,lag=1
slave1:ip=172.17.0.6,port=6379,state=online,offset=546,lag=0
...

在master做增删改操作后数据会立即同步到2个slave,主从结构可以做读写分离,缓解主库压力。

搭建Sentinel集群

准备配置文件

先从官网下载 Sentinel 的demo配置文件。

redis 配置文件改成 redis.conf 即可。

wget http://download.redis.io/redis-stable/sentinel.conf

做如下修改:

  • 设置需要监控的master节点信息,格式:sentinel monitor <master-name> <master-redis-ip> <master-redis-port> <quorum>
sentinel monitor mymaster 172.17.0.4 6379 2

如果要监控多个master集群,这里可以写多行,各个集群的自定义集群名要修改一下。

quorum 是最小投票数,准备使用3个sentinel节点,设置为2后选择新master时需要2个节点同意。

  • 设置 daemonize yes 表示以后台守护程序运行
运行集群

sentinel.conf 复制三个,分别为 sentinel1.conf、sentinel2.conf、sentinel3.conf,在启动时这几个文件会被自动写入一些其他配置信息。

先启动三个redis实例:redis-sentinel1、2、3,由于sentinel会修改sentinel.conf,我的配置文件位于 /root/redis 目录。

docker run -it --name redis-sentinel1 --privileged -v /root/redis/sentinel1.conf:/data/sentinel.conf -d redis
docker run -it --name redis-sentinel2 --privileged -v /root/redis/sentinel2.conf:/data/sentinel.conf -d redis
docker run -it --name redis-sentinel3 --privileged -v /root/redis/sentinel3.conf:/data/sentinel.conf -d redis

接着使用 /data/sentinel.conf配置启动 redis-sentinel,sentinel其实是一个运行在特殊模式下的 Redis实例。

docker exec -it redis-sentinel1 redis-sentinel /data/sentinel.conf
docker exec -it redis-sentinel2 redis-sentinel /data/sentinel.conf
docker exec -it redis-sentinel3 redis-sentinel /data/sentinel.conf

此时任意一台sentinel节点可以看到的信息:

docker exec -it redis-sentinel3 redis-cli -p 26379
127.0.0.1:26379> info Sentinel
# Sentinel
sentinel_masters:1
master0:name=mymaster,status=ok,address=172.17.0.4:6379,slaves=2,sentinels=3

可以看到:master节点是 172.17.0.4,有2个slave、3个sentinel节点。

自动故障切换测试

停止 master节点,再看看sentinel信息。

docker stop redis-master

很快sentinel会重新选举一个master,新的节点是:172.17.0.6,不再是172.17.0.4

master0:name=mymaster,status=ok,address=172.17.0.6:6379,slaves=2,sentinels=3

此时再启动 redis-master,查看其状态,切换成了slave节点。

docker exec -it redis-master redis-cli -p 6379
127.0.0.1:6379> info Replication
# Replication
role:slave
master_host:172.17.0.6
master_port:6379
master_link_status:up

Spring Boot 使用演示

以一个Spring Boot 2.0.6.RELEASE 程序演示配置及使用,先引入 redis 操作组件依赖(也可以使用Redisson):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置 sentinel 节点:

这里使用的是容器的IP:Port,需要将本机网络和容器网络打通,可参考 Mac 如何访问容器网络.

spring:
  redis:
    sentinel:
      master: mymaster
      nodes: 172.17.0.2:26379, 172.17.0.3:26379, 172.17.0.7:26379

提供一个简单的读写接口:

@RestController
public class DemoController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("sentinel")
    public String sentinel() {
        stringRedisTemplate.opsForValue().set("hello", "sentinel");
        return stringRedisTemplate.opsForValue().get("hello");
    }
}

访问 http://localhost:8080/sentinel,此时去redis任意节点查看,都能看到 hello:sentinel

以容器来演示非常方便,实际使用时,使用内部域名将IP全部换掉即可。