Redis分布式集群方案

mac2024-05-10  8

1 为什么要搭建Redis集群

我们知道单线程的Redis性能已经很高了,但实际应用中我们还是要搭建Redis集群,原因主要有三点:

可用性和安全性方面,单机的Redis服务一旦宕机,会造成服务不可用,严重的会丢失数据,造成不可估量的损失。存储数据有限,Redis是内存数据库,如果数据量大容易受到硬件条件限制。吞吐量性能考虑,单机的Redis性能虽高,但如果在高并发场景下,性能还是会受到影响。

2 Redis主从复制

2.1 主从复制配置

在每个 slave 节点的 redis.conf 配置文件增加一行 slaveof 192.168.8.203 6379 在主从切换的时候,这个配置会被重写成: replicaof 192.168.8.203 6379 或者在启动服务时通过参数指定 master 节点: ./redis-server --slaveof 192.168.8.203 6379 或在客户端直接执行 slaveof xx xx,使该 Redis 实例成为从节点。 启动后,查看集群状态:

redis> info replication

从节点不能写入数据(只读),只能从 master 节点同步数据。 主节点写入后,slave 会自动从 master 同步数据。

2.2 主从复制原理

2.2.1 连接阶段
slave node 启动时(执行 slaveof 命令),会在自己本地保存 master node 的 信息,包括 master node 的 host 和 ip。slave node 内部有个定时任务 replicationCron(源码 replication.c),每隔 1 秒钟检查是否有新的 master node 要连接和复制,如果发现,就跟 master node 建立 socket 网络连接,如果连接成功,从节点为该 socket 建立一个专门处理复制工作的文件 事件处理器,负责后续的复制工作,如接收 RDB 文件、接收命令传播等。 当从节点变成了主节点的一个客户端之后,会给主节点发送 ping 请求。
2.2.2 数据同步阶段
master node 第一次执行全量复制,通过 bgsave 命令在本地生成一份 RDB 快 照,将 RDB 快照文件发给 slave node(如果超时会重连,可以调大 repl-timeout 的值)。 slave node 首先清除自己的旧数据,然后用 RDB 文件加载数据。

问题: 生成 RDB 期间,master 接收到的命令怎么处理? 开始生成 RDB 文件时,master 会把所有新的写命令缓存在内存中。在 slave node。保存了 RDB 之后,再将新的写命令复制给 slave node。

2.2.3 命令传播阶段
master node 持续将写命令,异步复制给 slave node 延迟是不可避免的,只能通过优化网络。

repl-disable-tcp-nodelay no 当设置为 yes 时,TCP 会对包进行合并从而减少带宽,但是发送的频率会降低,从 节点数据延迟增加,一致性变差;具体发送频率与 Linux 内核的配置有关,默认配置为 40ms。当设置为 no 时,TCP 会立马将主节点的数据发送给从节点,带宽增加但延迟变 小。

一般来说,只有当应用对 Redis 数据不一致的容忍度较高,且主从节点之间网络状 况不好时,才会设置为 yes;多数情况使用默认值 no。 问题: 如果从节点有一段时间断开了与主节点的连接是不是要重新全量复制一遍? 如果可以增量复制,怎么知道上次复制到哪里? 通过 master_repl_offset 记录的偏移量

2.3 主从复制的不足

主从模式解决了数据备份和性能(通过读写分离)的问题,但是还是存在一些不足:

RDB 文件过大的情况下,同步非常耗时。在一主一从或者一主多从的情况下,如果主服务器挂了,对外提供的服务就不可 用了,单点问题没有得到解决。如果每次都是手动把之前的从服务器切换成主服务器, 这个比较费时费力,还会造成一定时间的服务不可用。

3 可用性保证之 哨兵机制Sentinel

3.1 Sentinel 原理

如何实现主从的自动切换?我们的思路: 创建一台监控服务器来监控所有 Redis 服务节点的状态,比如,master 节点超过一 定时间没有给监控服务器发送心跳报文,就把 master 标记为下线,然后把某一个 slave 变成 master。应用每一次都是从这个监控服务器拿到 master 的地址。

问题: 如果监控服务器本身出问题了怎么办?那我们就拿不到 master 的地址了, 应用也没有办法访问。 那我们再创建一个监控服务器,来监控监控服务器……似乎陷入死循环了,这个问题 怎么解决?这个问题先放着。 Redis 的 Sentinel 就是这种思路:通过运行监控服务器来保证服务的可用性。 从 Redis2.8 版本起,提供了一个稳定版本的 Sentinel(哨兵),用来解决高可用的 问题。它是一个特殊状态的 redis 实例。 我们会启动一个或者多个 Sentinel 的服务(通过 src/redis-sentinel),它本质上只 是一个运行在特殊模式之下的 Redis,Sentinel 通过 info 命令得到被监听 Redis 机器的 master,slave 等信息。 为了保证监控服务器的可用性,我们会对 Sentinel 做集群的部署。Sentinel 既监控 所有的 Redis 服务,Sentinel 之间也相互监控。 注意:Sentinel 本身没有主从之分,只有 Redis 服务节点有主从之分。 概念梳理:master,slave(redis group),sentinel,sentinel 集合。

3.1.1 服务下线

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

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

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

3.1.2 故障转移

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

问题: 怎么让一个原来的 slave 节点成为主节点? 1、选出 Sentinel Leader 之后,由 Sentinel Leader 向某个节点发送 slaveof no one 命令,让它成为独立节点。 2、然后向其他节点发送 slaveof x.x.x.x xxxx(本机服务),让它们成为这个节点的 子节点,故障转移完成。 问题: 这么多从节点,选谁成为主节点? 关于从节点选举,一共有四个因素影响选举的结果,分别是断开连接时长、优先级 排序、复制数量、进程 id。 如果与哨兵连接断开的比较久,超过了某个阈值,就直接失去了选举权。如果拥有 选举权,那就看谁的优先级高,这个在配置文件里可以设置(replica-priority 100), 数值越小优先级越高。 如果优先级相同,就看谁从 master 中复制的数据最多(复制偏移量最大),选最多 的那个,如果复制数量也相同,就选择进程 id 最小的那个。

3.2 Sentinel 的功能总结

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

最新回复(0)