Redis主从复制和高可用方案

Redis 安装

下载地址:https://redis.io/download
tar xzf redis-5.0.3.tar.gz
cd redis-5.0.3
make

启动脚本

src/redis-server

主从复制方案

从的配置文件修改

#replicaof <masterip> <masterport>
replicaof 127.0.0.1 6379
#masterauth <master-password>
masterauth 123456
重启从的redis

从日志输出

10896:S 25 Feb 2019 16:12:33.258 * Full resync from master: e3dba16f7d2f755f59a7307ad0955a9f584f5825:0
10896:S 25 Feb 2019 16:12:33.337 * MASTER <-> REPLICA sync: receiving 175 bytes from master
10896:S 25 Feb 2019 16:12:33.337 * MASTER <-> REPLICA sync: Flushing old data
10896:S 25 Feb 2019 16:12:33.338 * MASTER <-> REPLICA sync: Loading DB in memory
10896:S 25 Feb 2019 16:12:33.338 * MASTER <-> REPLICA sync: Finished with success
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

主日志输出

6364:M 25 Feb 2019 16:12:33.337 * Synchronization with replica 127.0.0.1:6380 succeeded
  • 1

通过cli连接主的redis 添加内容

set name zhang

通过从的查找

get name
“zhang”

高可用

方案一 哨兵

  • 环境准备

redis信息

master:6739
slave 1:6780
slave 2:6781

sentinel

sentinel1 : 26739
sentinel2 : 26780
sentinel3 : 26781

  • 配置信息

master:

port 6379
masterauth 123456
requirepass “123456”

slave1:

port 6380
replicaof 127.0.0.1 6379
masterauth 123456
requirepass “123456”

slave2:

port 6381
replicaof 127.0.0.1 6379
masterauth 123456
requirepass “123456”

sentinel1 :

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 123456

注:这一行代表sentinel监控的master的名字叫做mymaster,地址为127.0.0.1:6379。这个2代表,当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。(sentinel集群中各个sentinel也有互相通信,通过gossip协议)

sentinel2 :

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 123456

sentinel3 :

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 123456

  • 启动测试

依次启动master、slave、sentinel

启动后停止master节点,可以看到slave1切换为master节点。再次启动master,变为slave2.

sentinel 配置说明

参考文档:https://segmentfault.com/a/1190000002680804

sentinel monitor mymaster 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

上面的配置项配置了两个名字分别为mymaster和resque的master,配置文件只需要配置master的信息就好啦,不用配置slave的信息,因为slave能够被自动检测到(master节点会有关于slave的消息)。需要注意的是,配置文件在sentinel运行期间是会被动态修改的,例如当发生主备切换时候,配置文件中的master会被修改为另外一个slave。这样,之后sentinel如果重启时,就可以根据这个配置来恢复其之前所监控的redis集群的状态。

sentinel monitor mymaster 127.0.0.1 6379 2

这一行代表sentinel监控的master的名字叫做mymaster,地址为127.0.0.1:6379,行尾最后的一个2代表什么意思呢?我们知道,网络是不可靠的,有时候一个sentinel会因为网络堵塞而误以为一个master redis已经死掉了,当sentinel集群式,解决这个问题的方法就变得很简单,只需要多个sentinel互相沟通来确认某个master是否真的死了,这个2代表,当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。(sentinel集群中各个sentinel也有互相通信,通过gossip协议)。

除了第一行配置,我们发现剩下的配置都有一个统一的格式:

sentinel <option_name> <master_name> <option_value>

接下来我们根据上面格式中的option_name一个一个来解释这些配置项:

  • down-after-milliseconds
    sentinel会向master发送心跳PING来确认master是否存活,如果master在“一定时间范围”内不回应PONG 或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用了(subjectively down, 也简称为SDOWN)。而这个down-after-milliseconds就是用来指定这个“一定时间范围”的,单位是毫秒。

不过需要注意的是,这个时候sentinel并不会马上进行failover主备切换,这个sentinel还需要参考sentinel集群中其他sentinel的意见,如果超过某个数量的sentinel也主观地认为该master死了,那么这个master就会被客观地(注意哦,这次不是主观,是客观,与刚才的subjectively down相对,这次是objectively down,简称为ODOWN)认为已经死了。需要一起做出决定的sentinel数量在上一条配置中进行配置。

  • parallel-syncs
    在发生failover主备切换时,这个选项指定了最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave处于不能处理命令请求的状态。

