配置一个`Redis Cluster`至少需要`3`个`master`节点,所以为了高可用,每个`master`节点又至少需要配置一个`slave`节点,即:最低配版的高可用`Redis Cluster`服务是需要`3`主`3`从。
#### 为什么至少需要 3 个 maser 节点
为什么至少需要`3`个`master`节点的原因是:如果一个`master`挂了,至少`3`个节点才能执行后面的故障转移等操作。`1`个`master`就不用说了,挂了就没了;如果是`2`个`master`节点就可能出现这种情况`A`发现`B`挂了,但是`A`自己只有`1`票,也就是认为`B`挂了的主节点刚好等于所有主节点的一半,没大于一半,所以它就没办法断定节点`B`就是挂了。
#### 手把手搭建一个 3 主 3 从 Redis Cluster 集群
**注意:打开上个实验已保存的环境。**
接下来,请大家耐心跟着我一起操作,自己动手搭建一个`Redis Cluster`集群:
1. 为了避免干扰,如果大家前面的集群配置和`Sentinel`服务还是启动的话先全部关掉,根据`ps -ef | grep redis`获取到的进程`id`再执行`kill -9`命令停止全部`Redis`和`Sentinel`服务。
2. `3`主`3`从的集群至少需要启动`6`个`Redis`,执行以下命令复制`4`个`Redis`:
~~~bash
cp -rf /home/project/redis-6370 /home/project/redis-6372
cp -rf /home/project/redis-6370 /home/project/redis-6373
cp -rf /home/project/redis-6370 /home/project/redis-6374
cp -rf /home/project/redis-6370 /home/project/redis-6375
~~~
3. 执行`ls -lrt`确认是否`6`个`Redis`服务已经全部复制成功:

4. 然后依次执行以下`6`个命令,编辑每个`Redis`的`redis.conf`文件修改一些必要的配置:
~~~bash
vim /home/project/redis-6370/redis.conf
vim /home/project/redis-6371/redis.conf
vim /home/project/redis-6372/redis.conf
vim /home/project/redis-6373/redis.conf
vim /home/project/redis-6374/redis.conf
vim /home/project/redis-6375/redis.conf
~~~
5. 主要修改的配置如下(需要注意的是,如果之前搭建过`master-salve`集群,所以配置文件`redis.conf`中会出现`replicaof 127.0.0.1 6379`之类的信息,这个需要删掉,因为开启集群模式后不支持这个配置):
~~~java
/**统一配置修改**/
daemonize yes //是否后台运行
protected-mode no //网络是否允许对外访问 no 表示允许
cluster-enabled yes //是否开启集群模式(默认是注释掉的,打开注释就可以了)
cluster-node-timeout 5000 //集群超时时间
/** 下面这些配置需要按照目录来修改,如果目录是 6371,则下面所有的数字都要修改为 6371,其它目录也一样 **/
port 6370 //端口号,根据不同目录修改为不同的数字
dir /home/project/redis-6370/ //redis 工作主目录,根据不同目录修改为不同的数字
logfile "/home/project/redis-6370/redis.log" //日志文件
cluster-config-file /home/project/redis-6370/nodes-6370.conf //node 文件,根据不同目录修改为不同的数字
pidfile /var/run/redis_6370.pid //pid 文件,根据不同目录修改为不同的数字
~~~
6. 上面的配置尤其是下半部分,一定要修改完整,而且要根据不同的目录对应好关系,如果对应错了不同的目录下`Redis`服务就会串位了。完成好所有配置之后,依次启动`6`个`Redis`服务。
~~~bash
/home/project/redis-6370/bin/redis-server /home/project/redis-6370/redis.conf #启动 6370 端口Redis
/home/project/redis-6371/bin/redis-server /home/project/redis-6371/redis.conf #启动 6371 端口Redis
/home/project/redis-6372/bin/redis-server /home/project/redis-6372/redis.conf #启动 6372 端口Redis
/home/project/redis-6373/bin/redis-server /home/project/redis-6373/redis.conf #启动 6373 端口Redis
/home/project/redis-6374/bin/redis-server /home/project/redis-6374/redis.conf #启动 6374 端口Redis
/home/project/redis-6375/bin/redis-server /home/project/redis-6375/redis.conf #启动 6375 端口Redis
~~~
7. 启动之后执行`ps -ef | grep redis`命令查看确认是否成功启动了`6`个服务,如果正常启动后,服务后面会有一个`cluster`标记,表示当前`Redis`开启了集群:

8. 连接上任意一个节点,执行如下命令:
~~~bash
# 连接上任意节点
/home/project/redis-6370/bin/redis-cli -p 6370
# 查看节点状态
cluster info
# 退出当前客户端
exit
~~~
会发现当前集群的状态是下线状态(fail):

9. 再执行下面的命令创建一个集群(如果大家以后在项目中搭建集群的话,不建议使用`127.0.0.1`,而是建议使用真实的`ip`):
~~~bash
/home/project/redis-6370/bin/redis-cli --cluster create 127.0.0.1:6370 127.0.0.1:6371 127.0.0.1:6372 127.0.0.1:6373 127.0.0.1:6374 127.0.0.1:6375 --cluster-replicas 1
~~~
执行之后会有如下提示,也就是系统自动帮我们分配好了槽而且将主从确定了,我这里的提示是将`6370`,`6371`和`6372`三个服务作为了`master`节点,其余`3`个分别为对应的`slave`节点:

10. 输入`yes`同意系统的分配方案,然后等待配置成功:

11. 配置成功之后再执行命令:
~~~bash
# 连接上 6370 服务
/home/project/redis-6370/bin/redis-cli -p 6370
# 查看集群信息
cluster info
~~~
这时候就看到集群状态已经是`ok`了,说明集群搭建成功:
~~~
!\[13\-13\](https://doc.shiyanlou.com/courses/3368/1490584/731f34b0b5df16116548c0bc39bb9889-0)
~~~
#### 搭建集群常见错误
搭建集群过程中可能会出现以下错误:
1. `[ERR] Node 47.107.155.197:6370 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.`
这个错误有`2`个原因:一个就是`Redis`当中有数据,这个执行`flushall`命令或者把`rdb`和`aof`两个持久化文件删除掉(如果有的话),再重启即可;另一个原因就是可能初始化集群失败过`1`次,那么这时候需要把当时配置好的`nodes.conf`文件删掉,并重启`Redis`服务就可以解决。
2. 初始化集群输入`yes`之后提示`Waiting for the cluster to join`,但是却迟迟等不到成功。
这个原因可能是防火墙引起的,除了正常的数据连接端口,如`6370-6375`,还有另一个端口需要用数据端口固定加上`10000`得到`16370-16375`。也就是说需要确保以下`12`个端口都是通的:
~~~txt
6370 16370 6371 16371 6372 16372 6373 16373 6374 16374 6375 16375
~~~
这个`10000`的偏移量是固定的,`Redis`服务的端口加上`10000`偏移量后得到的端口是集群内部用来执行故障检测、配置更新、故障转移授权等操作的,客户端不能连接这个端口。
3. `[ERR] Not all 16384 slots are covered by nodes.`
这个原因说明分配槽的时候失败了,所以需要检查下配置是否正确。尤其是`cluster-config-file`这个`node`文件的配置是否正确,确认之后不管有没有配置错误,都把所有服务的`node`文件删除掉,并重启所有`Redis`服务,然后再次进行集群搭建。
- Redis 为什么这么快
- 什么是 Redis
- Redis 的安装
- Redis 到底有多快
- Redis 是单线程还是多线程
- Redis 为什么选择使用单线程来执行请求
- 什么是 IO 多路复用机制
- Redis 中 I/O 多路复用的应用
- 一个简单的字符串,为什么 Redis 要设计的如此特别
- Redis 的 9 种数据类型
- 二进制安全字符串
- sds 空间分配策略
- sds 和 C 语言字符串区别
- sds 是如何被存储的
- type 属性
- encoding 属性
- 通过牺牲速度来节省内存,Redis 是觉得自己太快了吗
- 什么是压缩列表
- ziplist 的存储结构
- entry 存储结构
- ziplist 数据示例
- ziplist 连锁更新问题
- 为了加快速度,Redis 都做了哪些“变态”设计
- 列表对象
- linkedlist
- linkedlist 和 ziplist 的选择
- quicklist
- 列表对象常用操作命令
- Redis 中哈希分布不均匀该怎么办
- 哈希对象
- hashtable
- ziplist
- ziplist 和 hashtable 的编码转换
- 哈希对象常用命令
- 同一份数据,Redis 为什么要存”两次”
- 五种基本类型之集合对象
- intset 编码
- 集合对象常用命令
- 五种基本类型之有序集合对象
- skiplist 编码
- ziplist 编码
- ziplist 和 skiplist 编码转换
- 有序集合对象常用命令
- 要想用活 Redis,Lua 脚本是绕不过去的坎
- 发布与订阅
- 基于频道的实现
- 基于模式的实现
- Lua 脚本
- Lua 脚本的调用
- Lua 脚本中执行 Redis 命令
- Lua 脚本摘要
- Lua 脚本文件
- 脚本异常
- 作为一款内存数据库,为什么断电后 Redis 数据不会丢失
- Redis 持久化机制
- RDB 持久化机制
- AOF 持久化机制
- 内存耗尽后 Redis 会发生什么
- 内存回收
- 过期策略
- 8 种淘汰策略
- LRU 算法
- LFU 算法
- 不能回滚的 Redis 事务还能用吗
- Redis 有事务吗
- Redis 事务实现原理
- Redis 事务 ACID 特性
- watch 命令
- watch 命令的作用
- watch 原理分析
- Redis 为什么不直接用 master-slave 集群
- Redis 集群方案
- 主从复制
- 配置一主两从 master-slave 集群
- 主从复制原理分析
- 主从服务的不足之处
- Sentinel(哨兵)机制为什么从神坛滑落
- 哨兵 Sentinel 机制
- Sentinel 原理分析
- 配置 Sentinel 集群
- Sentinel 机制实战
- Sentinel 机制的不足之处
- Redis Cluster 集群凭什么成为了最终的胜利者
- Redis 分布式集群方案
- 客户端实现分片
- 中间代理服务实现分片
- Redis Cluster 方案
- 手动配置一个 Redis Cluster 集群
- Redis Cluster 集群常用命令
- 客户端如何使用 Redis Cluster 集群
- Redis Cluster 的不足
- 如何从 10 亿数据中快速判断是否存在某一个元素
- 缓存雪崩
- 缓存击穿
- 缓存穿透
- 布隆过滤器(Bloom Filter)
- 布隆过滤器的 2 大特点
- 布隆过滤器的实现(Guava)
- 布隆过滤器的如何删除