站内链接:

架构

单机模式

Redis 单机模式是指在一个单独的 Redis 实例上运行,没有任何主从复制或分片分布。它是 Redis 最简单的部署模式,适用于小规模应用或开发测试环境。尽管 Redis 单机模式在部署和管理上相对简单,但在面对高并发和大规模数据负载时可能存在性能和可靠性方面的限制。其有如下缺点:

  • Redis 单机模式没有内置的高可用性机制。如果 Redis 服务器发生故障或宕机,将导致应用程序无法访问数据。单点故障可能会导致应用中断或数据丢失。
  • 有限的容量和性能:Redis 单机模式受限于单个服务器的资源,包括内存容量、CPU 和网络带宽等。对于大规模的数据集和高并发负载,单个 Redis 实例可能无法满足需求,导致性能下降或资源瓶颈。
  • 无自动扩展:在 Redis 单机模式下,无法自动水平扩展以应对增长的数据量和负载。如果需要增加存储容量或处理能力,需要手动升级硬件或迁移数据到更强大的服务器。
  • 数据丢失风险:由于 Redis 单机模式将数据存储在内存中,如果服务器发生故障或重启,内存中的数据将会丢失。虽然可以通过持久化机制将数据保存到磁盘上,但仍存在一定的数据丢失风险。
  • 无分片支持:Redis 单机模式无法自动将数据分片存储在多个节点上,无法实现数据的水平扩展和负载均衡。所有的请求都集中在单个节点上处理,可能导致性能瓶颈和资源不平衡。

对于需要更高可用性和扩展性的生产环境,可以考虑使用 Redis 集群模式或主从复制模式来实现数据的分片和复制。

主从模式

  1. 说明

主从架构可以是一主一从,也可以是一主多从,通过该架构我们可以完成类似 MySQL 那样的读写分离,从而降低主实例的并发请求量,降低系统资源损耗,同时从实例也可以作为数据副本。一般来说,主从架构中,数据都是单向传输的,即数据只能从 master 流向 slave,一个 master 可以有多个 slave,一个 slave 只能有一个 master。

  • 数据复制:主从配置通过将主节点的数据复制到从节点来实现数据的复制
  • 高可用性:主从配置提供了故障转移的机制,当主节点发生故障或不可用时,可以自动将其中一个从节点升级为新的主节点,继续提供服务
  • 扩展性:通过添加多个从节点,主从配置可以提供一定程度的读取负载均衡和横向扩展能力。
  • 数据备份:主从配置可以用于实现数据的备份和恢复。
  1. 主从复制方式:类似 MySQL 的主从复制,分为 RDB 和 AOF 两种方式进行数据同步,前者是全量同步。
  2. 主从复制过程
  • 配置主从关系:在从节点的配置文件中指定主节点的 IP 地址和端口号,并启动从节点。
  • 从节点发送 SYNC 命令:从节点启动后,会向主节点发送 SYNC 命令,请求进行全量同步。
  • 主节点执行 BGSAVE 命令:主节点收到 SYNC 命令后,会执行 BGSAVE 命令,将当前内存中的数据持久化到磁盘上生成 RDB 快照文件。
  • 主节点发送快照文件和命令流:主节点在生成 RDB 快照文件后,将文件发送给从节点,并同时将自己执行的写命令记录在缓冲区中。
  • 从节点加载快照文件:从节点接收到主节点发送的 RDB 快照文件后,会加载文件中的数据到自己的内存中。
  • 从节点执行命令流:从节点接收到主节点发送的命令流后,会按顺序执行这些命令,使自己的数据和主节点保持一致。
  • 从节点成为主节点的从节点:完成初始全量同步后,从节点会持续地与主节点保持连接,接收主节点的新命令并执行,以保持数据的一致性。
  • 增量同步:主节点会将自己执行的写命令发送给从节点进行增量同步,从节点接收并执行这些命令,使自己的数据与主节点保持同步。

redis-master-sync

  1. 缺点
  • 读写分离导致的数据不一致:复制数据延迟,读到过期数据,从节点故障
  • 主从配置不一致导致的主备切换可能存在问题: 比如 maxmemory 配置等,数据结构化参数配置不一致等,在极限情况下就会碰到问题
  • 全量复制:尽可能将第一次全量复制放在夜间,另外主节点重启,此时 ID 会变化,此时就会再次发生全量复制,另外rel_backlog_size配置增大复制缓冲区以减少缓冲区不足问题
  • 从节点资源浪费:从节点主要用于读取数据,但在主从模式中,从节点无法处理写操作。这可能导致从节点的资源被浪费,因为它们无法充分利用其计算能力和存储资源。

