Redis 7 + ACL 单节点、主从、哨兵、集群构建方法

摘要

redis安装

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
# 下载到指定目录
mkdir -p /usr/local/soft
wget https://download.redis.io/releases/redis-7.4.7.tar.gz -P /usr/local/soft

# 解压
cd /usr/local/soft
tar -zxvf redis-7.4.7.tar.gz

# 编译
sudo yum install gcc gcc-c++ -y
cd redis-7.4.7
# 编译,会将编译好的可执行文件放在src目录下
make
# 编译安装到指定目录,redis相关命令会被安装到 $(pwd)/build_dir/bin目录下
mkdir build_dir
make install PREFIX=$(pwd)/build_dir

# 编辑配置文件,不建议在原有配置文件中修改,可以新建一个配置文件
cp redis.conf redis-6379.conf
vim redis-6379.conf #见下面的配置信息

# 加入环境变量 /etc/bashrc,注意这里要是单引号,否则 $PATH 会被解析
echo 'export PATH=$PATH:/usr/local/soft/redis-7.4.7/build_dir/bin' >> /etc/bashrc
source /etc/bashrc

# 验证
redis-cli --version
# 输出
redis-cli 7.4.7

单节点

  • redis-6379.conf 的主要配置

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 端口,默认 6379
port 6379

# 后台启动,默认 no
daemonize yes

# yes: 当没有 bind / requirepass / ACL 时,只允许本机访问
# no: 允许任意访问
# 这里会启用ACL,所以设置为 yes,默认 yes
protected-mode yes

# 注释掉bind,绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置
#bind 127.0.0.1
# 可以配置为,本机IP 内网IP 外网IP
# bind 127.0.0.1 10.250.0.103 18.163.188.20

# 关闭rdb快照,因为会启用混合持久化,所以这里不需要开启rdb快照
# 这里只是关闭了自动快照,如果手动执行了 bgsave 命令,还是会生成一个 dump.rdb 文件
save ""

# 设置dir路径,redis日志、aof和rdb文件都会生成在这个路径下,需要提前创建好这个目录
dir /usr/local/soft/dir-redis7/6379

# 开启aof,实际上只需要开启这个配置,以下aof相关配置默认即可,默认 no
# 开启aof,重启redis时,会主动加载 appendonlydir 下的 相关 aof文件进行数据恢复
# 生产环境必须开启
appendonly yes

# aof文件名称,默认 appendonly.aof
appendfilename "appendonly.aof"
# aof文件保存目录,基于为当前dir路径,默认值就是 appendonlydir
# redis6+会生成3个文件,每个文件都以 appendfilename 配置的文件名称开头,如下:
# appendonly.aof.N.base.rdb:每次触发aof重写时都会生成这个文件,N是当前aof文件序号,base.rdb是当前rdb文件
# appendonly.aof.N.incr.aof:记录每个写操作命令
# appendonly.aof.manifest:记录 base.rdb 和 incr.aof 文件的最新索引(N)
appenddirname "appendonlydir"
# aof将数据fsync到磁盘的策略,默认即可,表示每秒一次,故障时最多会丢失一秒的数据,默认 everysec
appendfsync everysec

# 自动触发aof重写需要满足如下条件,如果需要手动触发aof重写,可以执行 BGREWRITEAOF 命令
# 重写时会删除旧的 appendonly.aof.N.base.rdb(RDB 快照) 文件,生成新的 appendonly.aof.N+1.base.rdb
# 当 AOF 重写完成后,当前的 appendonly.aof.N.incr.aof 会封存,Redis 会新建一个 appendonly.aof.N+1.incr.aof 来继续记录写命令
# 而此时 appendonly.aof.manifest(索引文件) 也会记录最新的 appendonly.aof.N.incr.aof 和 appendonly.aof.N.base.rdb
# aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就很快,重写的意义不大,默认即可,默认 64mb
auto-aof-rewrite-min-size 64mb
# aof文件自上一次重写后文件大小增长了100%则再次触发重写,默认 100
auto-aof-rewrite-percentage 100

# 开启混合持久化,4.0以后版本支持,需要先开启aof,默认 yes
# 开启混合持久化后,appendonly.aof.N.base.rdb 的文件后缀就是 rdb,否则是 aof
aof-use-rdb-preamble yes
# 防止 AOF 意外截断导致 Redis 起不来,默认 yes
aof-load-truncated yes

# pid文件路径,默认 /var/run/redis_6379.pid
pidfile "redis_6379.pid"

# 日志文件名称,默认 ""
logfile "6379.log"

# 指定最大内存,单位bytes,这里设置4G
# 如果不设置最大内存,redis会默认为物理内存,达到上限时会频繁与磁盘发生交换,使redis性能急剧下降
maxmemory 4294967296
# 达到最大内存时的清除策略,推荐 allkeys-lru,淘汰很久没被访问过的数据,基于最近一次的访问时间
# volatile-lru: 只会淘汰「设置了过期时间」的 key
# allkeys-lru: 淘汰最久没有被访问过的数据,最近最久没被访问的
# allkeys-lfu: 淘汰最不经常被访问过的数据,访问次数最少的
# noeviction: 不淘汰,默认
maxmemory-policy allkeys-lru

