1.1 安装 MySQL 主从复制
1.1.1 主从复制的原理
-
什么是主从复制 主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数据库一般是准实时的业务数据库。
-
主从复制的作用(好处,或者说为什么要做主从)重点!
- 做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。
- 架构的扩展。业务量越来越大,I/O 访问频率过高,单机无法满足,此时做多库的存储,降低磁盘 I/O 访问的频率,提高单个机器的 I/O 性能。
- 读写分离,使数据库能支撑更大的并发。在报表中尤其重要。由于部分报表 SQL 语句非常的慢,导致锁表,影响前台服务。如果前台使用 master,报表使用 slave,那么报表 SQL 将不会造成前台锁,保证了前台速度。
- 主从复制的原理(重中之重,面试必问):
1. 数据库有个 bin-log 二进制文件,记录了所有 SQL 语句。
2. 我们的目标就是把主数据库的 bin-log 文件的 SQL 语句复制过来。
3. 让其在从数据的 relay-log 重做(中继)日志文件中再执行一次这些 SQL 语句即可。
4. 下面的主从配置就是围绕这个原理配置
5. 具体需要三个线程来操作:
5.1 binlog 输出线程:每当有从库连接到主库的时候,主库都会创建一个线程然后发送 binlog 内容到从库。在从库里,当复制开始的时候,从库就会创建两个线程进行处理:
5.2 从库 I/O 线程:当 START SLAVE 语句在从库开始执行之后,从库创建一个 I/O 线程,该线程连接到主库并请求主库发送 binlog 里面的更新记录到从库上。从库 I/O 线程读取主库的 binlog 输出线程发送的更新并拷贝这些更新到本地文件,其中包括 relay log 文件。
5.3 从库的 SQL 线程:从库创建一个 SQL 线程,这个线程读取从库 I/O 线程写到 relay log 的更新事件并执行。
可以知道,对于每一个主从复制的连接,都有三个线程。拥有多个从库的主库为每一个连接到主库的从库创建一个 binlog 输出线程,每一个从库都有它自己的 I/O 线程和 SQL 线程。
主从复制如图:

解读主从复制的流程:
步骤一:主库 db 的更新事件 (update、insert、delete) 被写到 binlog
步骤二:从库发起连接,连接到主库
步骤三:此时主库创建一个 binlog dump thread 线程,把 binlog 的内容发送到从库
步骤四:从库启动之后,创建一个 I/O 线程,读取主库传过来的 binlog 内容并写入到 relay log.
步骤五:还会创建一个 SQL 线程,从 relay log 里面读取内容,从 Exec_Master_Log_Pos 位置开始执行读取到的更新事件,将更新内容写入到 slave 的 db.
- 主从复制的方式
1. 一主一从
2. 主主复制
3. 一主多从 —— 扩展系统读取的性能,因为读是在从库读取的;
4. 多主一从 —— 5.7开始支持
5. 联级复制
在课堂上我们带领大家搭建的是一主一从。
1.1.2 主从复制搭建的步骤
第一步:新建主服务器容器实例 3307
[root@shjava101 ~]# docker run -p 3307:3306 --name mysql-master \
> -v /mydata/mysql-master/log:/var/log/mysql \
> -v /mydata/mysql-master/data:/var/lib/mysql \
> -v /mydata/mysql-master/conf:/etc/mysql \
> -e MYSQL_ROOT_PASSWORD=root \
> -d mysql:5.7
be8a585a72b3639e532d77277ad9cc6ffe608e0a354598d265edba6def88a9a9
[root@shjava101 ~]# docker ps # 查看mysql容器是否运行
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be8a585a72b3 mysql:5.7 "docker-entrypoint.s…" 12 seconds ago Up 7 seconds 33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp mysql-master
第二步:进入 /mydata/mysql-master/conf 目录下新建 my.cnf
我们使用 vim my.cnf 命令,创建一个 MySQL 配置文件,然后输入:
[mysqld]
## 设置 server_id,同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed, statement, row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为 0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免 slave 端复制中断。
## 如:1062 错误是指一些主键重复,1032 错误是因为主从数据库数据不一致
slave_skip_errors=1062
[root@shjava101 ~]# cd /mydata/mysql-master/conf
[root@shjava101 conf]# vim my.cnf
然后输入以下配置内容:

