一步一步动手搭建 Redis Sentinel 集群并与 SpringBoot 整合

本文着力介绍如何实现 Redis Sentinel 模式, 从而实现高可用. 整体架构由 4 个 Redis Instance 和 3 个 Redis Sentinel 组成. 并介绍如何与 SpringBoot 集成.

工作机制

Redis Sentinel (哨兵) 是官方推荐的高可用解决方案, 当 Redis 在做 master-slave 的高可用方案时, 如果 master 宕机了, Redis 本身没有实现自动主备切换的特性, Sentinel 可以做到这一点.

Redis Sentinel 本身也是独立运行的进程, 可以部署在其他与 Redis 集群 (Cluster) 可通讯的机器中监控 Redis 集群.

  • 监控: Sentinel 能够持续的监听你的主备节点是否正常运行.
  • 通知: 当被监听的节点出现异常状况的时候, Sentinel 能够通知系统管理员, 或者通知应用程序 (通过 API).
  • 自动的故障转移: 如果主节点没有按照预期正常运行, Sentinel 会启动故障转移流程, 备用节点会被提升成主节点, 其他备用节点也会被重新配置以从新的主节点备份数据. 对接了 Redis 的应用程序也会被通知到切换到新的主节点的连接地址.
  • 配置提供: Sentinel 表现的像是 Redis Instance 的服务发现组件, 客户端连接 Sentinel 以获得当前主节点实例的地址, 如果故障转移流程启动, Sentinel 则会反馈新的主节点地址.

Redis Sentinel 本身就被设计作为一个分布式系统, 与其他 Sentinel 协同工作, 这样的好处有:

  • 投票机制: 当多个 Sentinel 同意当前主节点已经不再可用的时候, 执行主备切换 (少数服从多数).
  • 即使 Sentinel 集群本身有节点不可用, 也不妨碍其他 Sentinel 正常运行.

在这里插入图片描述

当 Sentinel 集群中多数 (如果节点数为 3, 这个阈值就应该是 2) Sentinel 都认为当前 master 故障, 才会进行主备切换, 投票将剩下的备用节点中的其中一台提升为 master 节点, 并自动修改 redis.conf 配置文件, 使其余备用节点响应新的 master.

环境搭建

首先, 你的机器上应该已经安装 Redis, 参考: CentOS 7 编译 安装 Redis-5.0.2

Redis Instance 配置

① 在 /usr/local 下新建一个目录 redis-5.0.2-sentinel:

mkdir redis-5.0.2-sentinel

② 我们占用 7501 ~ 7507 7 个端口, 其中 7501 ~ 7504 4 个端口为 Redis Instance 集群, 包含 1 主 3 从, 7505 ~ 7507 3 个端口为 Redis Sentinel 集群, 包含 1 主 2 从. 在该目录下新建 7 个文件夹:

mkdir /usr/local/redis-5.0.2-sentinel/{7501,7502,7503,7504,7505,7506,7507}

预期文件结构如下:

./redis-5.0.2-sentinel/
├── 7501
│   └── redis-7501.conf
├── 7502
│   └── redis-7502.conf
├── 7503
│   └── redis-7503.conf
├── 7504
│   └── redis-7504.conf
├── 7505
│   └── sentinel-7505.conf
├── 7506
│   └── sentinel-7506.conf
└── 7507
    └── sentinel-7507.conf

③ 依次从之前安装的 Redis 目录下拷贝 redis.conf 至 /usr/local/redis-5.0.2-sentinel/7501/redis-7501.conf, /usr/local/redis-5.0.2-sentinel/7502/redis-7502.conf, /usr/local/redis-5.0.2-sentinel/7503/redis-7503.conf, /usr/local/redis-5.0.2-sentinel/7504/redis-7504.conf:

