本文使用Docker部署实现于同一台服务器,Redis 版本 5.0.3
单机存在的问题
- 机器故障:导致Redis失效
- 容量瓶颈:容量不能水平扩展
- OPS( operation per second 每秒处理指令数):一台机器的网络带宽是有限的,如果有多台机器,可以有效解决QOS
Redis Cluster
Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施installation。
Redis 集群通过分区partition来提供一定程度的可用性availability: 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
Redis集群提供了以下好处:
- 将数据自动切分 split 到多个节点的能力
- 当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力
Redis 集群特点:
- 一个master可以有多个slave
- 一个slave只能有一个master
- 数据流向是单向的,master到slave
Redis 集群分区
参考:
浅谈Redis Cluster
Redis 集群方案
哨兵模式:
在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,
如果master节点异常,则会做主从切换,将某一台slave作为master
,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。
高可用集群模式(推荐):
redis集群是一个
由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性
。Redis集群不需要sentinel哨兵也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平扩展,据官方文档称可以线性扩展到上万个节点(官方推荐不超过1000个节点)。redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单。
Redis 高可用集群快速搭建
redis 集群需要
至少三个节点
(因为领导者选举需要至少一半加1个节点,奇数个节点可以在满足该条件的基础上节省一个节点),这里我们搭建三个主节点,每个主节点下面在提供一个从节点,共6个 redis 节点(三主三从)。
tip:这里我们使用 docker 搭建在同一台服务器上,实际使用时肯定是不同的服务器,不然没有意义(
Redis 版本 5.0.3
)。
单机搭建测试
(为了测试是否可以使用Docker 来 搭建 Redis,可以跳过)
由 docker 仓库中拉取相应的 Redis 镜像
docker pull redis:5.0.3
创建文件夹
/usr/local/redis/conf
/usr/local/redis/data
conf 存放配置文件目录,data 存放映射数据目录
修改 redis 配置文件,设置密码(获取的linux下安装后的配置文件)。
requirepass 123456
编写 docker-compose-redis.yaml [数据映射、配置文件映射] 启动镜像:
version: "3.4"
services:
redis:
image: redis:5.0.3
container_name: redis5-m1
command: redis-server /etc/redis/redis.conf
ports:
- "6379:6379"
volumes:
- ./data:/data
- ./conf/redis.conf:/etc/redis/redis.conf
docker-compose 命令启动
docker-compose -f docker-compose-redis.yaml up -d
启动后,测试是否可以正常访问。
集群搭建
-
创建对应的文件夹
在 /usr/local/redis-cluster 下创建6个文件夹 6388 6389 6378 6379 6368 6369,每个文件夹下都创建 conf、data 目录。 - 编辑配置文件
端口、密码、集群密码、节点信息文件配置(按需修改)
(1)绑定端口,port 63xx (对应文件夹名称)
(2)绑定IP,bind 192.168.2.128 or 0.0.0.0
(3)指定数据存放路径,dir /usr/local/redis-cluster/7031
(4)启动集群模式,cluster-enabled yes
(5)指定集群节点配置文件,cluster-config-file nodes-7031.conf
(6)后台启动,daemonize yes
(7)指定集群节点超时时间,cluster-node-timeout 5000
(8)指定持久化方式,appendonly yes # 这是AOF 持久化,按需要选择是否开启
前5项建议修改,63xx 最好指定为文件夹名称,将63xx的redis.conf改完后再拷贝到剩下的5个目录中,然后只要全局替换redis.conf中的 port 为相应的节点即可。
注意,
如果是docker运行不要设置后台运行( daemonize )
,否则运行后直接退出,因为没有前台线程。且无需指定数据存放路径,通过文件映射出来即可。
-
启动这6个容器
使用 docker-compose 一键启动:
x-xxx 指定了全局变量,后面对应的 xxx 引用
需要设置:network_mode: host (参考后面解释)
version: "3.4"
x-image:
&default-image
redis:5.0.3
x-restart:
&default-restart
always
x-command:
&default-command
redis-server /etc/redis/redis.conf
x-netmode:
&default-netmode
host
services:
redis1:
image: *default-image
restart: *default-restart
container_name: redis5-m1
command: *default-command
volumes:
- ./6368/data:/data
- ./6368/conf/redis.conf:/etc/redis/redis.conf
network_mode: *default-netmode
redis2:
image: *default-image
restart: *default-restart
container_name: redis5-m2
command: *default-command
volumes:
- ./6378/data:/data
- ./6378/conf/redis.conf:/etc/redis/redis.conf
network_mode: *default-netmode
redis3:
image: *default-image
restart: *default-restart
container_name: redis5-m3
command: *default-command
volumes:
- ./6388/data:/data
- ./6388/conf/redis.conf:/etc/redis/redis.conf
network_mode: *default-netmode
redis4:
image: *default-image
restart: *default-restart
container_name: redis5-s1
command: *default-command
volumes:
- ./6369/data:/data
- ./6369/conf/redis.conf:/etc/redis/redis.conf
network_mode: *default-netmode
redis5:
image: *default-image
restart: *default-restart
container_name: redis5-s2
command: *default-command
volumes:
- ./6379/data:/data
- ./6379/conf/redis.conf:/etc/redis/redis.conf
network_mode: *default-netmode
redis6:
image: *default-image
restart: *default-restart
container_name: redis5-s3
command: *default-command
volumes:
- ./6389/data:/data
- ./6389/conf/redis.conf:/etc/redis/redis.conf
network_mode: *default-netmode
启动命令:
docker-compose -f docker-compose-redis.yaml up -d
查看启动的服务:
4. 用redis-cli创建整个redis集群
(redis5以前的版本集群是依靠ruby脚本redis-trib.rb实现)
可以下载一个redis-cli镜像: goodsmileduck/redis-cli:v5.0.3
docker run --rm -it goodsmileduck/redis-cli:v5.0.3 redis-cli -a 123456 --cluster-replicas 1 --cluster create 192.168.6.181:6369 192.168.6.181:6379 192.168.6.181:6389 192.168.6.181:6368 192.168.6.181:6378 192.168.6.181:6388
# -a 表示连接密码
# --cluster-replicas 1 表示 一主一从
# --cluster create 后面表示需要集群的redis主机和端口
出现的问题1:
一直显示等待加入 (
Waiting for the cluster to join…
)
猜测原因:
redis集群不仅需要开通redis客户端连接的端口,而且
需要开通集群总线端口
,集群总线端口为redis客户端连接的端口 + 10000。如redis端口为7001,则集群总线端口为17001。
解决方法:
端口映射 6378:6379, 16378:16379
结果:
无效
实际原因:
当前Cluster尚不支持NATted环境
,在一般环境中IP地址或者port会重新映射(remapped)。Docker使用了一种称为“port mapping”技术:在Docker容器内运行的程序使用的端口,将以另一个端口的方式暴露出去(Docket的宿主环境)。这可以允许一个Server(物理环境)上允许多个Docker容器,而且每个容器内的程序可以使用相同的端口。为了让Redis Cluster与Docker机制兼容,Docker需要使用“host networking mode”,具体信息请参考
Dorcker文档
。
真正解决:
网络模式改成host
,docker run 的方式加上–net host,docker-compose方式加上network_mode: host。
出现的问题2:
提示节点不为空
Node 192.168.6.181:6369 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0
原因:
该节点下面存在数据,新增的集群下面不能存有数据
解决方法:
1).将需要新增的节点下 aof、rdb 等本地备份文件删除;
2).同时将新Node的集群配置文件删除,即:删除 redis.conf 里面 cluster-config-file 所在的文件;
3).再次添加新节点如果还是报错,则登录新Node,对数据库进行清除
# 登录 redis-cli
./redis-cli–h x –p
# 清空当前数据库
172.168.63.201:7001> flushdb
- 连接任意一个客户端,设置数据
# 连接 181:6368 客户端
docker run --rm -it goodsmileduck/redis-cli:v5.0.3 redis-cli -c -h 192.168.6.181 -p 6368 -a 123456
注意原本是 6368,然后变成了 6369 (解释见后文)
RedisDesktopManager 查看:
cluster info 查看集群信息:
cluster nodes 查看节点信息(0-5460,5461-10922,10923-16383 表示各哈希槽区间):
6. 高可用测试
我们关闭一个主节点容器,重新调用查询命令,提示一个失去连接,且其对应的从节点被投票选举为新的主节点,之前的主节点被更换为从节点(发现主从地址未改变,因为当客户端试图连接失效的主服务器时, 集群会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器)
重新启动该节点,再次调用查询命令,发现其已成功连接到了集群中,恢复原样
至此,Redis 集群搭建完毕。
Redis 集群原理
redis cluster采用无中心结构,节点间使用gossip协议进行通信。每个节点保存数据和所有节点和槽的映射关系。其架构图如下:
- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
- 节点的fail是通过集群中超过半数的节点检测失效时才生效。
- 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
- redis-cluster把所有的物理节点映射到 [0-16383] slot上,cluster 负责维护node<->slot<->value
Moved 异常
从上图可以看出,客户端是采用直连的方式来连接redis客户端。那么redis客户端是如何知道要提交到节点呢?
实际上,客户端可以将数据提交到任意一个redis cluster节点上,如果存储该数据的槽不在这个节点上,则返回给客户端moved异常,客户端通过moved异常,永久的将请求转移到目标节点,如下图所示。
首先来看下redis cluster的节点信息,执行命令redis-cli cluster nodes:
看到各虚拟槽分配范围 [0-5460]、[5461-10922]、[10923-16383],接下来演示该异常:
首先 cluster keyslot a,查看以 a 为key 的槽位在 15495上,即 6389 上,然后我们此时在 6368上设置 key – value,发现被重定向到了 6389 上。
参考:
如何用docker部署redis cluster:
https://www.cnblogs.com/chenchuxin/p/8404699.html
Redis cluster集群:原理及搭建:
https://blog.csdn.net/truelove12358/article/details/79612954
Redis3集群的安装、配置、高可用:
https://blog.csdn.net/qq_27384769/article/details/80662597
浅谈Redis Cluster:
https://blog.csdn.net/qq2430/article/details/80716313
redis主从复制原理和介绍:
https://blog.csdn.net/fst438060684/article/details/80958375
Redis集群 – 配置最简单的Redis主从读写分离:
https://blog.csdn.net/seven_2016/article/details/81952246
Redis 5 之后版本的高可用集群搭建:
https://blog.csdn.net/qq_34002221/article/details/85011041