第三步:修改完配置后重启 master 实例
由于修改了配置文件信息,我们需要重启 MySQL 容器
[root@shjava101 conf]# docker restart mysql-master
mysql-master
第四步:进入 mysql-master 容器
进入 MySQL 数据库容器,登录 MySQL 数据库
[root@shjava101 conf]# docker exec -it mysql-master /bin/bash
root@be8a585a72b3:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36-log MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
第五步:master 容器实例内创建数据同步用户
mysql> CREATE USER 'slave'@'%' IDENTIFIED BY '123456'; # 创建数据同步的用户
Query OK, 0 rows affected (0.19 sec)
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%'; # 对用户进行授权操作
Query OK, 0 rows affected (0.00 sec)
第六步:新建从服务器容器实例 3308
[root@shjava101 conf]# docker run -p 3308:3306 --name mysql-slave \
> -v /mydata/mysql-slave/log:/var/log/mysql \
> -v /mydata/mysql-slave/data:/var/lib/mysql \
> -v /mydata/mysql-slave/conf:/etc/mysql \
> -e MYSQL_ROOT_PASSWORD=root \
> -d mysql:5.7
2fd617d42f907f30c2cb468d6f4552987f406ab25d6fa52ba1545e4336354c94
第七步:进入 /mydata/mysql-slave/conf 目录下新建 my.cnf
使用命令 vim my.cnf 新建 my.cnf,并准备对应的配置文件内容
[mysqld]
## 设置 server_id,同一局域网中需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备 Slave 作为其它数据库实例的 Master 时使用
log-bin=mall-mysql-slave1-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed, statement, row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为 0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免 slave 端复制中断。
## 如:1062 错误是指一些主键重复,1032 错误是因为主从数据库数据不一致
slave_skip_errors=1062
第八步:修改完配置后重启 slave 实例
[root@shjava101 conf]# docker restart mysql-slave
mysql-slave
现在我们查看我们启动的 Mysql 容器:

第九步:在主数据库中查看主从同步状态
在 master 主机上查看主从同步的状态:
mysql> show master status;
第十步:进入 mysql-slave 容器
进入 mysql-slave 容器,然后登陆数据库:
[root@shjava101 conf]# docker exec -it mysql-slave /bin/bash
root@2fd617d42f90:/# mysql -uroot -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36-log MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
第十一步:在从数据库中配置主从复制
我们在从机上完成主从关系的配置:
具体语法如下:
change master to master_host='宿主机ip', master_user='slave',
master_password='123456', master_port=3307, master_log_file='mall-mysql-
bin.000001', master_log_pos=617, master_connect_retry=30;
我们在从机上执行以上命令:
mysql> change master to master_host='192.168.10.145', master_user='slave',
master_password='123456', master_port=3307, master_log_file='mall-mysql-
bin.000001', master_log_pos=617, master_connect_retry=30;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
重点提示:master_log_pos 参数的值一定要和主机中的 Position 参数的值保持一致!
注意:配置主从复制关系的参数说明
master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取 File 参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取 Position 参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
第十二步:在从数据库中查看主从同步状态
mysql> show slave status \G;

第十三步:在从数据库中开启主从同步
mysql> start slave;
Query OK, 0 rows affected (0.04 sec)
第十四步:查看从数据库状态发现已经同步
在从数据库执行 show slave status \G; 命令

如果出现两个 yes,说明主从复制成功。
第十五步:测试主从复制效果
- 在主机创建数据库,数据表
mysql> create database mysql_db;
Query OK, 1 row affected (0.00 sec)
mysql> use mysql_db;
Database changed
mysql> create table account(id int,name varchar(20),money double);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into account(id,name,money) values(1,'eric',100.0);
Query OK, 1 row affected (0.01 sec)
mysql> select * from account;
+------+------+-------+
| id | name | money |
+------+------+-------+
| 1 | eric | 100 |
+------+------+-------+
1 row in set (0.00 sec)
- 在从数据库查看数据是否同步

我们发现数据同步成功,说明 MySQL 数据库主从复制配置完毕!
1.2 分布式缓存经典面试题
需求:假设有 1 ~ 2 亿条数据需要缓存,请问如何设计这个存储案例。
单机单台 100% 不可能,肯定是分布式存储,用 Redis 如何落地?目前业内解决方案有三种:
1.2.1 哈希取余分区

2 亿条记录就是 2 亿个 k,v,我们单机不行必须要分布式多机,假设有 3 台机器构成一个集群,用户每次读写操作都是根据公式:Hash(key) % N (N 为机器台数),计算出哈希值,用来决定数据映射到哪一个节点上。
优点:
简单粗暴,直接有效,只需要预估好数据规划好节点,例如 3 台、8 台、10 台,就能保证一段时间的数据支撑。使用 Hash 算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡 + 分而治之的作用。
缺点:
原来规划好的节点,进行扩容或者缩容就比较麻烦了,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key) % 3 会变成 Hash(key) % ?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。
某个 Redis 机器宕机了,由于台数数量变化,会导致 Hash 取余全部数据重新洗牌。
1.2.2 一致性哈希算法分区
-
什么是一致性哈希算法 一致性哈希算法在 1997 年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不 OK 了。提出一致性 Hash 解决方案。目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系
-
如何构建一致性哈希算法分区
步骤 1:构建一致性哈希环
一致性哈希算法必然有个 Hash 函数并按照算法产生 Hash 值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个 Hash 空间 $[0,2^{32}-1]$,这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连 ($0 = 2^{32}$),这样让它逻辑上形成了一个环形空间。
它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)的数量进行取模。而一致性 Hash 算法是对 $2^{32}$ 取模,简单来说,一致性 Hash 算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数 Hash 的值空间为 $[0, 2^{32}-1]$(即哈希值是一个 32 位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表 0,0 点右侧的第一个点代表 1,以此类推,2、3、4、…… 直到 $2^{32}-1$,也就是说 0 点左侧的第一个点代表 $2^{32}-1$,0 和 $2^{32}-1$ 在零点中方向重合,我们把这个由 $2^{32}$ 个点组成的圆环称为 Hash 环。

步骤 2:服务器 IP 节点映射
将集群中各个 IP 节点映射到环上的某一个位置。将各个服务器使用 Hash 进行一个哈希,具体可以选择服务器的 IP 或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如 4 个节点 Node A、B、C、D,经过 IP 地址的哈希函数计算 $hash(ip)$,使用 IP 地址哈希后在环空间的位置如下:

步骤 3:key 落到服务器的落键规则
当我们需要存储一个 kv 键值对时,首先计算 key 的 hash 值,hash(key),将这个 key 使用相同的函数 Hash 计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。
如我们有 Object A、Object B、Object C、Object D 四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性 Hash 算法,数据 A 会被定为到 Node A 上,B 被定为到 Node B 上,C 被定为到 Node C 上,D 被定为到 Node D 上。

优点
容错性:
假设 Node C 宕机,可以看到此时对象 A、B、D 不会受到影响,只有 C 对象被重定位到 Node D。一般的,在一致性 Hash 算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是 C 挂了,受到影响的只是 B、C 之间的数据,并且这些数据会转移到 D 进行存储。

扩展性:
数据量增加了,需要增加一台节点 Node X,X 的位置在 A 和 B 之间,那受到影响的也就是 A 到 X 之间的数据,重新把 A 到 X 的数据录入到 X 上即可,不会导致 Hash 取余全部数据重新洗牌。
缺点
Hash 环的数据倾斜问题
一致性 Hash 算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器:

1.2.3 哈希槽分区
- 为什么出现 主要是为了解决一致性哈希算法出现的数据倾斜问题。哈希槽实质就是一个数组,数组 $[0,2^{14} -1]$ 形成 Hash slot 空间。
- 能干什么 解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽 (slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。
- 哈希槽的原理 Redis 集群中内置了 16384 个哈希槽,Redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value 时,Redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key 之 A、B 在 Node 2, key 之 C 落在 Node 3 上。

1.3 3 主 3 从 Redis 集群搭建
1.3.1 使用 Docker 搭建 Redis 集群
- 启动 6 台 Redis 实例
[root@shjava101 ~]# docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
7411fe90823cc6badd1914ea278fc4bc222990b531ee0ecd8b67e85c4ae89869
[root@shjava101 ~]# docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
0abb93bcd630a9a8d474e40760fc4c4f3b43891422100fa32945f133f89a2354
[root@shjava101 ~]# docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
6ba74f263a87e34b94a7d7634fd996528930b4c7a1019a04ceca04359dcc159c
[root@shjava101 ~]# docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
71b9d2fa27fa3f198c0d8941643833b28fee90fa668e1b4f3bed993a9ef15f20
[root@shjava101 ~]# docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
398c66d10574d2a37c5a5028c32c0cb95bb11f85a778f46af62497f0c0921c8d
[root@shjava101 ~]# docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
0b2402941910e3d7efa03dab4b8f793218f6c23d09af78b66267628fbadac3dc
- 启动之后查看容器是否启动
[root@shjava101 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0b2402941910 redis:6.0.8 "docker-entrypoint.s…" 34 seconds ago Up 33 seconds redis-node-6
398c66d10574 redis:6.0.8 "docker-entrypoint.s…" 41 seconds ago Up 40 seconds redis-node-5
71b9d2fa27fa redis:6.0.8 "docker-entrypoint.s…" 48 seconds ago Up 47 seconds redis-node-4
6ba74f263a87 redis:6.0.8 "docker-entrypoint.s…" 54 seconds ago Up 53 seconds redis-node-3
0abb93bcd630 redis:6.0.8 "docker-entrypoint.s…" About a minute ago Up About a minute redis-node-2
7411fe90823c redis:6.0.8 "docker-entrypoint.s…" About a minute ago Up About a minute redis-node-1

- 进入容器 Redis-node-1并为 6 台机器构建集群关系
[root@shjava101 ~]# docker exec -it redis-node-1 /bin/bash # 进入1号容器内部
接下来我们构建主从关系:
root@shjava101:/data# redis-cli --cluster create 192.168.10.145:6381 192.168.10.145:6382 192.168.10.145:6383 192.168.10.145:6384 192.168.10.145:6385 192.168.10.145:6386 --cluster-replicas 1
注意:–cluster-replicas 1 表示为每个 master 创建一个 slave 节点
执行之后如下:

我们输入 yes,表示同意上面的配置:

这样我们的主从关系就构建成功。
- 查看集群状态
我们随便去连接一台 Redis 服务,比如连接 6381
root@shjava101:/data# redis-cli -p 6381
127.0.0.1:6381> cluster info # 查看集群状态

我们也可以使用 Cluster nodes 查看集群节点状态:
127.0.0.1:6381> cluster nodes
1.3.2 在集群状态下存储数据
现在我们在集群的模式下面,存储数据。
127.0.0.1:6381> set k1 v1
(error) MOVED 12706 192.168.10.145:6383
我们发现现在存储数据失败,为什么?因为我们在 6381 机器上进行数据存储,但是落在的哈希槽位于 6383,超过了目前 6381 机器哈希槽的范围。
所以我们在在连接 Redis 的时候要加上 -c 参数。
127.0.0.1:6381> quit
root@shjava101:/data# redis-cli -p 6381 -c
127.0.0.1:6381> set k1 v1
- > Redirected to slot [12706] located at 192.168.10.145:6383
OK
我们还有一个命令也可以查看集群节点的状态:
root@shjava101:/data# redis-cli --cluster check 192.168.10.145:6381

1.3.3 Redis集群容错切换迁移
我们先查看运行的 Redis 容器:

现在我们停掉我们的 6381 机器
[root@shjava101 ~]# docker stop redis-node-1
redis-node-1
再次查看运行的 Redis 容器:

现在我们发现只有 5 台运行的 Redis 了。
接下来我们进入到 Redis 2 号机器的内部容器
[root@shjava101 ~]# docker exec -it redis-node-2 /bin/bash
root@shjava101:/data# redis-cli -p 6382 -c
127.0.0.1:6382> cluster nodes
查看集群节点信息:

我们发现 6386 以前是从机,现在变成了主机,完成了集群故障迁移。
大家思考一个问题,如果 6381 重新启动之后,目前 Redis 集群形成的主从关系会不会发生变化?
我们在另外一个 xshell 窗口先启动 Redis 6381这台机器:
[root@shjava101 ~]# docker start redis-node-1
redis-node-1
接下来我们再去查看集群的节点关系:

我们发现 6381 现在变成了从机,原来的主机状态依然没有发生变化。
1.3.4 Redis 集群扩容
需求:将现在的 3 主 3 从扩容成 4 主 4 从
新建 6387、6388 两个节点 + 新建后启动 + 查看是否 8 节点
[root@shjava101 ~]# docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
c51042dee9203ac07df202daa23a46f33b2d930b5d1e8a8e94c7193e1a243e4e
[root@shjava101 ~]# docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
f5c92d0af154f471160c2664b947a0544c911790beba978a20ca388cca3125f7
查看容器状态:
现在我们看到,8 台 Redis 已经成功启动。
- 进入 6387 容器实例内部
[root@shjava101 ~]# docker exec -it redis-node-7 /bin/bash
root@shjava101:/data#
- 将新增的 6387 节点(空槽号)作为 master 节点加入原集群
[root@shjava101 ~]# redis-cli --cluster add-node 192.168.10.145:6387 192.168.10.145:6381
释义:
6387 就是将要作为 master 新增节点
6381 就是原来集群节点里面的领路人,相当于 6387 找到 6381 这个领路人从而找到组织加入集群
执行之后,结果如下:
- 检查集群情况
root@shjava101:/data# redis-cli --cluster check 192.168.10.145:6381
我们发现 6387 这台机器暂时没有槽位,也没有从机。
- 重新分派槽号
命令:redis-cli –cluster reshard IP地址:端口号
root@shjava101:/data# redis-cli --cluster reshard 192.168.10.145:6381

接下来我们要把哈希槽分配给 6387 这台机器:

接下来输入 all:

我们最后输入 yes,保存以上配置信息。
- 再次检查集群状态
root@shjava101:/data# redis-cli --cluster check 192.168.10.145:6381

我们发现 6387 号机器以经分配了哈希槽。
为什么 6387 是 3 个新的区间,以前的还是连续?
重新分配成本太高,所以前 3 家各自匀出来一部分,从 6381 / 6382 / 6383 三个旧节点分别匀出 1364 个坑位给新节点 6387
- 为主节点 6387 分配从节点 6388
命令:
redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave -- cluster-master-id 新主机节点ID
root@shjava101:/data# redis-cli --cluster add-node 192.168.10.145:6388 192.168.10.145:6387 --cluster-slave --cluster-master-id 94c80c2ef8d004f4462e42dd00b89d237c9dfc4d
- 最后查看集群节点信息
root@shjava101:/data# redis-cli --cluster check 192.168.10.145:6381

1.3.5 Redis 集群缩容
需求:6387 和 6388 下线
- 检查集群情况,获得 6387 6388 的节点 ID
root@shjava101:/data# redis-cli --cluster check 192.168.10.145:6382

- 删除从节点 6388
命令:redis-cli –cluster del-node ip:从机端口 从机6388节点ID
root@shjava101:/data# redis-cli --cluster del-node 192.168.10.145:6388 3314c06b7b773b81bb4df47cb8ed6d44e8847684

再次查看集群节点情况:

我们发现从节点由原来的 4 台变成了现在的 3 台,说明 6388 号从节点删除成功。
- 将 6387 的槽号清空,重新分配
我们将清出来的槽号都给 6382。
root@shjava101:/data# redis-cli --cluster reshard 192.168.10.145:6381

- 再次检查集群节点情况
root@shjava101:/data# redis-cli --cluster check 192.168.10.145:6381

我们发现 6387 的哈希槽全部删除,并分配给 6382 了。
- 将 6387 删除
命令:redis-cli –cluster del-node ip:端口 6387节点ID
root@shjava101:/data# redis-cli --cluster del-node 192.168.10.145:6387 94c80c2ef8d004f4462e42dd00b89d237c9dfc4d
- 最后再次查看节点信息
root@shjava101:/data# redis-cli --cluster check 192.168.10.145:6381

我们发现 Redis 集群节点缩容成功!