cp ./redis-5.0.2/redis.conf ./redis-5.0.2-sentinel/7501/redis-7501.conf
cp ./redis-5.0.2/redis.conf ./redis-5.0.2-sentinel/7502/redis-7502.conf
cp ./redis-5.0.2/redis.conf ./redis-5.0.2-sentinel/7503/redis-7503.conf
cp ./redis-5.0.2/redis.conf ./redis-5.0.2-sentinel/7504/redis-7504.conf

④ 依次更改配置文件, 主要涉及端口, 日志文件, 工作目录等配置, 以 7501 举例:

port=7501
# 支持后台 (守护进程) 的方式运行
daemonize=yes
pidfile=/var/run/redis_7501.pid
# 需要注意的是: 如果设置成 ./redis-7501.log, 则实际日志文件的存放位置是相对路径, 相对的是你执行 redis-server <the-path-of-config-file> 命令的路径
logfile="/usr/local/redis-5.0.2-sentinel/7501/redis-7501.log"
dir="/usr/local/redis-5.0.2-sentinel/7501"
# 当前实例的密钥
requirepass=redis-cluster-pass
# master 节点的密钥, 由于要执行主备切换, requirepass 和 masterauth 应该一致
masterauth=redis-cluster-pass
appendonly=yes

⑤ 分别启动 4 个 Redis Instance:

redis-server /usr/local/redis-5.0.2-sentinel/7501/redis-7501.conf 
redis-server /usr/local/redis-5.0.2-sentinel/7502/redis-7502.conf 
redis-server /usr/local/redis-5.0.2-sentinel/7503/redis-7503.conf 
redis-server /usr/local/redis-5.0.2-sentinel/7504/redis-7504.conf 

⑥ 设置主从关系, 也可以在 redis-<port>.conf 中通过 replicaof 配置:

[root@VM-0-9-centos ~]# redis-cli -h 127.0.0.1 -p 7502
127.0.0.1:7502> auth redis-cluster-pass
OK
127.0.0.1:7502> SLAVEOF 127.0.0.1 7501
OK
127.0.0.1:7502> exit
[root@VM-0-9-centos ~]# redis-cli -h 127.0.0.1 -p 7503
127.0.0.1:7503> auth redis-cluster-pass
OK
127.0.0.1:7503> SLAVEOF 127.0.0.1 7501
OK
127.0.0.1:7503> exit
[root@VM-0-9-centos ~]# redis-cli -h 127.0.0.1 -p 7504
127.0.0.1:7504> auth redis-cluster-pass
OK
127.0.0.1:7504> SLAVEOF 127.0.0.1 7501
OK
127.0.0.1:7504> exit
[root@VM-0-9-centos ~]# 

⑦ cli 登陆 master 节点, 查看 Redis Instance 状态:

[root@VM-0-9-centos redis-5.0.2-sentinel]# redis-cli -h 127.0.0.1 -p 7501
127.0.0.1:7501> auth redis-cluster-pass
OK
127.0.0.1:7501> info replication
# Replication
role:master
connected_slaves:3
slave0:ip=127.0.0.1,port=7502,state=online,offset=644,lag=1
slave1:ip=127.0.0.1,port=7503,state=online,offset=644,lag=1
slave2:ip=127.0.0.1,port=7504,state=online,offset=644,lag=1
master_replid:6d8140a2963cbc57a7799c2300d9c08f125d4924
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:644
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:644
127.0.0.1:7501> 

Redis Sentinel 配置

① 将之前安装文件夹下的 sentinel.conf 一次拷贝到 /usr/local/redis-5.0.2-sentinel/7505/sentinel-7505.conf, /usr/local/redis-5.0.2-sentinel/7506/sentinel-7506.conf, /usr/local/redis-5.0.2-sentinel/7507/sentinel-7507.conf:

cp ./redis-5.0.2/sentinel.conf ./redis-5.0.2-sentinel/7505/sentinel-7505.conf
cp ./redis-5.0.2/sentinel.conf ./redis-5.0.2-sentinel/7506/sentinel-7506.conf
cp ./redis-5.0.2/sentinel.conf ./redis-5.0.2-sentinel/7507/sentinel-7507.conf