哨兵模式

  1. 介绍

注意,哨兵是 redis 高可用解决方案,并非分布式缓存系统解决方案。

Redis 哨兵模式是一种用于高可用性的 Redis 架构。在哨兵模式中,有多个 Redis 实例,其中一个被称为主节点(master),其他实例被称为从节点(slave)。同时,还有一个或多个哨兵节点(sentinel)负责监控主节点和从节点的状态。

哨兵节点的主要职责是监控主节点的健康状态,如果主节点发生故障或不可用,哨兵节点会自动将一个从节点提升为新的主节点,并将其他从节点切换到新的主节点上。这个过程称为自动故障转移(automatic failover),它确保了即使主节点发生故障,系统仍能继续提供服务。

哨兵模式的优点是实现了 Redis 的高可用性和自动故障转移。它能够在主节点故障时自动切换到新的主节点,减少了系统的停机时间和人工干预的需求。同时,哨兵节点还能监控整个集群的状态,并提供相关的信息和报警。

然而,哨兵模式也存在一些缺点。由于哨兵节点需要定期发送心跳检测和进行故障切换,这会增加一定的网络开销和延迟。此外,哨兵模式对于大规模的集群来说,管理和维护的复杂性也会增加。

哨兵模式的结构图如下:

redis-master-sentinel

  1. 哨兵监控箱术语
  • 主观下线:一个哨兵节点个人认为某个 Redis 节点(主节点或从节点)已经不可用,即该节点发生故障或无法正常响应
  • 客观下线(Objective Down):当多数(quorum)的哨兵节点都报告某个 Redis 节点主观下线时,就认为该节点达到了客观下线的状态。客观下线是一种共识,意味着集群中大多数节点都认为该节点不可用。
  • 选举(Election):选举是指在故障转移过程中,哨兵节点通过投票选择新的主节点。每个哨兵节点都会为候选节点投票,并根据投票结果确定新的主节点。
  • 领导者(Leader):在哨兵集群中,有一个哨兵节点被选举为领导者,负责协调和执行集群管理任务,如监控节点状态、处理故障转移等。领导者节点是集群中的核心节点,确保集群的一致性和正常运行。
  • 选举超时时间(Election Timeout):选举超时时间是指哨兵节点在进行故障转移选举时的时间限制。如果在选举超时时间内没有达成共识,将重新发起选举过程。
  1. 缺点

集群模式

Redis Cluster 是一种服务器 Sharding 技术,Redis 的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,所以在 redis3.0 上加入了 Cluster 集群模式,实现了 Redis 的分布式存储。

Redis 集群模式是一种分布式部署架构,用于实现高可用性和横向扩展的 Redis 解决方案。在 Redis 集群模式中,数据被分布到多个节点上进行存储和处理,以实现负载均衡和故障容错。该模式用到了数据分片、主从复制、节点间通信、负载均衡、故障转移等技术。

redis-master-cluster

主从架构

一主一从

这里我们就不通过 slave 命令进行主从的配置,而是直接更改 redis.conf 来完成主从配置,实际上 redis 可以在单个机器上运行多个实例(单线程单 CPU 无法高效利用资源,所以可以在一台机器上跑多个实例),下面的测试还是在多个云主机(centos8 系统)上进行主从的搭建,其中主(10.0.28.11),备(10.0.28.9):

  1. 主端和备端同时进行端口和 IP 地址的改动
1
2
3
4
5
6
7
# a. 主端,其中10.0.28.X为内网地址,其中dir和pidfile可以自行看情况调整
bind 10.0.28.11 127.0.0.1
port 6379

# b. 备端
bind 127.0.0.1 10.0.28.9
port 6379

重启主端和备端: systemctl restart redis.service

  1. 设置防火墙对10.0.28.0/24网段的来源 IP 开放 6379 端口,以便后续主备进行数据同步交互
1
2
3
# 在主备两端测试是否能够通过6379端口连接相应的服务,可以用telnet
redis-cli -h 10.0.28.11 KEYS "*"
redis-cli -h 10.0.28.9 KEYS "*"
  1. 配置主从节点并设置为只读
