Redis-Serie (4) - geschnittener Cluster

Serienspalte: Redis-Serienspalte

Slice-Cluster

Datenerweiterungsmodus

Wenn die Gesamtmenge der von Redis zwischenzuspeichernden Daten nicht sehr groß ist, z. B. 5 GB Daten, ist es im Allgemeinen ausreichend, das Master-Slave-Modell + Sentinel-Cluster zu verwenden, um eine hohe Verfügbarkeit sicherzustellen. Wenn jedoch die Gesamtmenge der von Redis zwischenzuspeichernden Daten relativ groß ist oder in Zukunft zunehmen kann, beispielsweise 20 GB oder 50 GB Daten, dann kann eine Hauptdatenbank nicht zufrieden sein.Zu diesem Zeitpunkt gibt es im Allgemeinen zwei Modi für Ausdehnung: vertikale Ausdehnung und horizontale Ausdehnung.

Vergrößern

Beim Hochskalieren wird die Konfiguration einer einzelnen Redis-Instanz aktualisiert, die Speicherkapazität des Servers und die Festplattenkapazität erhöht und eine höher konfigurierte CPU verwendet. Zum Beispiel, die zuvor verwendete 4C 8GB 50GB, aktualisiert auf 8C 32GB 100GB, und die Datenmenge steigt, weiterhin Konfiguration hinzufügen.

Der Vorteil der Skalierung ist die einfache Implementierung, aber es gibt potenzielle Probleme:

  • Wenn RDB-Datenpersistenz verwendet wird, steigt mit zunehmender Datenmenge einerseits auch der benötigte Arbeitsspeicher, andererseits wird bei Persistenz von RDB der Haupt-Thread den untergeordneten Prozess forken, und dies wird zeitaufwändig Die Fork-Operation und die Datenmenge in Redis Es ist positiv korreliert: Je größer die Datenmenge, desto länger wird der Haupt-Thread durch die Fork-Operation blockiert, was dazu führt, dass Redis die Antwort manchmal verlangsamt. Dieses Problem besteht natürlich nicht, wenn keine RDB-Persistenz erforderlich ist.

  • Ein weiteres Problem stellt die durch Hardware und Kosten begrenzte vertikale Erweiterung dar. Es ist einfach, den Arbeitsspeicher von 32 GB auf 64 GB zu erweitern, aber wenn Sie auf 1 TB erweitern möchten, werden Sie mit Hardwarekapazitäts- und Kostenbeschränkungen konfrontiert.

Aufskalieren

Die horizontale Erweiterung besteht darin, die Anzahl der Redis-Instanzen zu erhöhen und Daten auf jede Instanz zu verteilen. Um beispielsweise 15 GB Daten zwischenzuspeichern, können Sie drei 8-GB-Server verwenden, und eine Instanz muss nur 5 GB Daten zwischenspeichern.

Das ist Redis 切片集群, auch Sharded Cluster genannt, das mehrere Redis-Instanzen starten soll, um einen Cluster zu bilden, und dann die empfangenen Daten nach bestimmten Regeln auf die einzelnen Instanzen aufzuteilen. Diese Lösung muss nur die Anzahl der Redis-Instanzen erhöhen, ohne sich Gedanken über die Hardware- und Kostenbeschränkungen einer einzelnen Instanz machen zu müssen.

Obwohl es mühsam ist, einen Sliced ​​Cluster einzurichten, kann er eine große Datenmenge speichern.Da die Datenmenge, die von einer einzelnen Instanz gespeichert wird, gering ist, ist auch die blockierende Wirkung auf den Haupt-Thread während der RDB-Persistenz relativ gering. Und mit der Erweiterung der Benutzer- oder Unternehmensgröße ist es normalerweise unvermeidlich, eine große Datenmenge zu speichern, dann ist Sliced ​​Cluster eine sehr gute Lösung.

Cluster-Architektur

Der Einsatz von Redis hat im Allgemeinen je nach Szenario unterschiedliche Lösungen, hier ein einfacher Vergleich:

  • 1. Standalone-Modus

Wenn die Datenmenge klein ist, wird es hauptsächlich für Szenarien mit hoher Parallelität und hoher Leistung verwendet, da der Cache in der Regel nur wenige GB beträgt und es ausreicht, eine Redis-Instanz auf einer einzelnen Maschine bereitzustellen.

  • 2. Master-Slave-Replikation + Sentinel

Dieser Modus dient hauptsächlich dazu, hohe gleichzeitige Lese- und Hochverfügbarkeitsszenarien zu gewährleisten.Der Master-Slave-Modus ist eine Master-Bibliothek + mehrere Slave-Bibliotheken.Das Bereitstellen mehrerer Slave-Bibliotheken hängt mit dem Lesedurchsatz zusammen und dann das Bereitstellen eines Sentinel-Clusters, um die Hochverfügbarkeit des Masters sicherzustellen aus dem Cluster. Im Allgemeinen kann dieser Modus in Szenarien verwendet werden, in denen die Datenmenge nicht besonders groß ist.

  • 3. Cluster-Modus

Im Master-Slave-Architekturmodus von Redis werden alle Daten in eine Master-Bibliothek geschrieben, und es gibt einige Probleme wie die Obergrenze der Kapazität eines einzelnen Computers und eine hohe gleichzeitige Schreibleistung. Der Redis-Cluster hat mehrere Hauptbibliotheken. Die Daten werden nach bestimmten Regeln auf jede Hauptbibliothek verteilt. Die Anzahl der Hauptbibliotheken hängt von der Größe des Datenvolumens ab, und die Hauptbibliotheksknoten können entsprechend den Daten dynamisch hinzugefügt oder gelöscht werden Volumen.

Der Redis-Cluster benötigt mindestens 3 Master-Knoten, um normal zu funktionieren. Es wird empfohlen, mindestens einen Slave-Knoten für jeden Master-Knoten für die Master-Standby-Umschaltung zu konfigurieren. Wenn die Master-Bibliothek nicht verfügbar ist, kann die Slave-Bibliothek installiert werden. In der Produktionsumgebung wird empfohlen, 6 Server zu verwenden und jeweils 3 Master-Bibliotheken und 3 Slave-Bibliotheken bereitzustellen, wodurch die Hochverfügbarkeit des Clusters besser gewährleistet werden kann.

Bild.png

Anders als bei der Master-Slave-Architektur werden die Slave-Knoten im Redis-Cluster hauptsächlich für Hochverfügbarkeit verwendet.Jede Master-Bibliothek ist mit einem oder zwei Slave-Knoten für Daten-Hot-Backup und Master-Standby-Switching ausgestattet, um Hochverfügbarkeit zu erreichen.Daher in Der Cluster-Modus Die Master-Slave-Knoten benötigen keine Sentrys, um eine hohe Verfügbarkeit zu gewährleisten.

Wenn Sie außerdem die Leistung beim gleichzeitigen Lesen verbessern möchten, können Sie den Lesedurchsatz im Allgemeinen erhöhen, indem Sie den Hauptbibliotheksknoten erhöhen.Natürlich können Sie auch die Slave-Bibliothek so konfigurieren, dass sie lesbar ist, indem Sie die Konfiguration ändern und lesen -Write Separation Mode, aber das kann kompliziert sein Gleichzeitig unterstützt der Redis-Client auch die Read-Write-Separation.

Clusterbereitstellung

Stoppen Sie zunächst die zuvor bereitgestellten Redis-Master-Slave- und Sentinel-Cluster. Die Bereitstellungsmethode des Redis-Clusters unterscheidet sich von der vorherigen. Dann verwenden wir gemäß dem obigen Cluster-Architekturdiagramm drei Server, um 6 Instanzen bereitzustellen, d. h. drei Master und drei Slaves, und versuchen, die Master- und Slave-Instanzen nicht auf demselben Computer zu halten.