② 修改配置文件, 以 7505 为例:

# 需要在 Sentinel 的配置文件中指定 Sentinel 的密钥
# 如果不做这个操作, 在 SpringBoot 集成的时候, Redis Instance 有密钥保护, 而 Redis Sentinel 没有: 
#   application.yml 如果不设置密钥, 会报错: NOAUTH Authentication required.
#   application.yml 设置了密钥又囧报: ERR Client sent AUTH, but no password is set
requirepass="redis-cluster-pass"

port=7505
daemonize=yes
pidfile=/var/run/redis-sentinel-7505.pid
logfile="/usr/local/redis-5.0.2-sentinel/7505/sentinel-7505.log"
dir="/usr/local/redis-5.0.2-sentinel/7505"
# 默认将主节点设置为 7501, 
#   redis-5.0.2-master 是别名;
#   2 表示只要有 2 个 Sentinel 赞同, 就执行故障转移 (主备切换), 这个数字不能大于 Sentinel 的个数
sentinel=monitor redis-5.0.2-master 127.0.0.1 7501 2
# 主节点的访问信息
sentinel=auth-pass redis-5.0.2-master redis-cluster-pass

③ 启动 3 个哨兵:

[root@VM-0-9-centos redis-5.0.2-sentinel]# redis-sentinel 7505/sentinel-7505.conf 
[root@VM-0-9-centos redis-5.0.2-sentinel]# redis-sentinel 7506/sentinel-7506.conf 
[root@VM-0-9-centos redis-5.0.2-sentinel]# redis-sentinel 7507/sentinel-7507.conf 
[root@VM-0-9-centos redis-5.0.2-sentinel]# ps -ef | grep redis
root      6625     1  0 01:09 ?        00:00:00 redis-server 0.0.0.0:7501
root      6644     1  0 01:09 ?        00:00:00 redis-server 0.0.0.0:7502
root      6664     1  0 01:09 ?        00:00:00 redis-server 0.0.0.0:7503
root      6677     1  0 01:09 ?        00:00:00 redis-server 0.0.0.0:7504
root      7694     1  0 01:15 ?        00:00:00 redis-sentinel *:7505 [sentinel]
root      7714     1  0 01:15 ?        00:00:00 redis-sentinel *:7506 [sentinel]
root      7744     1  0 01:15 ?        00:00:00 redis-sentinel *:7507 [sentinel]
root      7841 27334  0 01:16 pts/0    00:00:00 grep --color=auto redis
[root@VM-0-9-centos redis-5.0.2-sentinel]#

测试

① 登陆主节点, 设置一个 KeyValue, 可以看到从节点也有对应的记录 (默认主节点可读写, 从节点只可读):

[root@VM-0-9-centos local]# redis-cli -h 127.0.0.1 -p 7501
127.0.0.1:7501> auth  redis-cluster-pass
OK
127.0.0.1:7501> set foo bar
OK
127.0.0.1:7501> exit
[root@VM-0-9-centos local]# redis-cli -h 127.0.0.1 -p 7503
127.0.0.1:7503> get foo
(error) NOAUTH Authentication required.
127.0.0.1:7503> auth redis-cluster-pass
OK
127.0.0.1:7503> get foo
"bar"
127.0.0.1:7503> exit

② 接下来我们 kill 掉主节点试试:

[root@VM-0-9-centos ~]# ps -ef | grep redis
root      6625     1  0 01:09 ?        00:00:23 redis-server 0.0.0.0:7501
root      6644     1  0 01:09 ?        00:00:22 redis-server 0.0.0.0:7502
root      6664     1  0 01:09 ?        00:00:22 redis-server 0.0.0.0:7503
root      6677     1  0 01:09 ?        00:00:22 redis-server 0.0.0.0:7504
root      7694     1  0 01:15 ?        00:00:42 redis-sentinel *:7505 [sentinel]
root      7714     1  0 01:15 ?        00:00:42 redis-sentinel *:7506 [sentinel]
root      7744     1  0 01:15 ?        00:00:42 redis-sentinel *:7507 [sentinel]
root     29385 29280  0 09:43 pts/0    00:00:00 grep --color=auto redis
[root@VM-0-9-centos ~]# kill -9 6625
[root@VM-0-9-centos ~]# ps -ef | grep redis
root      6644     1  0 01:09 ?        00:00:22 redis-server 0.0.0.0:7502
root      6664     1  0 01:09 ?        00:00:22 redis-server 0.0.0.0:7503
root      6677     1  0 01:09 ?        00:00:22 redis-server 0.0.0.0:7504
root      7694     1  0 01:15 ?        00:00:42 redis-sentinel *:7505 [sentinel]
root      7714     1  0 01:15 ?        00:00:42 redis-sentinel *:7506 [sentinel]
root      7744     1  0 01:15 ?        00:00:42 redis-sentinel *:7507 [sentinel]
root     30638 29280  0 09:50 pts/0    00:00:00 grep --color=auto redis
[root@VM-0-9-centos ~]# redis-cli -h 127.0.0.1 -p 7502
127.0.0.1:7502> auth redis-cluster-pass
OK
127.0.0.1:7502> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:7504
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:6511835
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:c60c6880cb9054c543a8472adf73432df74bf20b
master_replid2:aa1551df9635dcc155e510aaa6712cda6a7e7bff
master_repl_offset:6511835
second_repl_offset:6506247
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:5463260
repl_backlog_histlen:1048576
127.0.0.1:7502> 

可以看到 7504 已经被提升为 master 了.

③ 接下来再次启动之前的主节点:

[root@VM-0-9-centos ~]# redis-server /usr/local/redis-5.0.2-sentinel/7501/redis-7501.conf
[root@VM-0-9-centos ~]# redis-cli -h 127.0.0.1 -p 7501
127.0.0.1:7501> auth redis-cluster-pass
OK
127.0.0.1:7501> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:7504
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:6525162
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:c60c6880cb9054c543a8472adf73432df74bf20b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:6525162
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:6523848
repl_backlog_histlen:1315
127.0.0.1:7501> 

之前的主节点 7501 现已作为从节点工作, 从新任主节点 7501 备份数据.

SpringBoot 集成

SpringBoot 继承 Redis Sentinel Cluster 本身没什么难点, 值得一说的就是 Sentinel 的 requirepass 设置. 这里我直接引入自己的 data-redis-service-spring-boot-starter, 有兴趣的可以看看 SpringBoot 自动配置 (2) - 自己写个 Starter 二次封装 spring-boot-starter-data-redis.

配置文件方面只需要做如下配置:

spring:
  redis:
    password: redis-cluster-pass
    sentinel:
      master: redis-5.0.2-master
      nodes: 118.24.109.247:7505,118.24.109.247:7506,118.24.109.247:7507

新建测试用例:

@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisSentinelApplicationTest {

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    private RedisService redisService;

    @Test
    public void testSaving() {
        redisService.setValue(
                RedisKey.builder().prefix("temp").suffix("foo").build(),
                "bar",
                300
        );
        System.out.println("Value set...");
    }

}

启动后直接在本地客户端可以看到 4 个 Redis Instance 都有值:
在这里插入图片描述

示例源码颇为简单, 代码仓库.

总结

本文介绍了如何一步一步动手搭建 Redis Sentinel 并与 SpringBoot 整合. Sentinel 本质上也是一个独立于 Redis Instance Cluster 的分布式系统. 故障转移本质上也是通过 Sentinel 动态修改 redis.conf 实现的, 可以看到主节点挂掉之后, 从节点的配置文件都有变化.

恩~很有意思.

Reference

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值