1
2
3
4
# a. 备端进行设置,主端不需要更改
replicaof 10.0.28.11 6379
# 只读,默认就有
replica-read-only yes
  1. 密码认证: 对于需要密码登录的主备,还需要在主从设置密码
1
2
3
4
5
# 主端: 设置密码
requirepass PASSWORD1

# 备端:密码认证
masterauth PASSWORD1
  1. 查看主备信息查看是否配置完成:info replication
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 主端信息输出:
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.28.9,port=6379,state=online,offset=28877,lag=1
master_replid:11592b8de6da796684fa486cf4dad333a40b7ff2


# 备端信息输出:
# Replication
role:slave
master_host:10.0.28.11
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:28933
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:11592b8de6da796684fa486cf4dad333a40b7ff2

至此,一主一从配置已经完成,此时就可以在主端添加一条命令,并在备端查看是否可以读取信息。

一主多从

根据上面的说明可知,主从架构的流量反向都是固定的,即从主端流向备端,所以一主多从和一主一从的配置都是类似的,此时主端的配置无需变动,只不过备端的操作在另外一个实例上又做了一遍。

  1. 绑定备端 IP 和地址,设置为只读,注意开放端口
1
2
3
4
5
6
bind 127.0.0.1 10.0.28.6
port 6379

# 设置为只读并连接主端
replicaof 10.0.28.11 6379
replica-read-only yes
  1. 重启备端,测试主备此时的 info 输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 主端
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.28.9,port=6379,state=online,offset=30403,lag=0
slave1:ip=10.0.28.6,port=6379,state=online,offset=30403,lag=1
master_replid:11592b8de6da796684fa486cf4dad333a40b7ff2

# 备端
# Replication
role:slave
master_host:10.0.28.11
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_repl_offset:30431
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:11592b8de6da796684fa486cf4dad333a40b7ff2

客户端连接

  1. 一主一从
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import redis

# 获取 Redis 主节点连接对象
master = redis.Redis(host='10.0.28.11')

# 获取 Redis 从节点连接对象
slave = redis.Redis(host='10.0.28.9')

# 写操作
key = 'redistest:masterwrite:one'
master.set(key, 'value')

# 读操作
value = slave.get(key)
print(value)
  1. 一主多从
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import redis
import random
from redis.connection import ConnectionPool


# 自定义连接池类
class RandomSlavePool:
def __init__(self, addresses):
self.slave_connections = [ConnectionPool(host=ad[0], port=ad[1]) for ad in addresses]

def get_random_slave(self):
# 随机选择一个从节点连接
return random.choice(self.slave_connections)


# 创建 Redis 主节点连接对象
master = redis.Redis(host='10.0.28.11', port=6379)

# 创建从节点连接池
slave_addresses = [
('10.0.28.9', 6379),
('10.0.28.6', 6379),
# ... 可以继续添加更多的从节点连接地址
]
slave_pools = RandomSlavePool(slave_addresses)

# 写操作,将键值对存储到主节点
key = 'redistest:masterwrite:multi'
master.set(key, 'value-mutli')

# 获取从节点连接对象
slave = redis.Redis(connection_pool=slave_pools.get_random_slave())
# 读操作,从随机选择的从节点读取键的值
value = slave.get(key)
print(value)
print('----' * 5)

slave = redis.Redis(connection_pool=slave_pools.get_random_slave())
# 读操作,从随机选择的从节点读取键的值
value = slave.get(key)
print(value)

哨兵架构

配置

我们基于上面的一主二从架构进行哨兵模式的配置: 主-10.0.28.11, 从1-10.0.28.9,从2-10.0.28.6,其架构如下:

1
2
3
4
5
6
7
8
9
10
                sentinel-1
┌───────────────────┐
│ 10.0.28.11-master │
└──┬─────────────┬──┘
│ │
│ AOF/RDB │
┌─────────────▼─┐ ┌─▼─────────────┐
│10.0.28.6-slave│ │10.0.28.9-slave│
└───────────────┘ └───────────────┘
sentinel-2 sentinel-3
  1. 更改 redis sentinel 配置,/etc/redis-sentinel.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# A 主从配置
# 备份和打开配置,其中哨兵默认使用26379端口
cp /etc/redis-sentinel.conf /etc/redis-sentinel.conf.orig
vim /etc/redis-sentinel.conf

