Redis 5.0.7 讲解,单机、集群模式搭建

Redis 5.0.7 讲解,单机、集群模式搭建

一、Redis 介绍

不管你是从事 Python、Java、Go、PHP、Ruby等等... Redis都应该是一个比较熟悉的中间件。而大部分经常写业务代码的程序员,实际工作中或许只用到了 set value、get value 两个操作。

Redis 概念

Redis 是一个开源的底层使用 C 语言编写的 key-value 存储数据库。可用于缓存、事件发布订阅、高速队列等场景。而且支持丰富的数据类型:string(字符串)、hash(哈希)、list(列表)、set(无序集合)、zset(有序集合)

Redis 在 3.0 版本前只支持单实例模式,虽然支持主从模式、哨兵模式部署来解决单点故障,但是现在互联网企业动辄大几百 G 的数据,可完全是没法满足业务的需求,所以,Redis 在 3.0 版本以后就推出了集群模式。

Redis 应用场景

  1. 缓存数据:最常用,对经常需要查询且变动不是很频繁的数据。
  2. 消息队列:相当于消息订阅系统,类似与 RabbitMQ、ActiveMQ、RocketMQ。如果对数据有较高一致性要求时,还是建议使用 MQ。
  3. 计数器:比如统计点击率、点赞率,Redis 具有原子性,可以避免并发问题。
  4. 电商网站信息:大型电商平台初始化页面数据的缓存。比如去哪儿网购买机票的时候首页的价格和你点进去的价格会有差异。
  5. 热点数据:比如新闻网站实时热点、微博热搜等,需要频繁更新。总数据量比较大的时候直接从数据库查询会影响性能。
  6. 分布式锁:分布式程序可以用 Redis 来存储锁信息。

Redis 数据类型

类型 说明
string(字符串) string 是 Redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。string 类型是二进制安全的。意思是 Redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象 。string 类型是 Redis 最基本的数据类型,一个键最大能存储 512MB。
hash(哈希) Redis hash 是一个键值对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。每个 hash 可以存储 2 * 32 - 1 键值对(4294967295, 每个哈希可存储 40 多亿个成员)。
list(列表) Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。列表最多可存储 2 * 32 - 1元素 (4294967295, 每个列表可存储 40 多亿个成员)。
set(无序集合) Redis 的 set 是 string 类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中最大的成员数为 2 * 32 - 1 (4294967295, 每个集合可存储 40 多亿个成员)。
zset(有序集合) Redis zset 和 set 一样也是 string 类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。 zset 的成员是唯一的,但分数(score)却可以重复。

Redis 数据类型应用场景

前面提到了 Redis 支持五种丰富的数据类型,那么在不同场景下的选择

string

字符串是最常用的数据类型,他能够存储任何类型的字符串,当然也包括二进制、JSON化的对象、甚至是base64编码之后的图片。在Redis中一个字符串最大的容量为512MB,可以说是无所不能了。

hash

常用作存储结构化数据、比如论坛系统中可以用来存储用户的Id、昵称、头像、积分等信息。如果需要修改其中的信息,只需要通过Key取出Value进行反序列化修改某一项的值,再序列化存储到Redis中,Hash结构存储,由于Hash结构会在单个Hash元素在不足一定数量时进行压缩存储,所以可以大量节约内存。这一点在String结构里是不存在的。

list

List的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis 内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。另外,可以利用 lrange 命令,做基于 Redis 的分页功能,性能极佳,用户体验好。

set

set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,这个时候就可以选择使用set。

zset

可以按照某个条件的权重进行排序,比如可以通过点击数做出排行榜的数据应用。

Redis 优势和缺点

优势:

  1. 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)。
  2. 支持丰富数据类型,支持string,list,set,sorted set,hash。
  3. 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行。
  4. 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除。

缺点:

  1. 由于 Redis 是内存数据库,所以,单台机器,存储的数据量,跟机器本身的内存大小。虽然 Redis 本身有 Key 过期策略,但是还是需要提前预估和节约内存。如果内存增长过快,需要定期删除数据。
  2. Redis 是单线程的,单台服务器无法充分利用多核服务器的 CPU。