其他配置项在sentinel.conf中都有很详细的解释。
所有的配置都可以在运行时用命令SENTINEL SET command动态修改。

Sentinel的“仲裁会”

前面我们谈到,当一个master被sentinel集群监控时,需要为它指定一个参数,这个参数指定了当需要判决master为不可用,并且进行failover时,所需要的sentinel数量,本文中我们暂时称这个参数为票数

不过,当failover主备切换真正被触发后,failover并不会马上进行,还需要sentinel中的大多数sentinel授权后才可以进行failover。

当ODOWN时,failover被触发。failover一旦被触发,尝试去进行failover的sentinel会去获得“大多数”sentinel的授权(如果票数比大多数还要大的时候,则询问更多的sentinel)

这个区别看起来很微妙,但是很容易理解和使用。例如,集群中有5个sentinel,票数被设置为2,当2个sentinel认为一个master已经不可用了以后,将会触发failover,但是,进行failover的那个sentinel必须先获得至少3个sentinel的授权才可以实行failover。
如果票数被设置为5,要达到ODOWN状态,必须所有5个sentinel都主观认为master为不可用,要进行failover,那么得获得所有5个sentinel的授权。

方案二 集群

Redis Cluster提供了一种运行Redis安装的方法,其中数据 在多个Redis节点之间自动分片。
Redis Cluster还在分区期间提供一定程度的可用性,实际上是在某些节点发生故障或无法通信时继续运行的能力。但是,如果发生较大的故障(例如,当大多数主设备不可用时),群集将停止运行。

  • 能够在多个节点之间自动拆分数据集。
  • 当节点的子集遇到故障或无法与群集的其余部分通信时,能够继续操作。
    Redis群集TCP端口
    每个Redis群集节点都需要打开两个TCP连接。用于为客户端提供服务的普通Redis TCP端口,例如6379,加上通过向数据端口添加10000获得的端口,因此示例中为16379。

第二个高端口用于集群总线,即使用二进制协议的节点到节点通信通道。节点使用集群总线进行故障检测,配置更新,故障转移授权等。客户端永远不应尝试与群集总线端口通信,但始终使用正常的Redis命令端口,但请确保在防火墙中打开两个端口,否则Redis群集节点将无法通信。

命令端口和集群总线端口偏移是固定的,始终为10000。

请注意,对于每个节点,要使Redis群集正常工作,您需要:

  • 用于与客户端通信的普通客户端通信端口(通常为6379)对所有需要访问群集的客户端以及所有其他群集节点(使用客户端端口进行密钥迁移)开放。
  • 必须可以从所有其他群集节点访问群集总线端口(客户端端口+ 10000)。
  • 如果不打开两个TCP端口,则群集将无法按预期工作。

集群总线使用不同的二进制协议进行节点到节点的数据交换,这更适合于使用很少的带宽和处理时间在节点之间交换信息。

Redis群集数据分片

Redis Cluster不使用一致的散列,而是使用不同形式的分片,其中每个键在概念上都是我们称之为散列槽的一部分。
Redis集群中有16384个散列槽,为了计算给定密钥的散列槽,我们只需采用密钥模数16384的CRC16。
Redis群集中的每个节点都负责哈希槽的子集,例如,您可能拥有一个包含3个节点的群集,其中:

  • 节点A包含从0到5500的散列槽。
  • 节点B包含从5501到11000的散列槽。
  • 节点C包含从11001到16383的散列槽。

这允许轻松添加和删除集群中的节点。例如,如果我想添加一个新节点D,我需要将一些哈希槽从节点A,B,C移动到D.同样,如果我想从群集中删除节点A,我只需移动A服务的哈希槽。到B和C.当节点A为空时,我可以完全从集群中删除它。

因为将哈希槽从一个节点移动到另一个节点不需要停止操作,添加和删除节点,或者更改节点所持有的哈希槽的百分比,所以不需要任何停机时间。

只要涉及单个命令执行(或整个事务或Lua脚本执行)的所有键都属于同一个哈希槽,Redis Cluster就支持多个键操作。用户可以通过使用称为哈希标记的概念强制多个密钥成为同一哈希槽的一部分。

散列标记记录在Redis集群规范中,但要点是如果密钥中{}括号之间有子字符串,则只对字符串内部的内容进行散列,例如this{foo}key并another{foo}key 保证位于相同的散列槽中,并且可以在具有多个键作为参数的命令中一起使用。