# 主端(不需要改动),注意,其中的mymaster命令可以自定义,但是所有哨兵节点必须保持相同
sentinel monitor mymaster 127.0.0.1 6379 2

# 备端(两个备端)
sentinel monitor mymaster 10.0.28.11 6379 2

# B 认证配置, 暂时没必要
sentinel auth-pass mymaster PWD

# C 配置宕机多少秒之后自动进行切换,默认30S
sentinel down-after-milliseconds mymaster 30000

# D 故障转移超时时间,默认18S
sentinel failover-timeout mymaster 18000

# E 允许几个节点同时向主库同步数据
sentinel parallel-syncs mymaster 1

最终备端的配置文件变为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat > /etc/redis-sentinel.conf <<EOF
# default configure
# bind $(ifconfig | awk 'NR==2{print $2}')
bind 0.0.0.0
port 26379
daemonize no
pidfile /var/run/redis-sentinel.pid
logfile /var/log/redis/sentinel.log
dir /tmp

# sentinel confiure
sentinel monitor mymaster 10.0.28.11 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 60000
sentinel deny-scripts-reconfig yes
EOF
  1. 重启哨兵节点并设置防火墙: systemctl restart redis-sentinel
  2. 在三个哨兵都启动之后,查看 master 哨兵的日志
1
2
3
4
5
6
7
8
9
10
[root@VM-28-11-opencloudos ~]# tail -f /var/log/redis/sentinel.log
2353028:X 12 Jul 2023 19:31:19.712 # Configuration loaded
2353028:X 12 Jul 2023 19:31:19.712 * supervised by systemd, will signal readiness
2353028:X 12 Jul 2023 19:31:19.713 * Running mode=sentinel, port=26379.
2353028:X 12 Jul 2023 19:31:19.725 # Sentinel ID is 8fc4374094e139976ce6d5f39045860402bb3750
2353028:X 12 Jul 2023 19:31:19.725 # +monitor master mymaster 127.0.0.1 6379 quorum 2
2353028:X 12 Jul 2023 19:31:19.726 * +slave slave 10.0.28.9:6379 10.0.28.9 6379 @ mymaster 127.0.0.1 6379
2353028:X 12 Jul 2023 19:31:19.736 * +slave slave 10.0.28.6:6379 10.0.28.6 6379 @ mymaster 127.0.0.1 6379
2353028:X 12 Jul 2023 19:31:23.112 * +sentinel sentinel 3f8d1e82ac1db49b8b1dcec2c0264d17341d8513 10.0.28.6 26379 @ mymaster 127.0.0.1 6379
2353028:X 12 Jul 2023 19:31:24.235 * +sentinel sentinel 86f76c1a420af5b898f3a3c61f4eebc1cb587a13 10.0.28.9 26379 @ mymaster 127.0.0.1 6379

可以看到每个哨兵都增加了 sentinel id 的配置,而两个非 master 哨兵的/var/log/redis/sentinel.log一直持续不断的有连接 master 的日志输出。

  1. 配置文件自动追加新的配置信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# master
protected-mode no
supervised systemd
sentinel known-replica mymaster 10.0.28.9 6379
sentinel known-replica mymaster 10.0.28.6 6379
sentinel known-sentinel mymaster 10.0.28.9 26379 86f76c1a420af5b898f3a3c61f4eebc1cb587a13
sentinel known-sentinel mymaster 10.0.28.6 26379 3f8d1e82ac1db49b8b1dcec2c0264d17341d8513
sentinel current-epoch 0

# slaver-1
protected-mode no
supervised systemd
sentinel known-replica mymaster 10.0.28.6 6379
sentinel known-replica mymaster 10.0.28.9 6379
sentinel known-sentinel mymaster 10.0.28.11 26379 8fc4374094e139976ce6d5f39045860402bb3750
sentinel known-sentinel mymaster 127.0.0.1 26379 3f8d1e82ac1db49b8b1dcec2c0264d17341d8513
sentinel known-sentinel mymaster 10.0.28.9 26379 86f76c1a420af5b898f3a3c61f4eebc1cb587a13
sentinel current-epoch 0

