Redis可用性保证之Sentinel

Sentinel 原理(官网

通过运行监控服务器来保证服务的可用性

从 Redis2.8 版本起,提供了一个稳定版本的 Sentinel(哨兵),用来解决高可用的问题。它是一个特殊状态的 redis 实例。

 

我们会启动一个或者多个 Sentinel 的服务(通过 src/redis-sentinel),它本质上只是一个运行在特殊模式之下的 Redis,Sentinel 通过 info 命令得到被监听 Redis 机器的master,slave 等信息。

为了保证监控服务器的可用性,我们会对 Sentinel 做集群的部署。Sentinel 既监控所有的 Redis 服务,Sentinel 之间也相互监控

注意:Sentinel 本身没有主从之分,只有 Redis 服务节点有主从之分

服务下线

Sentinel 默认以每秒钟 1 次的频率向 Redis 服务节点发送 PING 命令。如果在down-after-milliseconds 内都没有收到有效回复,Sentinel 会将该服务器标记为下线(主观下线

# sentinel.conf
sentinel down-after-milliseconds <master-name> <milliseconds>

这个时候 Sentinel 节点会继续询问其他的 Sentinel 节点,确认这个节点是否下线,如果多数 Sentinel 节点都认为 master 下线,master 才真正确认被下线(客观下线),这个时候就需要重新选举 master

 

故障转移

如果 master 被标记为下线,就会开始故障转移流程

既然有这么多的 Sentinel 节点,由谁来做故障转移的事情呢?
故障转移流程的第一步就是在 Sentinel 集群选择一个 Leader,由 Leader 完成故障转移流程。Sentinle 通过 Raft 算法,实现 Sentinel 选举

在分布式存储系统中,通常通过维护多个副本来提高系统的可用性,那么多个节点之间必须要面对数据一致性的问题。Raft 的目的就是通过复制的方式,使所有节点达成一致,但是这么多节点,以哪个节点的数据为准呢?所以必须选出一个 Leader


大体上有两个步骤:领导选举,数据复制

Raft 是一个共识算法(consensus algorithm)。比如比特币之类的加密货币,就需要共识算法。Spring Cloud 的注册中心解决方案 Consul 也用到了 Raft 协议

Raft 的核心思想:先到先得,少数服从多数

 

Sentinle 的 Raft 算法和 Raft 论文略有不同

1、master 客观下线触发选举,而不是过了 election timeout 时间开始选举


2、Leader 并不会把自己成为 Leader 的消息发给其他 Sentinel。其他 Sentinel 等待 Leader 从 slave 选出 master 后,检测到新的 master 正常工作后,就会去掉客观下线的标识,从而不需要进入故障转移流程

  • 故障转移

怎么让一个原来的 slave 节点成为主节点?

1、选出 Sentinel Leader 之后,由 Sentinel Leader 向某个节点发送 slaveof no one命令,让它成为独立节点。
2、然后向其他节点发送 slaveof x.x.x.x xxxx(本机服务,IP:端口),让它们成为这个节点的子节点,故障转移完成。

这么多从节点,选谁成为主节点?

关于从节点选举,一共有四个因素影响选举的结果,分别是断开连接时长、优先级排序、复制数量、进程 id

如果与哨兵连接断开的比较久,超过了某个阈值,就直接失去了选举权。如果拥有选举权,那就看谁的优先级高,这个在配置文件里可以设置(replica-priority 100),数值越小优先级越高

 

如果优先级相同,就看谁从 master 中复制的数据最多(复制偏移量最大),选最多的那个,如果复制数量也相同,就选择进程 id 最小的那个

Sentinel 功能总结

  • 监控:Sentinel 会不断检查主服务器和从服务器是否正常运行
  • 通知:如果某一个被监控的实例出现问题,Sentinel 可以通过 API 发出通知
  • 自动故障转移(failover):如果主服务器发生故障,Sentinel 可以启动故障转移过程。把某台服务器升级为主服务器,并发出通知
  • 配置管理:客户端连接到 Sentinel,获取当前的 Redis 主服务器的地址

 

Sentinel 实战

Sentinel 配置

为了保证 Sentinel 的高可用,Sentinel 也需要做集群部署,集群中至少需要三个Sentinel 实例(推荐奇数个,防止脑裂

hostnameip地址节点角色&端口
master198.168.1.203Master:6379 / Sentinel:26379
slave1198.168.1.204Slave:6379 / Sentinel:26379
slave2198.168.1.205Slave:6379 / Sentinel:26379

以 Redis 安装路径/usr/local/soft/redis-5.0.5/为例

在 204 和 205 的 src/redis.conf 配置文件中添加:

slaveof 192.168.1.203 6379

在 203、204、205 创建 sentinel 配置文件(安装后根目录下默认有 sentinel.conf)

cd /usr/local/soft/redis-5.0.5

# 创建日志目录
mkdir logs 

# 创建备份目录
mkdir rdbs

mkdir sentinel-tmp

vim sentinel.conf

三台服务器编辑相同的内容(sentinel.conf)

daemonize yes

port 26379

protected-mode no

dir "/usr/local/soft/redis-5.0.5/sentinel-tmp"

sentinel monitor redis-master 192.168.1.203 6379 2

sentinel down-after-milliseconds redis-master 30000

sentinel failover-timeout redis-master 180000

sentinel parallel-syncs redis-master 1
参数说明
protected-mode是否允许外部网络访问
dirsentinel 的工作目录
sentinel monitor sentinel 监控的 redis 主节点
down-after-milliseconds(毫秒)master 宕机多久,才会被 Sentinel 主观认为下线
sentinel failover-timeout(毫秒)1.同一个 sentinel 对同一个 master 两次 failover 之间的间隔时间。
2. 当一个 slave 从一个错误的 master 那里同步数据开始计算时间。直到slave 被纠正为向正确的 master 那里同步数据时。
3.当想要取消一个正在进行的 failover 所需要的时间。
4.当进行 failover 时,配置所有 slaves 指向新的 master 所需的最大时间。
parallel-syncs 这个配置项指定了在发生 failover 主备切换时最多可以有多少个 slave 同时对新的 master 进行 同步,这个数字越小,完成 failover 所需的时间就越长,但是如果这个数字越大,就意味着越 多的 slave 因为 replication 而不可用。可以通过将这个值设为 1 来保证每次只有一个 slave 处于不能处理命令请求的状态

Sentinel 验证

启动 Redis 服务和 Sentinel

cd /usr/local/soft/redis-5.0.5/src

# 启动 Redis 节点
./redis-server ../redis.conf

# 启动 Sentinel 节点
./redis-sentinel ../sentinel.conf
# 或者
./redis-server ../sentinel.conf --sentinel

查看集群状态

redis> info replication

203机器执行

204和205机器执行

模拟 master 宕机,在 203 执行:

redis> shutdown

205 被选为新的 Master,只有一个 Slave 节点

注意: sentinel.conf 里面的 redis-master 被修改了

基于Java Sentinel 连接使用

master name 来自于 sentinel.conf 的配置

private static JedisSentinelPool createJedisPool() {
    String masterName = "redis-master";
    Set < String > sentinels = new HashSet < String > ();
    sentinels.add("192.168.1.203:26379");
    sentinels.add("192.168.1.204:26379");
    sentinels.add("192.168.1.205:26379");
    pool = new JedisSentinelPool(masterName, sentinels);
    return pool;
}

Spring Boot 连接 Sentinel

spring.redis.sentinel.master=redis-master
spring.redis.sentinel.nodes=192.168.1.203:26379,192.168.1.204:26379,192.168.1.205:26379

无论是 Jedis 还是 Spring Boot(2.x 版本默认是 Lettuce),都只需要配置全部哨兵的地址,由哨兵返回当前的 master 节点地址

哨兵机制的不足

  • 主从切换的过程中会丢失数据,因为只有一个 master
  • 只能单点写,没有解决水平扩容的问题
  • 如果数据量非常大,这个时候我们需要多个 master-slave 的 group,把数据分布到不同的 group 中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值