# 慢查询日志
# 单位微妙,这里表示10毫秒,即超过10毫秒的操作都会记录下来
slowlog-log-slower-than 10000

# 设置慢查询日志记录保存数量,如果数量已满会删除最早的记录
slowlog-max-len 1024

# 性能优化
# Redis 用多少附加线程来处理网络 I/O(不是执行命令),推荐:核心数 / 2,默认为1,超过 8 几乎就没有明显收益了
io-threads 4
# 多线程同时用于 读取 + 写回, no :多线程仅用于 写回客户端
# 推荐>=4核才开启,否则开了反而更慢
io-threads-do-reads yes
# 操作系统 TCP 层的健康检测,默认值300,这里如果 60 秒内没有数据流动,内核会发送探测包,判断连接是否活着
tcp-keepalive 60
# 客户端在 "多少秒不操作" 就强制断开,0:永不超时(推荐),默认 0
# 因为有 tcp-keepalive 60,会每 60 秒检测一下对面还在不在,如果不在,Redis 会主动断开该连接,所以不会导致连接永不释放
timeout 0
# 最大客户端连接数,默认 10000
maxclients 10000

# 禁用危险命令,根据需要自行添加,redis6+ 支持在 acl 文件中为不同的用户禁用危险命令
rename-command FLUSHALL ""
rename-command FLUSHDB ""
# rename-command SHUTDOWN ""
# rename-command CONFIG ""
# rename-command KEYS ""
# rename-command SAVE ""
# rename-command BGSAVE ""
# rename-command DEBUG ""
# rename-command EVAL ""
# rename-command SCRIPT ""

# Redis 在内部存在大量“隐式删除”场景(过期、覆盖写、eviction、rename、replication flush 等)。默认情况下,这些删除都是同步阻塞的(类似 DEL),可能导致主线程卡顿。Lazy Freeing 机制允许 Redis 在后台线程中释放大对象的内存(类似 UNLINK),从而减少阻塞。

# 当启用 maxmemory + eviction 策略(如 allkeys-lru、volatile-ttl)时,被淘汰的 key 是否采用异步释放(后台线程 UNLINK 模式)。适用场景:高吞吐、高并发、大对象(如大型 hash、set、zset、列表)场景才明显受益。
lazyfree-lazy-eviction yes
# 当 key 到期(EXPIRE 触发删除)时,是否异步释放其 Value。各种使用带 TTL 的缓存系统,尤其 value 是大型对象(JSON、大 Set、Hash 等)。过期 key 数量大、对象结构大时,推荐开启。
lazyfree-lazy-expire yes
# 针对“服务器内部因命令副作用导致的删除操作”是否异步释放,例如:
# RENAME 替换旧 key 时删除旧 value
# SET 操作覆盖旧值时删除旧 value
# SUNIONSTORE / SORT STORE 覆盖目标 key 时删除旧 value
# 重写函数、脚本时删除旧对象
# 适用场景:对象特别大,且存在覆盖写、rename 操作频繁的应用。
lazyfree-lazy-server-del yes
# 当副本(Replica/Slave)因全量同步而执行 FLUSHDB 时,是否异步释放原有数据。
# 此配置只影响副本不会影响主节点。
replica-lazy-flush yes
# 让用户执行 DEL 时也自动使用异步释放(等价于默认把 DEL 转换为 UNLINK)。
# 代码中大量使用 DEL 删除大对象又不方便统一改成 UNLINK 时。
# 一般生产环境我们倾向保持显式的语义(DEL/UNLINK),不建议轻易改写 DEL 行为。
lazyfree-lazy-user-del no
# FLUSHDB / FLUSHALL / SCRIPT FLUSH / FUNCTION FLUSH 在未显式指定 SYNC/ASYNC 时是否异步执行
# 大部分情况下建议保持 no,由应用决定是否用 FLUSHDB ASYNC。
lazyfree-lazy-user-flush no


# 开启 ACL 文件
aclfile /usr/local/soft/redis-7.4.7/users.acl
  • Redis 7 支持的淘汰策略

策略 是否只淘汰带 TTL 的 key 淘汰规则 说明
noeviction ❌ 不淘汰 不删任何 key 内存满了直接返回错误(默认)
allkeys-lru ❌ 所有 key 最近最久未使用 ✅ 最常用
allkeys-lfu ❌ 所有 key 访问频率最少 ✅ 热点场景最好
allkeys-random ❌ 所有 key 随机删除 ❌ 很少用
volatile-lru ✅ 只淘汰有 TTL 的 最近最久未使用 你之前用的
volatile-lfu ✅ 只淘汰有 TTL 的 访问频率最少 较少使用
volatile-random ✅ 只淘汰有 TTL 的 随机删除 很少用
volatile-ttl ✅ 只淘汰有 TTL 的 TTL 最小(马上过期的) 特殊场景用
  • users.acl 文件: 该文件不支持添加注释,所以使用时需要去掉如下注释行,关于ACL的详细说明,可以参考 Redis 7 + ACL 简介

