一、解决单点故障的问题
- 主备
- 主从
二、主从复制
运行机制
-
当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。
-
当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
-
当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave
-
Redis使用默认的异步复制,其特点是低延迟和高性能,是绝大多数 Redis 用例的自然复制模式。但是,从 Redis 服务器会异步地确认其从主 Redis 服务器周期接收到的数据量。
特点
- Redis 使用异步复制,slave 和 master 之间异步地确认处理的数据量
- 一个 master 可以拥有多个 slave
- slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外, slave 之间也可以像层叠状的结构(cascading-like structure)连接到其他 slave 。自 Redis 4.0 起,所有的 sub-slave 将会从 master 收到完全一样的复制流。
- Redis 复制在 master 侧是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时,可以继续处理查询请求。
- 复制在 slave 侧大部分也是非阻塞的。当 slave 进行初次同步时,它可以使用旧数据集处理查询请求,加载新数据集的操作依然需要在主线程中进行并且会阻塞 slave
- 复制既可以被用在可伸缩性,以便只读查询可以有多个 slave 进行(例如 O(N) 复杂度的慢操作可以被下放到 slave ),或者仅用于数据安全。
- 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf 以避免对磁盘进行持久化,然后连接一个 slave ,其配置为不定期保存或是启用 AOF。但是,这个设置必须小心处理,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空
工作流程
- 当 slave 连接到 master 时,它们使用 PSYNC 命令来发送它们记录的旧的 master replication ID 和它们至今为止处理的偏移量,通过这种方式, master 能够仅发送 slave 所需的增量部分但是如果 master 的缓冲区中没有足够的命令积压缓冲记录,
- 如果 slave 引用了不再知道的历史记录(replication ID),则会转而进行一个全量重同步:在这种情况下, slave 会得到一个完整的数据集副本,从头开始。
- master 开启一个后台保存进程,以便于生产一个 RDB 文件,同时它开始缓冲所有从客户端接收到的新的写入命令
- 当后台保存完成时, master 将数据集文件传输给 slave, slave将之保存在磁盘上,然后加载文件到内存。再然后 master 会发送所有缓冲的命令发给 slave。这个过程以指令流的形式完成并且和 Redis 协议本身的格式相同。
- 如果 master 收到了多个 slave 要求同步的请求,它会执行一个单独的后台保存,以便于为多个 slave 服务。
无需要磁盘参与的复制
- 如果磁盘性能很低的话,这对 master 是一个压力很大的操作。Redis 2.8.18 是第一个支持无磁盘复制的版本。在此设置中,子进程直接发送 RDB 文件给 slave,无需使用磁盘作为中间储存介质。
- 这样对网络带宽有很大的要求
配置文件信息
默认配置
replicaof <masterip> <masterport> --> 连接到master节点的ip和端口号
例如: replicaof 127.0.0.1 6378 -->master的地址为127.0.0.1:6379
------------------------------------------------------------------------------------------------------------------------------------
# masterauth <master-password>---> 如果master有密码的时候 填写密码
------------------------------------------------------------------------------------------------------------------------------------
replica-serve-stale-data yes -->设置为yes,主从复制中,从节点可以响应客户端的请求,设置为no,主从复制中,从节点将阻塞所有请求,有客户端请求时返回 SYNC with master in progress
------------------------------------------------------------------------------------------------------------------------------------
replica-read-only yes----->设置为yes,代表为只读节点,但并不表示客户端用集群方式以从节点为入口连入集群时,不可以进行 set 操作,且 set 操作的数据不会被放在从节点的槽上,会被放到某主节点的槽上
------------------------------------------------------------------------------------------------------------------------------------
如何处理过期的key
- Redis slaves 能正确地复制具有过期时间的 key。
- Redis 不能依靠主从使用同步时钟。会产生一个无法解决的并且会导致 race condition 和数据集不一致的问题
- slave 不会让 key 过期,而是等待 master 让 key 过期。当一个 master 让一个 key 到期(或由于 LRU 算法将之驱逐)时,它会合成一个 DEL 命令并传输到所有的 slave
- 但是,由于这是 master 驱动的 key 过期行为,master 无法及时提供 DEL 命令,所以有时候 slave 的内存中仍然可能存在在逻辑上已经过期的 key 。为了处理这个问题,slave 使用它的逻辑时钟以报告只有在不违反数据集的一致性的读取操作(从主机的新命令到达)中才存在 key。用这种方法,slave 避免报告逻辑过期的 key 仍然存在。在实际应用中,使用 slave 程序进行缩放的 HTML 碎片缓存,将避免返回已经比期望的时间更早的数据项。
- 在Lua脚本执行期间,不执行任何 key 过期操作。当一个Lua脚本运行时,从概念上讲,master 中的时间是被冻结的,这样脚本运行的时候,一个给定的键要么存在要么不存在。这可以防止 key 在脚本中间过期,保证将相同的脚本发送到 slave ,从而在二者的数据集中产生相同的效果。
- 一旦一个 slave 被提升为一个 master ,它将开始独立地过期 key,而不需要任何旧 master 的帮助。
重新启动和故障转移后的部分重同步
- 当一个实例在故障转移后被提升为 master 时,它仍然能够与旧 master 的 slaves 进行部分重同步
- slave 会记住旧 master 的旧 replication ID 和复制偏移量,因此即使询问旧的 replication ID,其也可以将部分复制缓冲提供给连接的 slave 。
三、高可用---Sentinel
说明
- Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。
- 虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。
做的任务
- 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
- 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
配置文件
运行一个 Sentinel 所需的最少配置
sentinel monitor mymaster 127.0.0.1 6379 2-->配置烧饼去监视一个名称为mymaster的主服务,这个主服务的ip地址为127.0.0.1 端口号为6379 ,而且这个主服务判断失效至少需要2个哨兵同意(哨兵数据不够,自动故障迁移就不会执行)
------------------------------------------------------------------------------
sentinel down-after-milliseconds mymaster 60000--> 指定了哨兵任务服务器已经断线所需要的毫秒数,如果在指定的时间内。没有返回给哨兵命令的回复,或者错误,那么哨兵就会将这个服务标记为主观下线
------------------------------------------------------------------------------
sentinel failover-timeout mymaster 180000-->
------------------------------------------------------------------------------
sentinel parallel-syncs mymaster 1--> 指定了早执行故障转移时,最多可以有多少个从节点同时以新的主服务器进行同步,这个数字越小,完成故障转移所需要的时间越长
------------------------------------------------------------------------------
sentinel monitor resque 192.168.1.3 6380 4-->
------------------------------------------------------------------------------
sentinel down-after-milliseconds resque 10000-->
------------------------------------------------------------------------------
sentinel failover-timeout resque 180000-->
------------------------------------------------------------------------------
sentinel parallel-syncs resque 5-->
------------------------------------------------------------------------------
主观下线和客观下线
- 主观下线(SDOWN)指的是单个Sentinel实例对服务器做出的下线判断
- 客观下线(ODOWN)指的是多个Sentinel实例在对同一个服务器做出SDOWN判断,并且通过选举的方式之后,得出的服务器下线判断。
- 客观下线条件只适用于主服务器,对于从节点的redis实例,Sentinel在将他们判断下线之前是不需要协商的,所以从节点永远不会达到客观下线的条件
- 只要一个Sentinel发现主节点的服务进入客观下线状态,这个Sentinel就可能会被其他的Sentinel推选出,并对失效的主节点执行自动故障迁移操作
自动发现从节点和其他的Sentinel
- 从节点启动时设置追随的主节点后,主节点会记录有哪些从节点追随,当Sentinel-1监听主节点的时候,根据主节点已知的那些从节点,也会将从节点进行监控,而Sentinel-2和Sentinel-3也监控主节点的时候,三个Sentinel也是相互知道的,他们是基于redis的发布订阅来知道彼此的存在
自动迁移的步骤
- 发现主服务器已经进入客观下线状态。
- 对我们的当前纪元进行自增(详情请参考 Raft leader election ), 并尝试在这个纪元中当选
- 如果当选失败, 那么在设定的故障迁移超时时间的两倍之后, 重新尝试当选。 如果当选成功, 那么执行以下步骤
- 选出一个从服务器,并将它升级为主服务器
- 向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器。
- 通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel , 其他 Sentinel 对它们自己的配置进行更新。
- 向已下线主服务器的从服务器发送 SLAVEOF 命令, 让它们去复制新的主服务器。
- 当所有从服务器都已经开始复制新的主服务器时, 领头 Sentinel 终止这次故障迁移操作。
Sentinel 自动故障迁移的一致性特质
- Sentinel 自动故障迁移使用 Raft 算法来选举领头(leader) Sentinel , 从而确保在一个给定的纪元(epoch)里, 只有一个领头产生。
- 更高的配置纪元总是优于较低的纪元, 因此每个 Sentinel 都会主动使用更新的纪元来代替自己的配置。
- 我们可以将 Sentinel 配置看作是一个带有版本号的状态。 一个状态会以最后写入者胜出(last-write-wins)的方式(也即是,最新的配置总是胜出)传播至所有其他 Sentinel 。