Redis Cluster主从模型

为了在主节点子集发生故障或无法与大多数节点通信时保持可用,Redis Cluster使用主从模型,其中每个散列槽从1(主机本身)到N个副本(N) -1个额外的从节点)。
在具有节点A,B,C的示例群集中,如果节点B发生故障,则群集无法继续,因为我们不再能够在5501-11000范围内提供服务哈希位置的方法。
然而,当创建集群时(或稍后),我们向每个主节点添加一个从节点,以便最终集群由作为主节点的A,B,C和作为从节点的A1,B1,C1组成。 ,如果节点B出现故障,系统就能继续运行。
节点B1复制B,B失败,集群将节点B1升级为新的主节点,并将继续正常运行。
但请注意,如果节点B和B1同时发生故障,Redis Cluster将无法继续运行。

Redis群集一致性保证

Redis Cluster无法保证强一致性。实际上,这意味着在某些条件下,Redis Cluster可能会丢失系统向客户端确认的写入。

Redis Cluster可能丢失写入的第一个原因是它使用异步复制。这意味着在写入期间会发生以下情况:

  • 您的客户端写入主B.
  • 主人B向您的客户回复确定。
  • 主设备B将写入传播到其从设备B1,B2和B3。

正如你所看到的,B在回复客户端之前并没有等待来自B1,B2,B3的确认,因为这对Redis来说是一个过高的延迟惩罚,所以如果你的客户端写了一些内容,B会确认写入,但是在崩溃之前崩溃能够将写入发送到其从属,其中一个从属(没有接收到写入)可以被提升为主,永远丢失写入。

这与配置为每秒将数据刷新到磁盘的大多数数据库所发生的情况非常相似,因此,由于过去使用不涉及分布式系统的传统数据库系统的经验,因此您已经能够推断这种情况。同样,您可以通过在回复客户端之前强制数据库刷新磁盘上的数据来提高一致性,但这通常会导致性能过低。在Redis Cluster的情况下,这相当于同步复制。

基本上需要在性能和一致性之间进行权衡。

Redis Cluster在绝对需要时支持同步写入,通过WAIT命令实现,这使得丢失写入的可能性大大降低,但请注意,即使使用同步复制,Redis Cluster也不会实现强一致性:在更复杂的情况下总是可以实现失败场景,无法接收写入的从站被选为主站。

还有另一个值得注意的情况是,Redis群集将丢失写入,这种情况发生在网络分区中,其中客户端与少数实例(至少包括主服务器)隔离。

以6个节点簇为例,包括A,B,C,A1,B1,C1,3个主站和3个从站。还有一个客户,我们称之为Z1。

在发生分区之后,可能在分区的一侧有A,C,A1,B1,C1,在另一侧有B和Z1。

Z1仍然可以写入B,它将接受其写入。如果分区在很短的时间内恢复,群集将继续正常运行。但是,如果分区持续足够的时间使B1在分区的多数侧被提升为主,则Z1发送给B的写入将丢失。

请注意,Z1将能够发送到B的写入量存在最大窗口:如果分区的多数方面已经有足够的时间将从属设备选为主设备,则少数端的每个主节点都会停止接受写入。

这段时间是Redis Cluster的一个非常重要的配置指令,称为节点超时。

节点超时过后,主节点被视为失败,可以由其中一个副本替换。类似地,在节点超时已经过去而主节点无法感知大多数其他主节点之后,它进入错误状态并停止接受写入。

Redis群集配置参数

我们即将创建一个示例集群部署。在继续之前,让我们介绍Redis Cluster在redis.conf文件中引入的配置参数。有些人会很明显,有些人会在你继续阅读时更清楚。

  • cluster-enabled<yes/no>:如果是,则在特定Redis实例中启用Redis群集支持。否则,实例像往常一样作为独立实例启动。
  • cluster-config-file:请注意,尽管有此选项的名称,但这不是用户可编辑的配置文件,而是每次发生更改时Redis群集节点自动保持群集配置(基本上是状态)的文件,为了能够在启动时重新阅读它。该文件列出了集群中其他节点,状态,持久变量等内容。由于某些消息接收,通常会将此文件重写并刷新到磁盘上。
  • cluster-node-timeout:Redis群集节点不可用的最长时间,不会被视为失败。如果主节点的可访问时间超过指定的时间,则其从属节点将进行故障转移。此参数控制Redis群集中的其他重要事项。值得注意的是,在指定时间内无法访问大多数主节点的每个节点都将停止接受查询。
  • cluster-slave-validity-factor:如果设置为零,则从站将始终尝试对主站进行故障切换,而不管主站和从站之间的链路是否保持断开连接的时间长短。如果该值为正,则计算最大断开时间作为节点超时值乘以此选项提供的因子,如果节点是从属节点,则如果主链接断开连接的时间超过指定的时间,则不会尝试启动故障转移。例如,如果节点超时设置为5秒,并且有效性因子设置为10,则从主设备断开超过50秒的从设备将不会尝试故障转移其主设备。请注意,如果没有从站能够对其进行故障转移,则任何不同于零的值都可能导致Redis群集在主站发生故障后不可用。在这种情况下,只有当原始主服务器重新加入群集时,群集才会返回。
  • cluster-migration-barrier:主服务器将保持连接的最小从服务器数,以便另一个从服务器迁移到不再由任何从服务器覆盖的主服务器。有关详细信息,请参阅本教程中有关副本迁移的相应部分。
    cluster-require-full-coverage<yes/no>:如果设置为yes,则默认情况下,如果任何节点未覆盖某个百分比的密钥空间,则集群将停止接受写入。如果该选项设置为no,即使只能处理有关键子集的请求,群集仍将提供查询。

创建和使用Redis群集

要创建集群,我们首先要做的是在集群模式下运行一些空的Redis实例。这基本上意味着不使用普通的Redis实例创建集群,因为需要配置特殊模式,以便Redis实例启用集群特定的功能和命令。

最小的Redis群集配置文件

port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

正如您所看到的,启用集群模式的只是cluster-enabled 指令。每个实例还包含存储此节点配置的文件路径,默认情况下为nodes.conf。它只是在Redis Cluster实例启动时生成,并在每次需要时更新。

cat nodes-30001.conf
ad7957bb9d7194de7bbb16a915130aed43429ecf :0@0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0

ad7957bb9d7194de7bbb16a915130aed43429ecf :节点ID 唯一

请注意,按预期工作的最小群集需要包含至少三个主节点。对于您的第一次测试,强烈建议启动具有三个主设备和三个从设备的六节点集群。

为此,请输入一个新目录,并创建以我们将在任何给定目录中运行的实例的端口号命名的以下目录

手动
  • 准备

mkdir cluster-test
cd cluster-test
mkdir 7000 7001 7002 7003 7004 7005

cp …/…/redis.conf ./7000
修改配置文件,遵循最小配置单元修改

  • 启动redis服务

…/src/redis-server ./7000/redis.conf

  • 执行命令 构建集群

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
–cluster-replicas 1

这里使用的命令是create,因为我们想要创建一个新的集群。该选项–cluster-replicas 1意味着我们希望每个创建的主服务器都有一个从服 其他参数是我要用于创建新集群的实例的地址列表。

显然,我们要求的唯一设置是创建一个包含3个主服务器和3个从服务器的集群。

Redis-cli将为您提供配置。键入yes接受建议的配置。将配置并加入群集,这意味着实例将被引导为彼此通信。最后,如果一切顺利,你会看到这样的消息:

[OK] All 16384 slots covered

这意味着至少有一个主实例为16384个可用插槽提供服务。

自动

如果您不想通过如上所述手动配置和执行单个实例来创建Redis群集,则可以使用更简单的系统(但您不会学习相同数量的操作详细信息)。

只需检查utils/create-clusterRedis发行版中的目录即可。create-cluster内部有一个脚本(与其包含的目录同名),它是一个简单的bash脚本。要启动具有3个主服务器和3个从服务器的6节点集群,只需键入以下命令:

create-cluster start
create-cluster create

start:创建redis的实例;create:创建集群

当redis-cli实用程序希望您接受群集布局时,回复"yes"。

您现在可以与群集交互,默认情况下,第一个节点将从端口30001开始。完成后,使用以下命令停止群集:

create-cluster stop。

管理

#查看集群的节点信息
redis-cli -c -p 30001 cluster nodes

参考文档: https://redis.io/topics/cluster-tutorial

posted @ 2019-09-24 15:56  门罗的魔术师  阅读(196)  评论(0编辑  收藏  举报