1
2
3
4
# 关闭默认用户,禁止匿名访问
user default off
# 超级管理员
user admin on ~* &* +@all >123456
  • redis 服务启动与关闭

1
2
3
4
5
6
7
8
9
10
11
12
# 启动服务
redis-server redis-6379.conf
# 登录服务,本机访问可以省略 -h -p
redis-cli -h 127.0.0.1 -p 6379 --user admin --pass 123456
# 或者
redis-cli -u redis://admin:123456@127.0.0.1:6379

# 关闭服务
# shutdown == shutdown save
redis-cli -u redis://admin:123456@127.0.0.1:6379 shutdown
# 关闭服务,不保存数据,已经开了 AOF(尤其是 everysec) 的场景下,可以
redis-cli -u redis://admin:123456@127.0.0.1:6379 shutdown nosave
场景 推荐命令
正常下线(生产) shutdown nosave
已开 AOF shutdown nosave
数据很大 shutdown nosave
单机调试 shutdown
确定要生成快照 shutdown save
强制杀死(redis卡死) kill -9(极端情况)

单节点优点

  • 单机部署简单方便

单节点缺点

  • 不保证数据的可靠性,不适用于数据可靠性要求高的场景

  • 单点故障导致无法提供服务,或者硬盘损坏导致数据丢失

  • redis单节点最大qps为10w(取决于单核cpu的处理能力),超过这个qps就需要做前端限流

主从

  • 规划

1
2
3
master 10.250.0.235
slave1 10.250.0.58
slave2 10.250.0.36
  • 主从配置时,主节点不需要做任何修改

  • 从节点配置文件增加同步主节点信息,其余配置与主节点相同

1
2
3
4
5
6
7
8
9
# 指定主节点,从节点会从主节点同步数据,这里10.250.0.235 6379是主节点的ip和端口号
replicaof 10.250.0.235 6379

# 配置从节点只读,默认开启,避免数据写入从节点导致主从数据不一致
replica-read-only yes

# 如果主节点开启了ACL认证,则从节点需要设置主节点的认证信息,这里设置为管理员帐号
masteruser admin
masterauth 123456
  • 此时启动从节点redis-server redis-6379.conf,会自动从主节点同步数据,同步前如果从节点已经有数据,则会先清除原有数据再进行同步

  • 主节点接收到从节点的同步请求后,会通过bgsave将内存数据dump到rdb文件中并传递给从节点

  • 主节点生成rdb文件并传递给从节点期间会继续处理客户端的请求,并将这部分数据缓存到内存中,待从节点接收到主节点发过来的rdb文件并完成内存加载后,主节点会将这部分缓存在内存中的数据发送给从节点

  • 从节点相当于主节点的备份,主节点挂了,从节点不能自动切换为主节点,如果需要自动切换,可以使用哨兵或者集群部署方式

  • 此时登录master的redis并执行info replication命令

1
2
3
4
5
6
7
8
9
10
11
12
13
# Replication
role:master # 表示当前是从节点
connected_slaves:1 # 从节点数量
slave0:ip=10.250.0.36,port=6379,state=online,offset=56,lag=1 # 从节点信息
master_failover_state:no-failover # 主节点切换状态,无
master_replid:93e564c18d27418e52fc40254c764d76c1dc3f67 # 主节点的复制ID
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:56 # 主节点复制的偏移量
second_repl_offset:-1
repl_backlog_active:1 # 是否开启复制回放
repl_backlog_size:1048576 # 复制回放缓冲区大小
repl_backlog_first_byte_offset:1 # 复制回放缓冲区第一个字节的偏移量
repl_backlog_histlen:56 # 复制回放缓冲区历史长度
  • 此时登录从节点的redis并执行info replication命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Replication
role:slave # 表示当前是从节点
master_host:10.250.0.235 # 主节点的ip
master_port:6379 # 主节点的端口
master_link_status:up # 主从节点连接状态,up 表示已经连接上主节点
master_last_io_seconds_ago:6 # 主从节点最后一次io操作时间
master_sync_in_progress:0 # 主从节点是否正在同步数据,0表示已完成
slave_read_repl_offset:112 # 从节点已经读取的复制偏移量
slave_repl_offset:112 # 从节点已经写入的复制偏移量
slave_priority:100 # 从节点的优先级
slave_read_only:1 # 从节点是否只读
replica_announced:1 # 从节点是否被其他节点所代理
connected_slaves:0 # 从节点所代理的从节点数量
master_failover_state:no-failover # 主节点的故障转移状态,no-failover表示没有进行故障转移
master_replid:93e564c18d27418e52fc40254c764d76c1dc3f67 # 主节点的复制ID
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:112 # 主节点已经写入的复制偏移量 slave_read_repl_offset ≈ master_repl_offset,说明数据已经同步
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:98
  • 主从数据同步是否完成判断规则,在从节点上执行命令info replication

字段 正常值 说明
role slave 表示当前是从节点
master_link_status up 表示已经连上主库
master_sync_in_progress 0 同步不在进行中 = 已完成
slave_read_repl_offsetmaster_repl_offset 接近 说明数据已追上
  • 参照上面的配置,再添加一个从节点后,在主节点执行命令 info replication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Replication
role:master
connected_slaves:2 # 从节点数量
slave0:ip=10.250.0.36,port=6379,state=online,offset=4313,lag=0
slave1:ip=10.250.0.58,port=6379,state=online,offset=4313,lag=0 # 第二个从节点信息
master_failover_state:no-failover
master_replid:93e564c18d27418e52fc40254c764d76c1dc3f67
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:4313
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:4313

主从优点

  • 对请求进行读写分离,提高处理效率

  • 可以提供多个副本,提高数据安全性

主从缺点

  • 不具备自动容错和恢复功能,主节点故障,集群则无法进行工作,可用性比较低,从节点升主节点需要人工手动干预

哨兵

  • 创建三个哨兵,为了方便就在上面主从配置的3台服务器上启动哨兵

  • 规划

1
2
3
4
5
6
master 10.250.0.235
slave1 10.250.0.58
slave2 10.250.0.36
sentinel1 10.250.0.71
sentinel2 10.250.0.131
sentinel3 10.250.0.63
  • 分别编辑各自的 sentinel.conf

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
# 端口号
port 26379

# 后台启动
daemonize yes

# dir,需要提前创建好
dir /usr/local/soft/dir-redis7/sentinel

# pid文件路径
pidfile redis-sentinel.pid

# 日志文件名称
logfile "sentinel.log"

# 配置监听的主节点地址和端口,mymaster为自定义的名称,最后的2表示,只要有2个哨兵节点认为主节点挂了就会进行重新选主,一般设置为sentinel总数/2+1
sentinel monitor mymaster 10.250.0.235 6379 2

# 主观下线时间(5秒),默认30秒
sentinel down-after-milliseconds mymaster 5000

# 故障转移超时时间 60秒,默认180秒
sentinel failover-timeout mymaster 60000

# 每次允许多少个slave重新同步,默认就是 1
sentinel parallel-syncs mymaster 1

# acl用户名和密码,这里为了方便也是用的管理员帐号
sentinel auth-user mymaster admin
sentinel auth-pass mymaster 123456
  • 分别启动三个哨兵节点redis-sentinel sentinel.conf,此时登录哨兵节点redis-cli -p 26379,并执行info Sentinel命令,查看其是否正确识别了主从

1
2
3
4
5
6
7
8
# Sentinel
sentinel_masters:1 # 哨兵集群中主从节点的数量
sentinel_tilt:0 # 是否处于 tilt 状态
sentinel_tilt_since_seconds:-1 # tilt 状态的开始时间
sentinel_running_scripts:0 # 正在运行的脚本数量
sentinel_scripts_queue_length:0 # 脚本队列长度
sentinel_simulate_failure_flags:0 # 模拟故障的标志
master0:name=mymaster,status=ok,address=10.250.0.235:6379,slaves=2,sentinels=3 # 主节点的地址,从节点数量和哨兵数量
  • 此时查看sentinel.conf可以在文件最后看到从节点信息和其它的哨兵节点信息(但实测无法感知其它哨兵节点),类似于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9 # 延迟追踪信息百分比
user default on nopass sanitize-payload ~* &* +@all # 用户信息,当前的哨兵没有开启权限认证,所以缺省为default用户,无密码
sentinel myid 8b9d55a581f2e41b4f8d92f4a9434d9b8a78b3e6 # 本节点的id
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel current-epoch 0
# 一个从节点信息
sentinel known-replica mymaster 10.250.0.58 6379
# 另一个从节点信息
sentinel known-replica mymaster 10.250.0.36 6379
# 一个哨兵节点信息
sentinel known-sentinel mymaster 10.250.0.71 26379 b230f6a6076c23eed1923b29027d9ba7b24bee5a
# 另一个哨兵节点信息
sentinel known-sentinel mymaster 10.250.0.63 26379 74ef58ef3616a27cc63d83bcfe422f15e11731b8
  • 此时关闭master节点(10.250.0.235:6379),然后登录哨兵节点查看info Sentinel,就会发现master节点变成了从节点其中的一个了

  • 此时再次开启原master节点,会发现其变成了从节点,相应的配置文件(redis-6379.conf)也发生了变更

1
2
3
4
5
6
# Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9
replicaof 10.250.0.36 6379
save 3600 1
save 300 100
save 60 10000
  • 这里有一点需要注意,就是master节点重启前也需要配置如下认证信息,因为master在哨兵模式下发生故障后重新启动会变成slave

1
2
3
# 如果主节点开启了ACL认证,则从节点需要设置主节点的认证信息,这里设置为管理员帐号
masteruser admin
masterauth 123456
  • 顺便说一下,关闭哨兵服务的命令如下:

1
redis-cli -p 26379 shutdown

哨兵优点

  • 主节点故障,可以自动在从节点中重新选主

哨兵缺点

  • 哨兵单点故障,则集群无法完整自主选举主节点,所以需要对哨兵集群部署,增加服务器成本,但是并没有提升负载

  • 另外,主节点故障时,哨兵介入有时间差,会导致响应延迟

  • 从节点仅作为备份不提供对外服务,只有当master出现故障时其晋升为master后才能提供服务,所以不支持读写分离

集群

  • 搭建6个redis的集群,3主3从

  • 规划

1
2
3
4
5
6
redis1 10.250.0.235
redis2 10.250.0.58
redis3 10.250.0.36
redis4 10.250.0.71
redis5 10.250.0.131
redis6 10.250.0.63
  • 还是基于单节点配置文件,只是将节点配置成集群模式,redis-6379.conf文件增加如下信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ACL认证,所有节点都要配置
masteruser "admin"
masterauth "123456"

# 启动集群模式
cluster-enabled yes

# 集群节点信息文件,这里最好和port对应上
cluster-config-file nodes-6379.conf

# 集群节点间通信的超时时间,单位毫秒,默认15000,这个时间别设置太短,避免网络抖动等原因干扰
cluster-node-timeout 15000

# 写数据成功最少同步的slave数量,默认数据写入master就返回给client了,加上这个配置,就需要数据同步到指定数量的slave后才能返回,
# 注意这个配置不仅会延长client的等待时间,而且可能会影响集群的可用性,比如这里配置至少同步1个slave,但是如果此时master对应可用的slave不足1个,集群就不能提供服务了,所以建议每个master至少配置了2个以上的slave时才开启这个配置
# 开启这个配置可以预防集群脑裂问题,默认为3
min-replicas-to-write 1

# 如果集群中某个master/slave全部挂掉,整个集群的其它master/slave是否还可以对外提供服务,默认yes,不能
# 如果设置为no,则表示依旧可以提供服务,不过如果有key落在了挂掉的主从上就会失败
cluster-require-full-coverage yes
  • 分别启动6个redis服务

1
redis-server redis-6379.conf
  • 创建集群,3主3从,注意创建集群前所有redis不能有数据,如果有需要先清空(删除dir配置的目录中的所有文件即可),然后在任意一个redis执行

1
2
3
4
5
redis-cli --user admin --pass 123456 --cluster create --cluster-replicas 1 10.250.0.235:6379 10.250.0.58:6379 10.250.0.36:6379 10.250.0.71:6379 10.250.0.131:6379 10.250.0.63:6379
# 参数说明:
# --cluster create:创建集群
# --cluster-replicas 1:设置从节点数量,这里设置为1,表示每个主节点都对应一个从节点
# 这里配置了6个节点组建集群,要保证每个master节点都有一个从节点,所以刚好是3主3从
  • 此时会列出集群内主从和槽位的分配方案,输入yes即可

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
42
43
44
45
46
47
48
49
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.250.0.131:6379 to 10.250.0.235:6379
Adding replica 10.250.0.63:6379 to 10.250.0.58:6379
Adding replica 10.250.0.71:6379 to 10.250.0.36:6379
M: afcb754ce8cc79122fe9bcd8c1567bbf13258fce 10.250.0.235:6379
slots:[0-5460] (5461 slots) master
M: 2527142b7cffaf6bb92608550c919a0db0607c39 10.250.0.58:6379
slots:[5461-10922] (5462 slots) master
M: 88762f7d0bbb99bbaf68556ef5fd113cba46d295 10.250.0.36:6379
slots:[10923-16383] (5461 slots) master
S: 547fbd934293ddb5eb770e111b65910f4e604023 10.250.0.71:6379
replicates 88762f7d0bbb99bbaf68556ef5fd113cba46d295
S: 17b33861e6b086b86902fe75f79e5b878bd26f94 10.250.0.131:6379
replicates afcb754ce8cc79122fe9bcd8c1567bbf13258fce
S: 119e5823cccafef506b9b256aad206678eab7d41 10.250.0.63:6379
replicates 2527142b7cffaf6bb92608550c919a0db0607c39
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 10.250.0.235:6379)
M: afcb754ce8cc79122fe9bcd8c1567bbf13258fce 10.250.0.235:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 547fbd934293ddb5eb770e111b65910f4e604023 10.250.0.71:6379
slots: (0 slots) slave
replicates 88762f7d0bbb99bbaf68556ef5fd113cba46d295
S: 119e5823cccafef506b9b256aad206678eab7d41 10.250.0.63:6379
slots: (0 slots) slave
replicates 2527142b7cffaf6bb92608550c919a0db0607c39
S: 17b33861e6b086b86902fe75f79e5b878bd26f94 10.250.0.131:6379
slots: (0 slots) slave
replicates afcb754ce8cc79122fe9bcd8c1567bbf13258fce
M: 88762f7d0bbb99bbaf68556ef5fd113cba46d295 10.250.0.36:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 2527142b7cffaf6bb92608550c919a0db0607c39 10.250.0.58:6379
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.
  • 登录集群并查询集群配置信息

1
2
# -c 表示以集群模式登录,-h 集群内任意ip
redis-cli --user admin --pass 123456 -c -h 10.250.0.235
  • 查看集群信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
10.250.0.235:6379> cluster info
# 输出集群状态
cluster_state:ok # 集群整体状态:ok 表示集群当前可用、健康
cluster_slots_assigned:16384 # 已分配的哈希槽数量(总槽数固定为 16384)
cluster_slots_ok:16384 # 正常工作的槽数量(等于已分配槽,说明全部正常)
cluster_slots_pfail:0 # 处于“疑似失败(pfail)”状态的槽数量
cluster_slots_fail:0 # 被判定为失败(fail)的槽数量
cluster_known_nodes:6 # 当前节点已知的集群节点总数(主节点 + 从节点)
cluster_size:3 # 主节点数量(3 主节点,典型的 3 主 3 从结构)
cluster_current_epoch:6 # 集群当前的全局纪元(用于选举和配置同步)
cluster_my_epoch:1 # 当前这个节点所在的纪元
cluster_stats_messages_ping_sent:159 # 当前节点已发送的 PING 消息数量(心跳)
cluster_stats_messages_pong_sent:156 # 当前节点已发送的 PONG 消息数量(心跳响应)
cluster_stats_messages_sent:315 # 当前节点发送的所有集群消息总数
cluster_stats_messages_ping_received:151 # 当前节点收到的 PING 消息数量
cluster_stats_messages_pong_received:159 # 当前节点收到的 PONG 消息数量
cluster_stats_messages_meet_received:5 # 当前节点收到的 MEET 消息数量(新节点加入发现)
cluster_stats_messages_received:315 # 当前节点收到的所有集群消息总数
total_cluster_links_buffer_limit_exceeded:0 # 因输出缓冲区超限被强制断开的集群连接数(0 = 正常)
  • 查看节点列表

1
2
3
4
5
6
7
8
9
10
11
12
13
10.250.0.235:6379> cluster nodes
# 当前节点(myself),角色为 master,负责槽位 0-5460,是本机所在的主节点
afcb754ce8cc79122fe9bcd8c1567bbf13258fce 10.250.0.235:6379@16379 myself,master - 0 0 1 connected 0-5460
# 从节点(slave),对应的主节点是 10.250.0.36 这个 master(负责槽位 10923-16383)
547fbd934293ddb5eb770e111b65910f4e604023 10.250.0.71:6379@16379 slave 88762f7d0bbb99bbaf68556ef5fd113cba46d295 0 1765033120132 3 connected
# 从节点(slave),对应的主节点是 10.250.0.58 这个 master(负责槽位 5461-10922)
119e5823cccafef506b9b256aad206678eab7d41 10.250.0.63:6379@16379 slave 2527142b7cffaf6bb92608550c919a0db0607c39 0 1765033118000 2 connected
# 从节点(slave),对应的主节点是当前节点 10.250.0.235(负责槽位 0-5460)
17b33861e6b086b86902fe75f79e5b878bd26f94 10.250.0.131:6379@16379 slave afcb754ce8cc79122fe9bcd8c1567bbf13258fce 0 1765033119000 1 connected
# 主节点(master),负责槽位 10923-16383(集群中第三段槽位)
88762f7d0bbb99bbaf68556ef5fd113cba46d295 10.250.0.36:6379@16379 master - 0 1765033117000 3 connected 10923-16383
# 主节点(master),负责槽位 5461-10922(集群中第二段槽位)
2527142b7cffaf6bb92608550c919a0db0607c39 10.250.0.58:6379@16379 master - 0 1765033119126 2 connected 5461-10922
  • 此时查看nodes-6379.conf也会看到和上面一样的节点信息

  • 此时关闭其中一个master节点,比如10.250.0.36,则其对应的slave节点10.250.0.71会切换为新的master节点,此时10.250.0.36的状态最终变为fail