Redis 相比同类型的 Memcached 有哪些优势?

  1. Memcached 所有的值均是简单的字符串,Redis 作为其替代者,支持更为丰富的数据类型。
  2. Redis 的速度比 Memcached 快很多
  3. Redis 可以持久化其数据到硬盘

Redis 常见性能问题和解决方案

  1. Master 最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件
  2. 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次
  3. 为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网内
  4. 尽量避免在压力很大的主库上增加从库
  5. 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3…这样的结构方便解决单点故障问题,实现 Slave 对 Master 的替换。如果 Master 挂了,可以立刻启用 Slave1 做 Master,其他不变。

二、Redis 单机安装

服务器系统为 centos 7.5,Redis 版本为 5.0.7,采用源码方式安装。

安装

yum install -y gcc
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
tar xzf redis-5.0.7.tar.gz
cd redis-5.0.7
make
mkdir -p /usr/local/redis/bin
cp src/redis-server /usr/local/redis/bin
cp src/redis-cli /usr/local/redis/bin
cp src/redis-sentinel /usr/local/redis/bin
cp src/redis-trib.rb /usr/local/redis/bin
cp src/redis-check-aof /usr/local/redis/bin
cp src/redis-check-rdb /usr/local/redis/bin
cp src/redis-benchmark /usr/local/redis/bin
echo 'export PATH=$PATH:/usr/local/redis/bin' >> .bash_profile
. .bash_profile
cp ./redis.conf /etc

配置

vim /etc/redis.conf,修改其中配置:

bind 0.0.0.0	# 把 127.0.0.1 改为 0.0.0.0,监听所有 IPV4 地址,可以根据需求设置
daemonize yes	# 把 no 修改为 yes,后台运行

启动

$ redis-server /etc/redis.conf

验证

$ redis-cli 
127.0.0.1:6379> 
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> 

也可以通过桌面客户端验证:redis desktop manager - https://github.com/uglide/RedisDesktopManager/releases

设置开机启动

vim /usr/lib/systemd/system/redis.service:

[Unit]
Description=Redis Server
After=network.target

[Service]
Type=simple
# User=redis
# Group=redis
PIDFile=/var/run/redis.pid
ExecStart=/usr/local/redis/bin/redis-server /etc/redis.conf --daemonize no
# ExecStop=/usr/local/redis/bin/redis-cli shutdown
ExecStop=/usr/local/redis/bin/redis-cli -p 6379 shutdown
Restart=always
 
[Install]
WantedBy=multi-user.target
systemctl daemon-reload 
systemctl start redis
systemctl enable redis

三、Redis 集群安装

2018 年 10 月 Redis 发布了稳定版本的 5.0 版本,推出了各种新特性,其中一点是放弃 Ruby 的集群方式,改为 使用 C 语言编写的 redis-cli 的方式,是集群的构建方式复杂度大大降低。

服务器系统为 centos 7.5,Redis 版本为 5.0.7,采用源码方式安装。在一台服务器上搭建有 6 个节点的 Redis 集群。(因为Redis 集群最低 6 个节点,不然无法创建)

安装

yum install -y gcc
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
tar xzf redis-5.0.7.tar.gz
cd redis-5.0.7
make
mkdir -p /usr/local/redis/bin
cp src/redis-server /usr/local/redis/bin
cp src/redis-cli /usr/local/redis/bin
cp src/redis-sentinel /usr/local/redis/bin
cp src/redis-trib.rb /usr/local/redis/bin
cp src/redis-check-aof /usr/local/redis/bin
cp src/redis-check-rdb /usr/local/redis/bin
cp src/redis-benchmark /usr/local/redis/bin
echo 'export PATH=$PATH:/usr/local/redis/bin' >> .bash_profile
. .bash_profile

创建 6 个配置文件并配置

mkdir /etc/redis-cluster
cp redis.conf /etc/redis-cluster/redis-7001.conf
cp redis.conf /etc/redis-cluster/redis-7002.conf
cp redis.conf /etc/redis-cluster/redis-7003.conf
cp redis.conf /etc/redis-cluster/redis-7004.conf
cp redis.conf /etc/redis-cluster/redis-7005.conf 
cp redis.conf /etc/redis-cluster/redis-7006.conf
mkdir /opt/redis-7001
mkdir /opt/redis-7002
mkdir /opt/redis-7003
mkdir /opt/redis-7004
mkdir /opt/redis-7005
mkdir /opt/redis-7006