# slaver-2
protected-mode no
supervised systemd
sentinel known-replica mymaster 10.0.28.9 6379
sentinel known-replica mymaster 10.0.28.6 6379
sentinel known-sentinel mymaster 10.0.28.11 26379 8fc4374094e139976ce6d5f39045860402bb3750
sentinel known-sentinel mymaster 127.0.0.1 26379 86f76c1a420af5b898f3a3c61f4eebc1cb587a13
sentinel known-sentinel mymaster 10.0.28.6 26379 3f8d1e82ac1db49b8b1dcec2c0264d17341d8513
sentinel current-epoch 0
  1. 在 master 哨兵上通过命令查看哨兵信息
1
2
3
4
5
6
7
8
[root@VM-28-11-opencloudos ~]# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3

测试

测试哨兵在 master 这边阻塞 60S 或者停止,然后重新查看新的组长

1
2
3
4
5
6
7
8
# master
redis-cli shutdown
pkill redis

# 在等待一段时间之后查看备,发现组长已经变动,并且10.0.28.6变为可写
[root@VM-28-6-opencloudos ~]# redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
1) "10.0.28.6"
2) "6379"

集群架构

配置

  1. 结构

集群的配置不是以上面的主从配置为基础,这里也不会对每个节点设置哨兵配置,其整体的结构如下图:

redis-master-cluster-6

  1. 配置

不使用系统默认的 redis 配置进行启动,而是在指定目录下创建配置、数据、日志目录,配置完成之后的文件结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@VM-28-11-opencloudos app]# tree -NC /app/redis/
/app/redis/
├── conf
│ ├── redis-6378.conf
│ └── redis-6379.conf
├── data
│ ├── redis-6378
│ │ └── nodes-6378.conf
│ └── redis-6379
│ └── nodes-6379.conf
└── log
├── redis-6378.log
└── redis-6379.log

5 directories, 6 files

其中redis-6379.conf的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# redis后台运行
daemonize yes

# 数据存放目录
dir /app/redis/data/redis-6379

# 日志文件
logfile /app/redis/log/redis-6379.log

# 端口号
bind 0.0.0.0
port 6379

# 开启集群模式
cluster-enabled yes

# 集群的配置,配置文件首次启动自动生成, 集群启动成功后会自动在data目录下创建
cluster-config-file "nodes-6379.conf"

# 请求超时,设置10秒
cluster-node-timeout 10000

在确保三台服务器都配置了 6379/6378 的 redis 服务器之后就可以直接启动 redis 服务了: redis-server conf/redis-6378.conf

手动搭建集群

  1. 加入集群

在上面的 6 个 redis 实例都已经启动成功之后,此时查看日志会发现一行输出:No cluster configuration found, I'm 55435032647bd23e94634fa83cded67e0240deaf,即表示 redis cluster 并未配置。

Redis Cluster 集群模式下的节点彼此通过 Gossip 协议进行通信,但集群中的节点需要先进行握手通信。节点握手需要通过命令CLUSTER MEET <ip> <port>来完成,当执行CLUSTER MEET命令时,Redis 会将新节点添加到集群中,并与其他节点进行通信。新节点会尝试与集群中的任一节点建立连接,并通过节点间的消息交换和握手过程加入到集群中。

一旦握手成功,该状态会通过下发消息在集群中传播,其它节点就会自动发现新节点然后发起握手,最后所有节点都彼此感知并组成集群)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 在10.0.28.11上进入redis-6379进行手动握手
127.0.0.1:6379> cluster meet 10.0.28.11 6378
OK
127.0.0.1:6379> cluster meet 10.0.28.9 6379
OK
127.0.0.1:6379> cluster meet 10.0.28.9 6378
OK
127.0.0.1:6379> cluster meet 10.0.28.6 6379
OK
127.0.0.1:6379> cluster meet 10.0.28.6 6378
OK

# 查看集群节点, 注意,此时是6个主,并非三主三从
127.0.0.1:6379> cluster nodes
f297b857cc90ed86343270848eccdef611927979 10.0.28.9:6379@16379 master - 0 1689218653658 0 connected
d72df5fff1c831ce70a4aab6f670e18f699bc894 10.0.28.6:6378@16378 master - 0 1689218652000 5 connected
55435032647bd23e94634fa83cded67e0240deaf 10.0.28.11:6379@16379 myself,master - 0 1689218653000 1 connected
0ac03660123c4de7625f6c678160ee89c968ec1a 10.0.28.9:6378@16378 master - 0 1689218651000 3 connected
bab2174286e4f76099e2741cd1bbd1c5c70e114e 10.0.28.6:6379@16379 master - 0 1689218651653 4 connected
c4e856d3789b4aac6029b9b642a57a6dc4223b2e 10.0.28.11:6378@16378 master - 0 1689218652656 2 connected
  1. 分配槽