1
2
3
4
5
6
7
8
10.250.0.235:6379> cluster nodes
## 输出
afcb754ce8cc79122fe9bcd8c1567bbf13258fce 10.250.0.235:6379@16379 myself,master - 0 0 1 connected 0-5460
547fbd934293ddb5eb770e111b65910f4e604023 10.250.0.71:6379@16379 master - 0 1765033733534 7 connected 10923-16383
119e5823cccafef506b9b256aad206678eab7d41 10.250.0.63:6379@16379 slave 2527142b7cffaf6bb92608550c919a0db0607c39 0 1765033734542 2 connected
17b33861e6b086b86902fe75f79e5b878bd26f94 10.250.0.131:6379@16379 slave afcb754ce8cc79122fe9bcd8c1567bbf13258fce 0 1765033732526 1 connected
88762f7d0bbb99bbaf68556ef5fd113cba46d295 10.250.0.36:6379@16379 master,fail - 1765033690200 1765033686170 3 connected
2527142b7cffaf6bb92608550c919a0db0607c39 10.250.0.58:6379@16379 master - 0 1765033735550 2 connected 5461-10922
  • 再次启动10.250.0.36,其会变成10.250.0.71的slave节点

1
2
3
4
5
6
7
8
10.250.0.235:6379> cluster nodes
## 输出
afcb754ce8cc79122fe9bcd8c1567bbf13258fce 10.250.0.235:6379@16379 myself,master - 0 0 1 connected 0-5460
547fbd934293ddb5eb770e111b65910f4e604023 10.250.0.71:6379@16379 master - 0 1765033859000 7 connected 10923-16383
119e5823cccafef506b9b256aad206678eab7d41 10.250.0.63:6379@16379 slave 2527142b7cffaf6bb92608550c919a0db0607c39 0 1765033860493 2 connected
17b33861e6b086b86902fe75f79e5b878bd26f94 10.250.0.131:6379@16379 slave afcb754ce8cc79122fe9bcd8c1567bbf13258fce 0 1765033858000 1 connected
88762f7d0bbb99bbaf68556ef5fd113cba46d295 10.250.0.36:6379@16379 slave 547fbd934293ddb5eb770e111b65910f4e604023 0 1765033859488 7 connected
2527142b7cffaf6bb92608550c919a0db0607c39 10.250.0.58:6379@16379 master - 0 1765033859000 2 connected 5461-10922
  • 若此时还是希望 10.250.0.36 做为主节点,则需要先登录10.250.0.36,再执行如下命令

1
2
3
4
5
# 注意要加 -c
redis-cli -c --user admin --pass 123456 -h 10.250.0.36
10.250.0.36:6379> cluster failover # 安全版(等待复制同步)
# 或者
10.250.0.36:6379> CLUSTER FAILOVER TAKEOVER # TAKEOVER 会立即切主,不会等待复制数据,非常强制(生产环境不推荐)
  • redis集群会将2的14次幂(16384)的slot平均分配到所有master上,然后对key进行hash后计算应该存储到那个slot

1
2
3
4
5
6
7
HASH_SLOT=CRC16(key) mod 16384

# 跳转重定位
10.250.0.235:6379> set name zhangsan
# 输出
-> Redirected to slot [5798] located at 10.250.0.58:6379
OK
  • 关闭集群,6个redis分别关闭

1
redis-cli -c -h 10.250.0.235 -p 6379 --user admin --pass 123456 shutdown
  • 重启集群,6个redis分别启动即可

1
redis-server redis-6379.conf
  • mset/mget要求key都落在同一个slot上,每个key都加上哈希标签(Hash Tag)-- {xxx},其必须用{}括起来,xxx可以是任意字符串,计算slot时,只会根据xxx来计算hash值,这样就保证了所有key中包含{xxx}的key都会落到同一个slot,{xxx}可以放在key的任意位置

1
2
3
4
5
6
7
8
9
10
10.250.0.235:6379> mset name1 lisi name2 wangwu
(error) CROSSSLOT Keys in request don't hash to the same slot

10.250.0.235:6379> mset {user}:name1 lisi {user}:name2 wangwu
OK

10.250.0.235:6379> mget {user}:name1 {user}:name2
-> Redirected to slot [5474] located at 10.250.0.58:6379
1) "lisi"
2) "wangwu"

注意:
{…} 让多个 key 落在同一个 slot,支持跨 key 原子操作
只有 第一个匹配的 {…} 会被当做 tag
{} 不能嵌套
空标签 {} 是非法的
{abc} 和 {def} 就落不同 slot

  • 如何判断 key 落在哪个节点?

1
2
3
10.250.0.235:6379> cluster keyslot name1
# 输出的数值就表示 slot
(integer) 5461 # slot值
  • 如何查看指定的slot中有多少个key?

1
2
3
10.250.0.235:6379> cluster countkeysinslot 5461
# 输出
(integer) 1 # 表示slot中key的个数,这里显示只有1个key
  • 集群推举新的master时要求至少一半的master同意,所以一个集群至少需要3个master,官方推荐master节点数为奇数,比如3个和4个master节点,都至多允许一个master节点挂掉时进行选主,但是3个master可以节省资源

  • 集群通过10000+port这个端口号进行集群间通信,所以除了要开放prot这个端口,还要开放10000+port这个端口

  • 有关redis集群及其水平扩展的进一步说明,可以参看Redis集群

集群优点

  • 无中心架构,集群内部自行维护数据的分片和主从的切换

  • 数据分片存储,提供很高的访问效率

  • 高可用性,可实现部分节点不可用时,集群仍可用

  • 高扩展性,可以横向扩展1000个节点后依旧保证访问效率,扩容缩容都支持

集群缺点

  • 数据通过异步复制,不保证数据的强一致性

  • 不支持多数据库空间,单机下的redis可以支持到16个数据库,集群模式下只能使用1个数据库空间,即db 0

  • 不支持跨slot操作,如使用mset、mget目前只支持具有相同slot值的Key执行批量操作

  • Key作为数据分区的最小粒度,不能将一个很大的键值对象如hash、list等映射到不同的节点

  • Key事务操作支持有限,只支持多key在同一节点上的事务操作,当多个Key分布于不同的节点上时无法使用事务功能

  • 不建议使用pipeline和multi-keys操作

  • 另外,如果集群内节点时间不同步,可能存在脏写

redis-cli 的 Cluster 管理命令(用于管理/创建/调整集群)

命令 作用 示例
redis-cli --cluster create host1:port host2:port ... 创建 Redis Cluster 集群(自动分配 slots) redis-cli --cluster create 10.0.0.1:7000 10.0.0.2:7000 --cluster-replicas 1
redis-cli --cluster check host:port 检查集群状态、健壮性 redis-cli --cluster check 10.0.0.1:7000
redis-cli --cluster info host:port 显示集群结构、节点、slots 分布 redis-cli --cluster info 10.0.0.1:7000
redis-cli --cluster fix host:port 修复 slots 移动、节点中断等异常状态 redis-cli --cluster fix 10.0.0.1:7000
redis-cli --cluster rebalance host:port 重新分布 slots(自动均衡负载) redis-cli --cluster rebalance 10.0.0.1:7000
redis-cli --cluster rebalance --cluster-threshold <percent> host:port 手动设置 rebalance 阈值;低于此阈值才会调整(百分比) redis-cli --cluster rebalance --cluster-threshold 1 10.0.0.1:7000
redis-cli --cluster add-node newHost:newPort existingHost:existingPort 将新节点加入集群 redis-cli --cluster add-node 10.0.0.3:7000 10.0.0.1:7000
redis-cli --cluster add-node --cluster-slave newHost:newPort existingMaster:port 将新节点作为某主节点的 slave 加入 redis-cli --cluster add-node --cluster-slave 10.0.0.4:7000 10.0.0.1:7000
redis-cli --cluster del-node host:port node_id 从集群删除某节点(必须无 slots) redis-cli --cluster del-node 10.0.0.1:7000 <node-id>
redis-cli --cluster call host:port command ... 在所有节点上批量执行命令 redis-cli --cluster call 10.0.0.1:7000 PING
redis-cli --cluster help 显示 cluster 子命令帮助 redis-cli --cluster help

Redis 内置的 Cluster 操作命令

命令 作用 示例
CLUSTER INFO 查看集群状态、failover 状态、slot 分布统计 CLUSTER INFO
CLUSTER NODES 显示所有节点和角色(master/slave) CLUSTER NODES
CLUSTER MYID 输出本节点 ID CLUSTER MYID
CLUSTER REPLICATE <node-id> 将当前节点设置为某个 master 的 slave CLUSTER REPLICATE <node-id>
CLUSTER FAILOVER 主动 failover(slave 升级为 master) 从节点执行:CLUSTER FAILOVER
CLUSTER FAILOVER FORCE 不等待复制同步,立刻切主 CLUSTER FAILOVER FORCE
CLUSTER FAILOVER TAKEOVER 强制接管 slot(完全覆盖 master)(危险) CLUSTER FAILOVER TAKEOVER
CLUSTER ADDSLOTS <slot...> 将 slots 分配给当前 master CLUSTER ADDSLOTS 0 1 2
CLUSTER DELSLOTS <slot...> 从当前节点移除 slots CLUSTER DELSLOTS 0 1 2
CLUSTER SETSLOT <slot> NODE <node-id> 直接指定某个 slot 属于某个节点 CLUSTER SETSLOT 0 NODE <id>
CLUSTER SETSLOT <slot> IMPORTING <node-id> 设定迁移 key 的源节点(用于 slot 迁移) -
CLUSTER SETSLOT <slot> MIGRATING <node-id> 设定迁移 key 的目标节点(用于 slot 迁移) -
CLUSTER KEYSLOT key 返回 key 所属 slot CLUSTER KEYSLOT mykey
CLUSTER COUNT-FAILURE-REPORTS <node-id> 查看某节点的 fail 票数 -
CLUSTER RESET 删除节点全部集群信息(用来重置为 standalone) CLUSTER RESET HARD