修改所有的配置文件 (端口以及目录依次类推)

port 7001	# 监听端口
bind 0.0.0.0  # 监听 ip
dir /opt/redis-7001		# 指定文件存放路径 ( .rdb .aof nodes-xxxx.conf 这样的文件都会在此路径下)
cluster-enabled yes   # 启动集群模式 
cluster-config-file nodes-7001.conf		# 集群节点配置文件
daemonize yes		# 后台启动
cluster-node-timeout 5000		# 集群节点超时时间​
appendonly yes		# 指定持久化方式,开启 AOF 模式
protected-mode no	# 非保护模式

启动节点

redis-server /etc/redis-cluster/redis-7001.conf
redis-server /etc/redis-cluster/redis-7002.conf
redis-server /etc/redis-cluster/redis-7003.conf
redis-server /etc/redis-cluster/redis-7004.conf
redis-server /etc/redis-cluster/redis-7005.conf
redis-server /etc/redis-cluster/redis-7006.conf

创建集群

redis-cli --cluster create 192.168.223.111:7001 192.168.223.111:7002 192.168.223.111:7003 192.168.223.111:7004 192.168.223.111:7005 192.168.223.111:7006 --cluster-replicas 1
  • --replicas 1 表示为集群中的每个主节点创建一个从节点,6 个节点就是 3 主 3 从。

结果

>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.223.111:7005 to 192.168.223.111:7001
Adding replica 192.168.223.111:7006 to 192.168.223.111:7002
Adding replica 192.168.223.111:7004 to 192.168.223.111:7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001
   slots:[0-5460] (5461 slots) master
M: 9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002
   slots:[5461-10922] (5462 slots) master
M: 15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003
   slots:[10923-16383] (5461 slots) master
S: 70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004
   replicates 9a347d87b115ab8be8662771aa2d0579465ae6ff
S: 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005
   replicates 15e768a013d6042de80b82aa2274ffcf30381085
S: ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006
   replicates b3919787aa7bc4123e5f87b8995680e2187bf4cc
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 192.168.223.111:7001)
M: b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006
   slots: (0 slots) slave
   replicates b3919787aa7bc4123e5f87b8995680e2187bf4cc
M: 15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004
   slots: (0 slots) slave
   replicates 9a347d87b115ab8be8662771aa2d0579465ae6ff
S: 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005
   slots: (0 slots) slave
   replicates 15e768a013d6042de80b82aa2274ffcf30381085
M: 9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002
   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 -c -h 192.168.223.111 -p 7001
192.168.223.111:7001> cluster info
cluster_state:ok	# 集群状态
cluster_slots_assigned:16384	# 槽分配
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:371
cluster_stats_messages_pong_sent:382
cluster_stats_messages_sent:753
cluster_stats_messages_ping_received:377
cluster_stats_messages_pong_received:371
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:753
192.168.223.111:7001> 

查看节点信息

$ redis-cli -c -h 192.168.223.111 -p 7001
192.168.223.111:7001> cluster nodes
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575617014596 6 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 master - 0 1575617015504 3 connected 10923-16383
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 slave 9a347d87b115ab8be8662771aa2d0579465ae6ff 0 1575617014496 4 connected
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 slave 15e768a013d6042de80b82aa2274ffcf30381085 0 1575617014000 5 connected
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575617013000 1 connected 0-5460
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 master - 0 1575617015000 2 connected 5461-10922
192.168.223.111:7001> 

或者

$ redis-cli --cluster check 192.168.223.111:7001
192.168.223.111:7001 (b3919787...) -> 1 keys | 5461 slots | 1 slaves.
192.168.223.111:7003 (15e768a0...) -> 0 keys | 5461 slots | 1 slaves.
192.168.223.111:7002 (9a347d87...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 2 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.223.111:7001)
M: b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006
   slots: (0 slots) slave
   replicates b3919787aa7bc4123e5f87b8995680e2187bf4cc
M: 15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004
   slots: (0 slots) slave
   replicates 9a347d87b115ab8be8662771aa2d0579465ae6ff