关于槽的知识后续有机会再聊,Redis 集群将所有的数据映射到 16384 个槽中,每个 key 都会对应一个槽,只有把槽分配给了节点,节点才能响应与槽相关的命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 分别对三个master节点进行槽的分配
[root@VM-28-11-opencloudos redis]# redis-cli -p 6379 -h 10.0.28.11 cluster addslots {0..5461}
OK
[root@VM-28-11-opencloudos redis]# redis-cli -p 6379 -h 10.0.28.9 cluster addslots {5462..10922}
OK
[root@VM-28-11-opencloudos redis]# redis-cli -p 6379 -h 10.0.28.6 cluster addslots {10923..16383}
OK

# 查看集群信息,可以看到cluster_state已经变为ok
[root@VM-28-11-opencloudos redis]# redis-cli
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384

# 查看集群槽
127.0.0.1:6379> cluster slots
1) 1) (integer) 5462
2) (integer) 10922
3) 1) "10.0.28.9"
2) (integer) 6379
3) "f297b857cc90ed86343270848eccdef611927979"
2) 1) (integer) 0
2) (integer) 5461
3) 1) "10.0.28.11"
2) (integer) 6379
3) "55435032647bd23e94634fa83cded67e0240deaf"
3) 1) (integer) 10923
2) (integer) 16383
3) 1) "10.0.28.6"
2) (integer) 6379
3) "bab2174286e4f76099e2741cd1bbd1c5c70e114e"
  1. 将从节点设置为 6379 的备,注意,一定要在从上执行
1
2
3
4
5
6
7
8
9
10
11
12
13
# 10.0.28.11的备, 这里的ID就是上面cluster slots的ID信息
[root@VM-28-11-opencloudos redis]# redis-cli -p 6378
127.0.0.1:6378> cluster replicate 55435032647bd23e94634fa83cded67e0240deaf
OK

# 其他两个
[root@VM-28-9-opencloudos redis]# redis-cli -p 6378
127.0.0.1:6378> cluster replicate f297b857cc90ed86343270848eccdef611927979
OK

[root@VM-28-6-opencloudos redis]# redis-cli -p 6378
127.0.0.1:6378> cluster replicate bab2174286e4f76099e2741cd1bbd1c5c70e114e
OK
  1. 此时,再去查看节点状态,整个架构就变为三主三从
1
2
3
4
5
6
7
127.0.0.1:6379> cluster nodes
bab2174286e4f76099e2741cd1bbd1c5c70e114e 10.0.28.6:6379@16379 myself,master - 0 1689219131000 4 connected 10923-16383
0ac03660123c4de7625f6c678160ee89c968ec1a 10.0.28.9:6378@16378 slave f297b857cc90ed86343270848eccdef611927979 0 1689219130000 3 connected
c4e856d3789b4aac6029b9b642a57a6dc4223b2e 10.0.28.11:6378@16378 slave 55435032647bd23e94634fa83cded67e0240deaf 0 1689219129000 2 connected
f297b857cc90ed86343270848eccdef611927979 10.0.28.9:6379@16379 master - 0 1689219132064 0 connected 5462-10922
55435032647bd23e94634fa83cded67e0240deaf 10.0.28.11:6379@16379 master - 0 1689219131863 1 connected 0-5461
d72df5fff1c831ce70a4aab6f670e18f699bc894 10.0.28.6:6378@16378 slave bab2174286e4f76099e2741cd1bbd1c5c70e114e 0 1689219130862 5 connected

自动搭建集群

通过命令redis-cli --cluster create 10.0.28.11:6379 10.0.28.11:6378 10.0.28.9:6379 10.0.28.9:6378 10.0.28.6:6379 10.0.28.6:6378 --cluster-replicas 1,该命令会自动对这 6 个节点进行一主一从分配(--cluster-replicas 1),当然这样可能不符合实际要求。

测试

  1. python 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import random
from rediscluster import RedisCluster