规划6个实例部署到三台服务器上,6个实例的端口依次为 7001 ~ 7006,部署架构如下:

服务器 Redis 实例
172.17.0.2 7001、7002
172.17.0.3 7003、7004
172.17.0.4 7005、7006

1、创建数据目录

首先在第一台服务器上操作,先创建几个目录:

# mkdir -p /var/redis/log
# mkdir -p /var/redis/7001
# mkdir -p /var/redis/7002
复制代码

2、配置文件

将Redis配置文件拷贝两份到 /etc/redis 下,分别为 7001.conf、7002.conf:

# cp /usr/local/src/redis-6.2.5/redis.conf /etc/redis/7001.conf
# cp /usr/local/src/redis-6.2.5/redis.conf /etc/redis/7002.conf
复制代码

修改配置文件中的如下配置,7001 与文件端口一致即可:

配置 说明
bind 172.17.0.2 绑定本机IP
port 7001 端口
cluster-enabled yes 开启集群模式
cluster-config-file /etc/redis/node-7002.conf 集群配置文件
cluster-node-timeout 15000 节点存活超时时长
daemonize yes 守护进程
pidfile /var/run/redis_7001.pid PID文件
dir /var/redis/7001 数据目录
logfile /var/redis/log/7001.log 日志文件
appendonly yes 开启AOF持久化

注意不要在文件中配置 replicaof <masterip> <masterport>

3、启动脚本

将Redis启动脚本复制两份到 /etc/init.d/下:

# cp /usr/local/src/redis-6.2.5/utils/redis_init_script /etc/init.d/redis_7001
# cp /usr/local/src/redis-6.2.5/utils/redis_init_script /etc/init.d/redis_7002
复制代码

然后修改脚本中的端口号:

Bild.png

并在脚本开头添加如下两行注释做开机启动:

# chkconfig: 2345 90 10 
# description: Redis is a persistent key-value database
复制代码

设置开机启动:

# chkconfig redis_7001 on
# chkconfig redis_7002 on
复制代码

4、启动Redis实例

分别安装上面的方式在三台服务器上加好配置文件和启动脚本,然后分别启动各个实例。

# cd /etc/init.d

# ./redis_7001 start
# ./redis_7002 start
复制代码

查看Redis进程:

Bild.png

如果启动不成功可以查看日志:

Bild.png

5、创建集群

集群管理可以使用官方提供的 redis-cli --cluster 工具,命令格式为:

redis-cli --cluster SUBCOMMAND [ARGUMENTS] [OPTIONS]
复制代码

创建集群的命令格式如下,--cluster-replicas <arg> 表示每个 master 有几个 slave:

redis-cli --cluster create host1:port1 ... hostN:portN --cluster-replicas <arg>
复制代码

下面将6个实例创建一个集群,它会自动帮我们分配哪些实例作为 master,哪些作为 slave,并尽量让 master 和 slave 不在同一个服务器上。通过输出结果可以看到集群创建的过程。

[root@centos-01 init.d]# redis-cli --cluster create 
    172.17.0.2:7001 172.17.0.2:7002 
    172.17.0.3:7003 172.17.0.3:7004 
    172.17.0.4:7005 172.17.0.4:7006 
    --cluster-replicas 1
    
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.17.0.3:7004 to 172.17.0.2:7001
Adding replica 172.17.0.4:7006 to 172.17.0.3:7003
Adding replica 172.17.0.2:7002 to 172.17.0.4:7005
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots:[5461-10922] (5462 slots) master
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
S: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   replicates 4e2f6532200991c93bbf23f7d4996fbd2aff02ac
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 172.17.0.2:7001)
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   slots: (0 slots) slave
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
S: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   slots: (0 slots) slave
   replicates 4e2f6532200991c93bbf23f7d4996fbd2aff02ac
M: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
复制代码

创建完成后,可以在其它实例上用 redis-cli --cluster check 检查集群状态:

[root@centos-02 init.d]# redis-cli --cluster check 172.17.0.3:7003
172.17.0.3:7003 (4e2f6532...) -> 0 keys | 5462 slots | 1 slaves.
172.17.0.4:7005 (26776d9a...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.2:7001 (9b4f3c2c...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 172.17.0.3:7003)
M: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   slots: (0 slots) slave
   replicates 4e2f6532200991c93bbf23f7d4996fbd2aff02ac
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   slots: (0 slots) slave
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
复制代码

至此,一个三台服务器 三主三从 的Redis集群就搭建好了。

集群原理

数据分布算法

切片集群是一种保存大量数据的通用机制,这个机制可以有不同的实现方案,Redis 官方提供的集群化方案为 Redis Cluster,Redis Cluster 方案中规定了数据和实例的对应规则。

哈希槽

Redis Cluster 采用哈希槽(Hash Slot)来处理数据和实例之间的映射关系,Redis Cluster 将集群划分为 16384 个槽,每个键值对都会根据它的 key,被映射到一个哈希槽中。

在创建集群时,redis-cli --cluster create 命令会自动把 16384 个槽平均分布在集群实例上,如果集群有 N 个Master,那每个Master上槽的个数为 16384 / N

通过前面创建集群的日志可以得知,每个Master对应了哪些 Slot,以及 Master -> Slave 的关系。

Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.17.0.3:7004 to 172.17.0.2:7001
Adding replica 172.17.0.4:7006 to 172.17.0.3:7003
Adding replica 172.17.0.2:7002 to 172.17.0.4:7005
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots:[5461-10922] (5462 slots) master
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
S: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   replicates 4e2f6532200991c93bbf23f7d4996fbd2aff02ac
复制代码

当然,如果某台机器内存、CPU等配置较高,我们可以给这台机器的Redis实例分配更多的槽。重新分配槽的命令为 redis-cli --cluster reshard,例如下面将 172.17.0.2:7001(..2f5ca7bf646) 上500个 Slots 移到 172.17.0.2:7003(..fbd2aff02ac) 去。

[root@centos-01 /]# redis-cli --cluster reshard 172.17.0.2:7001 
    --cluster-from 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 
    --cluster-to 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 
    --cluster-slots 500
复制代码

重新分配后,可以再用 redis-cli --cluster check 命令检查槽位配置。

槽位定位算法

Redis Cluster 默认会对 key 值使用 CRC16 算法计算得到一个 16 bit 的hash整数,然后用这个整数值对 16384 取模,得到一个 0~16383 范围内的模数,每个模数就代表一个相应编号的哈希槽,就得到了具体的槽位。

Redis Cluster 还允许用户强制某个 key 挂在特定槽位上,通过在 key 字符串里面嵌入 {tag} 标记,CRC16 就会只计算 tag 的 hash 值。例如:user_{system}、role_{system},这两个 key 都只对 system 计算 hash 值,那最终这两个 key 都会落到同一个槽上。

哈希槽的优点

Redis Cluster 不是直接维护key与实例的映射关系,而是维护了哈希槽和实例的映射关系,这就需要客户端先用 CRC16 计算key的hash值,那为什么不直接维护key与实例的映射关系呢?

  • 首先,整个集群存储key的数量是无法预估的,直接存储key与实例的映射关系,这个映射表可能会非常庞大,这个映射表无论是存储在服务端还是客户端都会占用非常大的内存空间。

  • Redis Cluster 采用去中心化的模式,每个实例会与其它实例交换自己的槽位配置,存储了整个集群完整的映射关系,如果是存储key与实例的关系,节点之间交换信息会变得庞大,消耗过多的网络资源。

  • 当集群在扩容、缩容、数据均衡时,节点之间会发生数据迁移,迁移时需要修改每个key的映射关系,维护成本高。

通过在中间增加一层哈希槽,可以把数据和节点解耦,key通过hash计算,只需要关心映射到了哪个哈希槽,然后再通过哈希槽和节点的映射表找到节点,相当于消耗了很少的CPU资源,不但让数据分布更均匀,还可以让这个映射表变得很小,利于客户端和服务端保存,节点之间交换信息时也变得轻量。在数据迁移时,都以哈希槽为基本单位进行操作,也简化了节点扩容、缩容的难度,便于集群的维护和管理。

槽位配置信息

Redis 集群中的客户端(jedis、lettuce等)连接到集群实例时,它会得到一份集群的槽位配置信息,然后客户端会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给哈希槽对应的实例发送请求了。

那每个实例怎么知道其它实例负责的槽位呢?这是因为集群中的实例相互连接时,会将自己的哈希槽信息发送给对方,当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。这样客户端在连接到某个实例时,就可以得到集群的整个哈希槽映射关系了。

集群的槽位信息存储于每个节点中,它不需要另外的分布式存储来存储节点槽位信息。前面在创建集群时,我们通过 cluster-config-file 指定了集群配置文件,集群的每个节点会将集群的哈希槽信息持久化到这个配置文件中,所以必须确保配置文件是可写的,而且不要人工修改配置文件。有了这个文件,实例宕机重启也能恢复槽位信息配置。

例如下面的两个配置文件: Bild.png

槽位重定向

前面说了,Redis集群是去中心化的模式,集群中每个实例都有一份整个集群完整的槽位映射表,这就为客户端提供了纠错能力,因为客户端访问的槽位可能并不在目标实例上。

Redis集群的客户端连接集群时,它也会得到一份集群的槽位配置信息,然后缓存在本地。但如果集群槽位信息发生变更,比如扩容、缩容,节点之间可以通过相互传递消息来获得最新的哈希槽分配信息,但是客户端是无法主动感知这些变化的。

Redis Cluster 提供了一种重定向机制,在客户端给一个实例发送指令时,该实例发现指令的 key 所在的槽位并不归自己管理,这时它会向客户端返回一个特殊的跳转指令 MOVED,其中就包含了这个 key 所在的槽位和实例,然后客户端再重新去访问这个新实例。

例如下面在 7001 上访问返回了 MOVED 命令,说明了请求的键值对所在的哈希槽为 5798,实际是在 172.17.0.3:7003 这个实例上。这时客户端会更新本地缓存的槽位信息,然后向新实例重新发送指令。

Bild.png

数据迁移

在集群中,我们可能会进行扩容、缩容,或是负载均衡等操作,Redis Cluster 就会把哈希槽重新分布一遍,然后就会迁移数据。

实例之间进行数据迁移都是以哈希槽为基本单位进行操作,当一个槽正在迁移时,这个槽就处于中间过渡状态。那么就有可能这个槽的一部分数据已迁移到目标节点,一部分数据还在原节点。

客户端在访问原节点时,如果对应的数据还在原节点里,那么原节点正常处理。如果对应的数据不在原节点里,那么有两种可能,要么该数据在新节点里,要么根本就不存在。旧节点不知道是哪种情况,所以它会向客户端返回一个 ASK 的重定向指令,返回的 ASK 指令告诉了客户端这个槽位的数据正在迁移中,并且告诉客户端这个槽位的新实例地址。客户端收到这个重定向指令后,先去目标节点执行一个不带任何参数的 ASKING 指令,然后在目标节点再重新执行原先的操作指令。

GET hello:key
(error) ASK 13320 172.17.0.3:7003
复制代码

之所以要先发送 ASKING 指令,是因为在迁移没有完成之前,这个槽位不归新节点管理,如果这个时候向新节点发送该槽位的指令,它会向客户端返回一个 MOVED 重定向指令告诉它去原节点去执行,这样就会导致 循环重定向。而 ASKING 指令就是告诉新节点强制执行下一条指令,把下一条指令当成自己的槽位来处理。

MOVED 命令不同,ASK 命令并不会更新客户端缓存的哈希槽映射信息。所以,如果客户端再次请求这个槽中的数据,它还是会给原节点发送请求。

另外,Redis Cluster 的数据迁移是同步的,迁移一个key会同时阻塞原节点和目标节点,迁移过程中会有一定的性能问题。

主备切换

Redis 集群中的 Slave 节点主要是用于做数据的热备、主备切换,实现集群的高可用的,主库宕机后,集群就会从主库的 Slave 节点中选举出一个节点切换为新主库。

主备切换选举的过程与哨兵模式的原理非常类似,可参考:Redis系列(3) — 哨兵高可用,下面简单说明下集群模式中主备切换的原理。

集群中的 Master 节点之间会不断发送 PING 消息来交换信息,并确认节点间的通信是否正常等。

如果一个节点 PING 另一个节点,在 cluster-node-timeout 内都没有返回,那么就认为另一个节点宕机,这个节点的状态就是主观下线(sdown),如果超过半数节点都认为另一个节点宕机了,那就是客观下线(odown)

判断节点客观下线后,就要从 节点的Slave节点中重选一个,这时会按如下规则进行选举:

  • Slave 节点与 Master 节点断开连接的时间如果超过了 cluster-node-timeout * cluster-replica-validity-factor,就会被剔除
  • 根据Slave节点对Master节点复制数据的 offset 排序,offset 越大,优先选举
  • 如果 offset 一样,所有 Master 节点对这些 Slave 节点投票,得票超过半数(N/2+1)的就选举通过。
cluster-node-timeout 15000
cluster-replica-validity-factor 10
复制代码

选举出新的节点后,就执行主备切换的过程。整个流程跟哨兵非常类似,可以看出 Redis Cluster 功能更强大,集成了 主从复制 和 哨兵 的功能。

集群实验

主从切换

下面通过实验来验证下主库宕机后,从库是否会自动切换为主库。

通过前面的部署可以知道集群节点的关系如下,以 7003 为例做测试:

172.17.0.2:7001(Master) -> 172.17.0.3:7004(Slave)
172.17.0.4:7005(Master) -> 172.17.0.2:7002(Slave)
172.17.0.3:7003(Master) -> 172.17.0.4:7006(Slave)
复制代码

先在 7003(Master) 上验证操作可行:

Bild.png

在 对应的 7006(Slave)上不可操作:

Bild.png

此时将 7003 kill 掉:

Bild.png

这时再检查集群状态,会发现之前的 7006(Slave)已经切换为 Master 了:

[root@centos-01 ~]# redis-cli --cluster check 172.17.0.2:7001
Could not connect to Redis at 172.17.0.3:7003: Connection refused
172.17.0.2:7001 (9b4f3c2c...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.4:7005 (26776d9a...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.4:7006 (fc25b50d...) -> 1 keys | 5462 slots | 0 slaves.
[OK] 1 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 172.17.0.2:7001)
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   slots: (0 slots) slave
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   slots:[5461-10922] (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
复制代码

再连接到 7006 上,这时发现可以进行操作了:

Bild.png

接下来再把之前的 7003 重新启动:

Bild.png

再检查集群的状态,可以看到 7003(...2aff02ac) 自动变为了 7006(...50c9e3183b) 的从库。

[root@centos-01 ~]# redis-cli --cluster check 172.17.0.2:7001
172.17.0.2:7001 (9b4f3c2c...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.4:7005 (26776d9a...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.4:7006 (fc25b50d...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 1 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 172.17.0.2:7001)
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   slots: (0 slots) slave
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots: (0 slots) slave
   replicates fc25b50d6afe39211a47609287afd250c9e3183b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
复制代码

通过上面的测试说明主库宕机时,从库会自动切换为主库顶上去,原主库重启后,会自动变为新主库的从库。

集群扩容

如果要提高集群的读写吞吐量、或支撑更多的数据,这时就需要做集群扩容,增加节点,下面就来实验一下。

增加一台 172.17.0.5 的服务器,同样的,新增 一主一从 两个节点,端口分别为 7007、7008

先按照前面集群搭建的步骤把基础环境装好:

# 创建目录
# mkdir -p /var/redis/log
# mkdir -p /var/redis/7007
# mkdir -p /var/redis/7008

# 拷贝配置文件,并修改相关配置
# cp /usr/local/src/redis-6.2.5/redis.conf /etc/redis/7007.conf
# cp /usr/local/src/redis-6.2.5/redis.conf /etc/redis/7008.conf

# 拷贝脚本,并修改相关配置
# cp /usr/local/src/redis-6.2.5/utils/redis_init_script /etc/init.d/redis_7007
# cp /usr/local/src/redis-6.2.5/utils/redis_init_script /etc/init.d/redis_7008
复制代码

将两个节点启动起来:

Bild.png

集群中增加节点的命令格式如下:

redis-cli --cluster add-node new_host:new_port existing_host:existing_port
    --cluster-slave --cluster-master-id <arg>
复制代码

下面将 7007 添加为集群的 Master:

[root@centos-01 ~]# redis-cli --cluster add-node 172.17.0.5:7007 172.17.0.2:7001
>>> Adding node 172.17.0.5:7007 to cluster 172.17.0.2:7001
......
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 172.17.0.5:7007 to make it join the cluster.
[OK] New node added correctly.
复制代码

此时检查集群状态,发现 7007 没有 slave(0 slaves),也没有分配槽位(0 slots),7007 的实例ID 为 bca31339ca8d8177e9d80831d72b64bc52fdbb87

[root@centos-01 ~]# redis-cli --cluster check 172.17.0.2:7001
172.17.0.2:7001 (9b4f3c2c...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.4:7005 (26776d9a...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.5:7007 (bca31339...) -> 0 keys | 0 slots | 0 slaves.
172.17.0.4:7006 (fc25b50d...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 1 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 172.17.0.2:7001)
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: bca31339ca8d8177e9d80831d72b64bc52fdbb87 172.17.0.5:7007
   slots: (0 slots) master
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   slots: (0 slots) slave
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots: (0 slots) slave
   replicates fc25b50d6afe39211a47609287afd250c9e3183b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
复制代码

接下来将 7008 添加为 7007 的 Slave:

[root@centos-01 ~]# redis-cli --cluster add-node 172.17.0.5:7008 172.17.0.2:7001 
        --cluster-slave --cluster-master-id bca31339ca8d8177e9d80831d72b64bc52fdbb87
>>> Adding node 172.17.0.5:7008 to cluster 172.17.0.2:7001
>>> Performing Cluster Check (using node 172.17.0.2:7001)
......
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 172.17.0.5:7008 to make it join the cluster.
Waiting for the cluster to join

>>> Configure node as replica of 172.17.0.5:7007.
[OK] New node added correctly.
复制代码

此时再检查集群状态,可以看到 7008 已经变为 7007 的从库了:

[root@centos-01 ~]# redis-cli --cluster check 172.17.0.2:7001
172.17.0.2:7001 (9b4f3c2c...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.4:7005 (26776d9a...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.5:7007 (bca31339...) -> 0 keys | 0 slots | 1 slaves.
172.17.0.4:7006 (fc25b50d...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 1 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 172.17.0.2:7001)
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: bca31339ca8d8177e9d80831d72b64bc52fdbb87 172.17.0.5:7007
   slots: (0 slots) master
   1 additional replica(s)
S: 5bfc64bbce07a872d6d6048c62e80f7a8e56990a 172.17.0.5:7008
   slots: (0 slots) slave
   replicates bca31339ca8d8177e9d80831d72b64bc52fdbb87
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   slots: (0 slots) slave
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots: (0 slots) slave
   replicates fc25b50d6afe39211a47609287afd250c9e3183b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
复制代码

但此时新加入的节点还没有分配哈希槽,我们可以使用 reshardrebalance 命令分配一些槽位到新节点上。例如从 7001(...2f5ca7bf646) 上移动2000个哈希槽到 7007(...c52fdbb87) 上:

[root@centos-01 ~]# redis-cli --cluster reshard 172.17.0.2:7001 
        --cluster-from 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 
        --cluster-to bca31339ca8d8177e9d80831d72b64bc52fdbb87 
        --cluster-slots 2000
复制代码

再检查集群状态,发现 7007 上已经有哈希槽了:

[root@centos-01 ~]# redis-cli --cluster check 172.17.0.2:7001
172.17.0.2:7001 (9b4f3c2c...) -> 0 keys | 3461 slots | 1 slaves.
172.17.0.4:7005 (26776d9a...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.5:7007 (bca31339...) -> 0 keys | 2000 slots | 1 slaves.
172.17.0.4:7006 (fc25b50d...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 1 keys in 4 masters.
...
[OK] All 16384 slots covered.
复制代码

集群缩容

下面演示删除 172.17.0.5:7007(bca31339ca8d8177e9d80831d72b64bc52fdbb87) 节点。

要删除集群中某个节点,需先将集群上所有的哈希槽移到其它节点后才可以删除,否则会报错:

Bild.png

Verwenden Sie zuerst den reshardBefehl , um den Hash-Slot des Knotens 7007(...c52fdbb87) auf 7001(...2f5ca7bf646) zu verschieben:

[root@centos-01 ~]# redis-cli --cluster reshard 172.17.0.2:7001 
        --cluster-from bca31339ca8d8177e9d80831d72b64bc52fdbb87
        --cluster-to 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 
        --cluster-slots 2000
复制代码

An dieser Stelle kann das Löschen des Knotens 7007 erfolgreich ausgeführt werden:

[root@centos-01 ~]# redis-cli --cluster del-node 172.17.0.2:7002 bca31339ca8d8177e9d80831d72b64bc52fdbb87
>>> Removing node bca31339ca8d8177e9d80831d72b64bc52fdbb87 from cluster 172.17.0.2:7002
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.
复制代码

Der ursprüngliche Slave-Knoten 7008 wird automatisch an andere Master gemountet. Sie können sehen, dass 7008 ein Slave von 7001 wird:

[root@centos-01 ~]# redis-cli --cluster check 172.17.0.2:7001
172.17.0.2:7001 (9b4f3c2c...) -> 0 keys | 5461 slots | 2 slaves.
172.17.0.4:7005 (26776d9a...) -> 0 keys | 5461 slots | 1 slaves.
172.17.0.4:7006 (fc25b50d...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 1 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 172.17.0.2:7001)
M: 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646 172.17.0.2:7001
   slots:[0-5460] (5461 slots) master
   2 additional replica(s)
M: 26776d9aef1c511d77efee79a45a63eff18fb4f9 172.17.0.4:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 5bfc64bbce07a872d6d6048c62e80f7a8e56990a 172.17.0.5:7008
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9a627cad72e4192802237c00e4e570b37241feda 172.17.0.3:7004
   slots: (0 slots) slave
   replicates 9b4f3c2ca93b576776e3d3ea5b0c12f5ca7bf646
S: 9b0751a4b6ea227658ed26576d9bda1f3b01fc04 172.17.0.2:7002
   slots: (0 slots) slave
   replicates 26776d9aef1c511d77efee79a45a63eff18fb4f9
M: fc25b50d6afe39211a47609287afd250c9e3183b 172.17.0.4:7006
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 4e2f6532200991c93bbf23f7d4996fbd2aff02ac 172.17.0.3:7003
   slots: (0 slots) slave
   replicates fc25b50d6afe39211a47609287afd250c9e3183b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
复制代码

Natürlich können wir den 7008-Knoten auch löschen:

[root@centos-01 ~]# redis-cli --cluster del-node 172.17.0.2:7002 5bfc64bbce07a872d6d6048c62e80f7a8e56990a
>>> Removing node 5bfc64bbce07a872d6d6048c62e80f7a8e56990a from cluster 172.17.0.2:7002
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.
复制代码

Ich denke du magst

Origin juejin.im/post/7084163543108927502
Empfohlen
Rangfolge