S: 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005
   slots: (0 slots) slave
   replicates 15e768a013d6042de80b82aa2274ffcf30381085
M: 9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002
   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.

集群测试

[root@k8s1 ~]# redis-cli -c -h 192.168.223.111 -p 7001
192.168.223.111:7001> set name test
-> Redirected to slot [5798] located at 192.168.223.111:7002
OK
192.168.223.111:7002> set age 18
-> Redirected to slot [741] located at 192.168.223.111:7001
OK
192.168.223.111:7001> get name
-> Redirected to slot [5798] located at 192.168.223.111:7002
"test"
192.168.223.111:7002> get age
-> Redirected to slot [741] located at 192.168.223.111:7001
"18"
192.168.223.111:7001> 

可以看到,客户端连接加 -c 选项的时候,存储和提取 key 的时候不断在 7001 和 7002 之间跳转,这个称为客户端重定向。之所以发生客户端重定向,是因为
Redis Cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽(hash slot)的方式来分配的。Redis Cluster 默认分配了 16384 个 slot,当 set 一个 key 时,会用 CRC16 算法来取模得到所属的 slot,然后将这个 key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。所以在测试的时候看到set 和 get 的时候,会跳转节点。Redis 集群会把数据存在一个 Master 节点,然后在这个 Master 节点和其对应的 Salve 节点之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。只有当一个 Master 节点挂掉之后,才会启动一个对应的 Salve 节点,充当 Master 节点。

扩充:客户端默认只能从 Master 节点上获取数据,不能从 Slave 节点获取;如果需要直接从 Slave 节点获取数据,客户端可以设置为 readonly 模式,具体参考官方文档。

集群故障切换测试

首先查看当前主节点信息:

$ redis-cli -p 7001 cluster nodes | grep master 
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 master - 0 1575618684601 3 connected 10923-16383
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575618685000 7 connected 5461-10922
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575618685000 1 connected 0-5460

模拟崩溃主节点 7003:

$ redis-cli -p 7003 debug segfault
Error: Server closed the connection

debug segfault 命令执行一个非法的内存访问从而让 Redis 崩溃,仅在开发时用于 bug 调试。

再次查看当前主节点信息:

$ redis-cli -p 7001 cluster nodes | grep master 
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 master,fail - 1575618827980 1575618827074 3 disconnected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575618873502 7 connected 5461-10922
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575618875000 9 connected 10923-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575618873000 1 connected 0-5460

可以看到 7003 已是 fail 状态,并且 7005 已经成为新的 Master 节点

重新启动 7003:

$ redis-server /etc/redis-cluster/redis-7003.conf  
81882:C 06 Dec 2019 15:57:17.086 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
81882:C 06 Dec 2019 15:57:17.086 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=81882, just started
81882:C 06 Dec 2019 15:57:17.086 # Configuration loaded

$ redis-cli -p 7001 cluster nodes
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575619045171 6 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 slave 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 0 1575619044666 9 connected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575619044000 7 connected 5461-10922
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575619045000 9 connected 10923-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575619045000 1 connected 0-5460
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 slave 70b40a69c2ee564cf1e1ff59f26b1a754443509e 0 1575619044565 7 connected

可以看到重新启动的 7003 已经成为 7005 的 Slave 节点

注意: 当存活的 Master 节点小于总节点数的一半时,整个集群就无法提供服务了。

添加节点

两种情况,添加一个 Master 节点或者 Slave 节点。

添加 Master 节点

redis-cli --cluster add-node 192.168.223.111:7007 192.168.223.111:7001
  • 第一个参数(192.168.223.111:7007) 为新加入的节点,具体配置参照前面部分。
  • 第二个参数(192.168.223.111:7001)为集群中任一正常节点。
$ redis-cli -p 7001 cluster nodes
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575619906900 6 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 slave 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 0 1575619907405 9 connected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575619906601 7 connected 5461-10922
0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007@17007 master - 0 1575619906000 0 connected
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575619907908 9 connected 10923-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575619907000 1 connected 0-5460
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 slave 70b40a69c2ee564cf1e1ff59f26b1a754443509e 0 1575619906000 7 connected

可以看到已经成功的向集群中添加了 Master 节点 7007,但是这个 Master 节点还没有成为真正的 Master 节点,因为还没有分配槽(slot),也没有从节点,现在要给它分配槽(slot)。

[root@k8s1 ~]# redis-cli --cluster reshard 192.168.223.111:7001
>>> Performing Cluster Check (using node 192.168.223.111:7001)
M: b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006
   slots: (0 slots) slave
   replicates b3919787aa7bc4123e5f87b8995680e2187bf4cc
S: 15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003
   slots: (0 slots) slave
   replicates 478491a5f75d8fbceeaa7a61bbc4866b5893b99c
M: 70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007
   slots: (0 slots) master
M: 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002
   slots: (0 slots) slave
   replicates 70b40a69c2ee564cf1e1ff59f26b1a754443509e
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 2048   # 指定分配多少个槽
What is the receiving node ID? 0be08034ff73657bb525158821ab0210894af917		# 分配到哪个节点(ID)?
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1: all		# 选择 all

Ready to move 2048 slots.
  Source nodes:
    M: b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001
       slots:[0-5460] (5461 slots) master
       1 additional replica(s)
    M: 70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004
       slots:[5461-10922] (5462 slots) master
       1 additional replica(s)
    M: 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005
       slots:[10923-16383] (5461 slots) master
       1 additional replica(s)
  Destination node:
    M: 0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007
       slots: (0 slots) master
  Resharding plan:
    Moving slot 5461 from 70b40a69c2ee564cf1e1ff59f26b1a754443509e
...
...
...
Moving slot 11604 from 192.168.223.111:7005 to 192.168.223.111:7007: 

$ redis-cli --cluster check 192.168.223.111:7001
192.168.223.111:7001 (b3919787...) -> 1 keys | 4779 slots | 1 slaves.
192.168.223.111:7004 (70b40a69...) -> 0 keys | 4779 slots | 1 slaves.
192.168.223.111:7007 (0be08034...) -> 1 keys | 2047 slots | 0 slaves.
192.168.223.111:7005 (478491a5...) -> 0 keys | 4779 slots | 1 slaves.
[OK] 2 keys in 4 masters.
...
...
...
[OK] All 16384 slots covered.

可以看到新的 Master 节点 7007 已经获取到了新分配的槽,并且其目前还没有 Slave 节点。

添加 Slave 节点

redis-cli --cluster add-node 192.168.223.111:7008 192.168.223.111:7001 --cluster-slave --cluster-master-id 0be08034ff73657bb525158821ab0210894af917
  • 如果不指定 --cluster-master-id 参数, Redis Cluster 会将新加入的 Slave 节点随机分配给一个 Master 节点,这里指定 Master 节点 7007。
$ redis-cli -p 7001 cluster nodes
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575621163000 6 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 slave 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 0 1575621163562 9 connected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575621164067 7 connected 6144-10922
0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007@17007 master - 0 1575621163057 10 connected 0-681 5461-6143 10923-11604
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575621164572 9 connected 11605-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575621162000 1 connected 682-5460
629a4e7bafac9522b974b0a12f7cd28d7be51cfd 192.168.223.111:7008@17008 slave 0be08034ff73657bb525158821ab0210894af917 0 1575621165077 10 connected
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 slave 70b40a69c2ee564cf1e1ff59f26b1a754443509e 0 1575621163000 7 connected

可以看到 7008 已经成为 7007 的 Slave 节点。

平衡各节点槽数量

当前新加 Master 节点后各节点的槽可能会分配不均匀。

$ redis-cli --cluster info 192.168.223.111:7001
192.168.223.111:7001 (b3919787...) -> 1 keys | 4779 slots | 1 slaves.
192.168.223.111:7004 (70b40a69...) -> 0 keys | 4779 slots | 1 slaves.
192.168.223.111:7007 (0be08034...) -> 1 keys | 2047 slots | 1 slaves.
192.168.223.111:7005 (478491a5...) -> 0 keys | 4779 slots | 1 slaves.
[OK] 2 keys in 4 masters.
0.00 keys per slot on average.

可以重新分配

$ redis-cli --cluster rebalance --cluster-threshold 1 192.168.223.111:7001
>>> Performing Cluster Check (using node 192.168.223.111:7001)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Rebalancing across 4 nodes. Total weight = 4.00
...
...
...

$ redis-cli --cluster info 192.168.223.111:7001
192.168.223.111:7001 (b3919787...) -> 0 keys | 4096 slots | 1 slaves.
192.168.223.111:7004 (70b40a69...) -> 0 keys | 4096 slots | 1 slaves.
192.168.223.111:7007 (0be08034...) -> 2 keys | 4096 slots | 1 slaves.
192.168.223.111:7005 (478491a5...) -> 0 keys | 4096 slots | 1 slaves.
[OK] 2 keys in 4 masters.
0.00 keys per slot on average.

可以看到已重新分配。

Slave 节点重新分配

首先查看集群信息

$ redis-cli -p 7001 cluster nodes
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575622162000 6 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 slave 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 0 1575622162506 9 connected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575622162000 7 connected 6827-10922
0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007@17007 master - 0 1575622162706 10 connected 0-1364 5461-6826 10923-12287
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575622162000 9 connected 12288-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575622161000 1 connected 1365-5460
629a4e7bafac9522b974b0a12f7cd28d7be51cfd 192.168.223.111:7008@17008 slave 0be08034ff73657bb525158821ab0210894af917 0 1575622161000 10 connected
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 slave 70b40a69c2ee564cf1e1ff59f26b1a754443509e 0 1575622162202 7 connected
[root@k8s1 ~]# 
[root@k8s1 ~]# 

可以看到当前 7002 是 7004 的 Slave 节点,如果想把 7002 变成 7001 的 Slave 节点,则首先登陆 7002 节点执行以下操作:

$ redis-cli -c -h 192.168.223.111 -p 7002
192.168.223.111:7002> cluster replicate b3919787aa7bc4123e5f87b8995680e2187bf4cc
OK
192.168.223.111:7002> exit

$ redis-cli -p 7001 cluster nodes        
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575622409000 6 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 slave 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 0 1575622410891 9 connected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575622410588 7 connected 6827-10922
0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007@17007 master - 0 1575622409881 10 connected 0-1364 5461-6826 10923-12287
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575622410083 9 connected 12288-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575622410000 1 connected 1365-5460
629a4e7bafac9522b974b0a12f7cd28d7be51cfd 192.168.223.111:7008@17008 slave 0be08034ff73657bb525158821ab0210894af917 0 1575622409000 10 connected
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575622410000 7 connected
[root@k8s1 ~]# 
  • b3919787aa7bc4123e5f87b8995680e2187bf4cc 为 7001 的 ID。
  • 可以看到 7002 已经变成 7001 的 Slave 节点。

删除节点

分两种情况:删除 Master 节点和 Slave 节点。

删除 Slave 节点

比较简单

$ redis-cli  --cluster del-node 192.168.223.111:7001 629a4e7bafac9522b974b0a12f7cd28d7be51cfd
>>> Removing node 629a4e7bafac9522b974b0a12f7cd28d7be51cfd from cluster 192.168.223.111:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
  • 629a4e7bafac9522b974b0a12f7cd28d7be51cfd 为 Slave 节点 7008 的 ID。
$ redis-cli -p 7001 cluster nodes
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575622972929 6 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 slave 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 0 1575622972000 9 connected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575622972525 7 connected 6827-10922
0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007@17007 master - 0 1575622971515 10 connected 0-1364 5461-6826 10923-12287
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575622971000 9 connected 12288-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575622972000 1 connected 1365-5460
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 slave 70b40a69c2ee564cf1e1ff59f26b1a754443509e 0 1575622973030 7 connected

可以看出 7008 已被删除。

删除 Master 节点

删除 Master 节点相对来说就是复杂一点,主要步骤:

  1. 如果 Master 节点有 Slave 节点,则首先要将 Slave 节点重新分配到其他 Master 节点或者删除。
  2. 如果 Master 节点有槽(slot),则需要去掉分配的槽(slot),然后再删除主节点

Slave 节点重新分配与删除 Slave 参考前面部分,这里主要讲下怎么去掉分配的槽(slot),已 7007 节点为例:

$ redis-cli --cluster info 192.168.223.111:7001
192.168.223.111:7001 (b3919787...) -> 0 keys | 4096 slots | 1 slaves.
192.168.223.111:7004 (70b40a69...) -> 0 keys | 4096 slots | 1 slaves.
192.168.223.111:7007 (0be08034...) -> 2 keys | 4096 slots | 0 slaves.
192.168.223.111:7005 (478491a5...) -> 0 keys | 4096 slots | 1 slaves.
[OK] 2 keys in 4 masters.
0.00 keys per slot on average.
  • 7007 有槽
$ redis-cli --cluster reshard 192.168.223.111:7001
>>> Performing Cluster Check (using node 192.168.223.111:7001)
M: b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
S: ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006
   slots: (0 slots) slave
   replicates b3919787aa7bc4123e5f87b8995680e2187bf4cc
S: 15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003
   slots: (0 slots) slave
   replicates 478491a5f75d8fbceeaa7a61bbc4866b5893b99c
M: 70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
M: 0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
M: 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
S: 9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002
   slots: (0 slots) slave
   replicates 70b40a69c2ee564cf1e1ff59f26b1a754443509e
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 4096	# 7007 的槽个数
What is the receiving node ID? b3919787aa7bc4123e5f87b8995680e2187bf4cc		# 由谁来接手 7007 的槽
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1: 0be08034ff73657bb525158821ab0210894af917	# 7007 节点 ID
Source node #2: done

Ready to move 4096 slots.
  Source nodes:
    M: 0be08034ff73657bb525158821ab0210894af917 192.168.223.111:7007
       slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
  Destination node:
    M: b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001
       slots:[1365-5460] (4096 slots) master
       1 additional replica(s)
  Resharding plan:
    Moving slot 0 from 0be08034ff73657bb525158821ab0210894af917
    ...
    ...
    ...

$ redis-cli --cluster info 192.168.223.111:7001   
192.168.223.111:7001 (b3919787...) -> 2 keys | 8192 slots | 1 slaves.
192.168.223.111:7004 (70b40a69...) -> 0 keys | 4096 slots | 1 slaves.
192.168.223.111:7007 (0be08034...) -> 0 keys | 0 slots | 0 slaves.
192.168.223.111:7005 (478491a5...) -> 0 keys | 4096 slots | 1 slaves.
[OK] 2 keys in 4 masters.
0.00 keys per slot on average.

可以看到 7007 的槽个数已经为 0。执行删除:

$ redis-cli  --cluster del-node 192.168.223.111:7001 0be08034ff73657bb525158821ab0210894af917
>>> Removing node 0be08034ff73657bb525158821ab0210894af917 from cluster 192.168.223.111:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

$ redis-cli -p 7001 cluster nodes
ec514db1730a466cf10d3ee54f32003c7690602a 192.168.223.111:7006@17006 slave b3919787aa7bc4123e5f87b8995680e2187bf4cc 0 1575623784000 11 connected
15e768a013d6042de80b82aa2274ffcf30381085 192.168.223.111:7003@17003 slave 478491a5f75d8fbceeaa7a61bbc4866b5893b99c 0 1575623785208 9 connected
70b40a69c2ee564cf1e1ff59f26b1a754443509e 192.168.223.111:7004@17004 master - 0 1575623784000 7 connected 6827-10922
478491a5f75d8fbceeaa7a61bbc4866b5893b99c 192.168.223.111:7005@17005 master - 0 1575623784703 9 connected 12288-16383
b3919787aa7bc4123e5f87b8995680e2187bf4cc 192.168.223.111:7001@17001 myself,master - 0 1575623784000 11 connected 0-6826 10923-12287
9a347d87b115ab8be8662771aa2d0579465ae6ff 192.168.223.111:7002@17002 slave 70b40a69c2ee564cf1e1ff59f26b1a754443509e 0 1575623784198 7 connected

可以看到已删除 7007 节点。

集群升级

分两种情况:升级 Master 节点和 Slave 节点。

升级 Slave 节点

升级 Slave 节点比较简单,只需要停止 Slave 节点,然后升级 Redis 程序,最后重启即可。

升级 Master 节点

升级 Master 节点相对来说复杂一点,主要步骤:

  1. 使用 debug segfault 使 Master 节点发生故障转换为 Slave 节点(参考前面部分)。
  2. 然后再照升级 Slave 节点的方法升级此节点。