# 创建Redis Cluster连接
cluster_nodes = [
{'host': '10.0.28.11', 'port': 6379},
{'host': '10.0.28.9', 'port': 6379},
{'host': '10.0.28.6', 'port': 6379},
]
r = RedisCluster(startup_nodes=cluster_nodes, decode_responses=True)

# 存储数据到Redis Cluster
for i in range(1, 100):
r.set(f'redistest:cluster:{i}', f'value-{i}')

# 随机获取多条数据
for i in range(10):
key = random.randint(1, 100)
value1 = r.get(f'redistest:cluster:{key}')
print(f"Retrieved redistest:cluster:{key}: {value1}")

运行代码会发现这 99 个数据分别被存储到三个 Master 上,即三个 master 之间类似一个水平分库的效果,但是我们去获取某个键值的时候不需要考虑去哪里获取值。

  1. 命令行通过-c也可以达到将数据通过 slot 插入集群的效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 获取其他分片的数据
10.0.28.11:6379> get redistest:cluster:99
-> Redirected to slot [10106] located at 10.0.28.9:6379
"value-99"

# 2. 设置值
10.0.28.9:6379> set redistest:cli:1000 1
-> Redirected to slot [13408] located at 10.0.28.6:6379
OK
10.0.28.6:6379> set redistest:cli:1001 1
-> Redirected to slot [9281] located at 10.0.28.9:6379
OK
10.0.28.9:6379> set redistest:cli:1002 1
-> Redirected to slot [5154] located at 10.0.28.11:6379
OK

故障和分片

  1. 重新进行 slot 的分片,在 redis5 以上版本使用redis-cli --cluster reshard 10.0.28.11:6379来完成,只需要在一个节点上执行该命令 redis-cli 将自动找到其他节点
  2. 故障转移测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# a. 让10.0.28.11的master节点崩溃
redis-cli -p 6379 -h 10.0.28.11 debug segfault

# 查看cluster,发现该节点已经disconnected(需要一段时间),重点看10.0.28.11
127.0.0.1:6379> cluster nodes
bab2174286e4f76099e2741cd1bbd1c5c70e114e 10.0.28.6:6379@16379 myself,master - 0 1689223093000 4 connected 10923-16383
0ac03660123c4de7625f6c678160ee89c968ec1a 10.0.28.9:6378@16378 slave f297b857cc90ed86343270848eccdef611927979 0 1689223093019 3 connected
c4e856d3789b4aac6029b9b642a57a6dc4223b2e 10.0.28.11:6378@16378 master - 0 1689223092000 7 connected 0-5461
f297b857cc90ed86343270848eccdef611927979 10.0.28.9:6379@16379 master - 0 1689223091013 0 connected 5462-10922
55435032647bd23e94634fa83cded67e0240deaf 10.0.28.11:6379@16379 master,fail - 1689223039379 1689223036875 1 disconnected
d72df5fff1c831ce70a4aab6f670e18f699bc894 10.0.28.6:6378@16378 slave bab2174286e4f76099e2741cd1bbd1c5c70e114e 0 1689223094019 5 connected

# b. 重新启动10.0.28.11的6379服务
redis-server /app/redis/conf/redis-6379.conf

# 此时发现cluster会将新的节点重新拉入,此时该节点就不能进行写入操作了。
127.0.0.1:6379> cluster nodes
bab2174286e4f76099e2741cd1bbd1c5c70e114e 10.0.28.6:6379@16379 myself,master - 0 1689223230000 4 connected 10923-16383
0ac03660123c4de7625f6c678160ee89c968ec1a 10.0.28.9:6378@16378 slave f297b857cc90ed86343270848eccdef611927979 0 1689223233376 3 connected
c4e856d3789b4aac6029b9b642a57a6dc4223b2e 10.0.28.11:6378@16378 master - 0 1689223234377 7 connected 0-5461
f297b857cc90ed86343270848eccdef611927979 10.0.28.9:6379@16379 master - 0 1689223234000 0 connected 5462-10922
55435032647bd23e94634fa83cded67e0240deaf 10.0.28.11:6379@16379 slave c4e856d3789b4aac6029b9b642a57a6dc4223b2e 0 1689223234000 7 connected
d72df5fff1c831ce70a4aab6f670e18f699bc894 10.0.28.6:6378@16378 slave bab2174286e4f76099e2741cd1bbd1c5c70e114e 0 1689223233000 5 connected

参考: