故障等级
访问慢 轻微
网站显示异常 一般
网站打不开 严重
数据丢失 炼狱
Redis用3.2以上版本
因为Redis3.2版本以上搭集群才稳定
6.Redis Cluster
哨兵的不足
1.配置复杂
-ansible利用模块和模板
2.中断时间长
-调整参数
3.资源利用率低(只有一台主库提供对外服务)
-
4.针对现在环境,三台哨兵只能挂一个
-调整参数可以允许挂两台
5.依赖于redis数据节点
-
Redis Cluster
1.槽位分配slot
2.16384个槽位
3.每一个槽都得分配到位,有一个槽没分配,整个集群不可用
4.序号顺序不一定要连续,最重要的是每个节点的槽位数量要大致相同,允许2%的误差
Redis Cluster
集群简介
Redis Cluster是redis的分布式解决方案,在3.0版本以上正式推出
当遇到单机,内存,并发,流量等瓶颈时,可以采用cluster架构方案达到负载均衡目的
Redis Cluster之前的分布式方案有两种:
1)客户端分区方案,优点分区逻辑可控,缺点是需要自己处理数据路由,高可用和故障转移等。
2) 代理方案,优点是简化客户端分布式逻辑和升级维护便利,缺点加重架构部署和性能消耗。
数据分布
分布式数据库首先要解决把整个数据库集按照分区规则映射到多个节点的问题,即把数据集划分到
多个节点上,每个节点负责整体数据的一个子集,需要关注的是数据分片规则,Redis Cluster 采用
哈希分片规则。
目录规划
# redis 安装目录
/opt/redis_cluster/redis_{PORT}/{conf,logs,pid}
# redis 数据目录
/data/redis_cluster/redis_{PORT}/redis_{PORT}.rdb
# redis 运维脚本
/root/scripts/redis_shell.sh
集群拓扑
不合理的拓扑
合理的拓扑
手动搭建部署集群
思路:
1)部署一台服务器上的 2 个集群节点
2)发送完成后修改其他主机的 IP 地址
3)使用 ansible 批量部署
实现命令:
db01 操作
mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid}
mkdir –p /data/redis_cluster/redis_{6380,6381}
cat >/opt/redis_cluster/redis_6380/conf/redis_6380.conf<
db02操作
find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#52#g"
mkdir –p /data/redis_cluster/redis_{6380,6381}
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
#######db03操作
find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#53#g"
mkdir –p /data/redis_cluster/redis_{6380,6381}
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
手动配置节点发现
当把所有节点都启动后查看进程会有 cluster 的字样
但是登录后执行 CLUSTER NODES 命令会发现只有每个节点自己的 ID,目前集群内的节点
还没有互相发现,所以搭建 redis 集群我们第一步要做的就是让集群内的节点互相发现.
在执行节点发现命令之前我们先查看一下集群的数据目录会发现有生成集群的配置文件
查看后发现只有自己的节点内容,等节点全部发现后会把所发现的节点 ID 写入这个文件
集群模式的 Redis 除了原有的配置文件之外又加了一份集群配置文件.当集群内节点
信息发生变化,如添加节点,节点下线,故障转移等.节点会自动保存集群状态到配置文件.
需要注意的是,Redis 自动维护集群配置文件,不需要手动修改,防止节点重启时产生错乱.
节点发现使用命令: CLUSTER MEET {IP} {PORT}
提示:在集群内任意一台机器执行此命令就可以
[root@db01 ~]# sh redis_shell.sh login 6380
10.0.0.51:6380> CLUSTER MEET 10.0.0.51 6381
OK
10.0.0.51:6380> CLUSTER MEET 10.0.0.52 6380
OK
10.0.0.51:6380> CLUSTER MEET 10.0.0.53 6380
OK
10.0.0.51:6380> CLUSTER MEET 10.0.0.52 6381
OK
10.0.0.51:6380> CLUSTER MEET 10.0.0.53 6381
OK
10.0.0.51:6380> CLUSTER NODES
d03cb38d612802aead8f727b1726a3359c241818 10.0.0.51:6380 myself,master - 0 0 4 connected
67c8128df00b2fa304a41bafbadac25a654f196d 10.0.0.51:6381 master - 0 1562059947079 1 connected
a23ec7d444791a0b258ac454ef15cb4d6ab5abd2 10.0.0.53:6381 master - 0 1562059948087 5 connected
e57807d4d35daaaca05f4a9705e844eab15c7ce8 10.0.0.52:6381 master - 0 1562059949098 0 connected
aa9da67a594dfb357195f12ca4c44001804ee470 10.0.0.53:6380 master - 0 1562059945063 3 connected
5cb6895305520e6a0aa4198a6ea5f2c087530b41 10.0.0.52:6380 master - 0 1562059950108 2 connected
节点都发现完毕后我们再次查看集群配置文件
可以看到,发现到的节点的 ID 也被写入到了集群的配置文件里
Redis Cluster 通讯流程
在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否
出现故障灯状态信息,redis 集群采用 Gossip(流言)协议,Gossip 协议工作原理就是节点彼此不断
交换信息,一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播。
通信过程
1)集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信,通信端口在基础端口上家 10000.
2)每个节点在固定周期内通过特定规则选择结构节点发送 ping 消息
3)接收到 ping 消息的节点用 pong 消息作为响应。集群中每个节点通过一定规则挑选要通信的节点,每个节点
可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会打成一致的状态,当
节点出现故障,新节点加入,主从角色变化等,它能够给不断的 ping/pong 消息,从而达到同步目的。
通讯消息类型:
Gossip
Gossip 协议职责就是信息交换,信息交换的载体就是节点间彼此发送 Gossip 消息。
常见 Gossip 消息分为:ping、 pong、 meet、 fail 等
meet
meet 消息:用于通知新节点加入,消息发送者通知接受者加入到当前集群,meet 消息通信正常完成后,接收节
点会加入到集群中并进行 ping、 pong 消息交换
ping
ping 消息:集群内交换最频繁的消息,集群内每个节点每秒想多个其他节点发送 ping 消息,用于检测节点是否
在线和交换彼此信息。
pong
Pong 消息:当接收到 ping,meet 消息时,作为相应消息回复给发送方确认消息正常通信,节点也可以向集群内
广播自身的 pong 消息来通知整个集群对自身状态进行更新。
fail
fail 消息:当节点判定集群内另一个节点下线时,回向集群内广播一个 fail 消息,其他节点收到 fail 消息之
后把对应节点更新为下线状态。
Redis Cluster 手动分配槽位
虽然节点之间已经互相发现了,但是此时集群还是不可用的状态,因为并没有给节点分配槽位,而且必
须是所有的槽位都分配完毕后整个集群才是可用的状态.
反之,也就是说只要有一个槽位没有分配,那么整个集群就是不可用的.
测试命令:
[root@db01 ~]# sh redis_shell.sh login 6380
10.0.0.51:6380> set k1 v1
(error) CLUSTERDOWN Hash slot not served
10.0.0.51:6380> CLUSTER INFO
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:4
cluster_stats_messages_sent:1200
cluster_stats_messages_received:1200
10.0.0.51:6380>
前面说了,我们虽然有 6 个节点,但是真正负责数据写入的只有 3 个节点,其他 3 个节点只是作为主节
点的从节点,也就是说,只需要分配期中三个节点的槽位就可以了
分配槽位的方法:
分配槽位需要在每个主节点上来配置,此时有 2 种方法执行:
1.分别登录到每个主节点的客户端来执行命令
2.在其中一台机器上用 redis 客户端远程登录到其他机器的主节点上执行命令
每个节点执行命令:
[root@db01 ~]# redis-cli -h db01 -p 6380 cluster addslots {0..5461}
OK
[root@db01 ~]# redis-cli -h db02 -p 6380 cluster addslots {5462..10922}
OK
[root@db01 ~]# redis-cli -h db03 -p 6380 cluster addslots {10923..16383}
OK
分配完所有槽位之后我们再查看一下集群的节点状态和集群状态
可以看到三个节点都分配了槽位,而且集群的状态是 OK 的
手动配置集群高可用
虽然这时候集群是可用的了,但是整个集群只要有一台机器坏掉了,那么整个集群都是不可用的.
所以这时候需要用到其他三个节点分别作为现在三个主节点的从节点,以应对集群主节点故障时可以
进行自动切换以保证集群持续可用.
注意:
1.不要让复制节点复制本机器的主节点, 因为如果那样的话机器挂了集群还是不可用状态, 所以复制
节点要复制其他服务器的主节点.
2.使用 redis-trid 工具自动分配的时候会出现复制节点和主节点在同一台机器上的情况,需要注意
测试集群
这一次我们采用在一台机器上使用 redis 客户端远程操作集群其他节点
注意:
1.需要执行命令的是每个服务器的从节点
2.注意主从的 ID 不要搞混了.
执行命令:
[root@db01 ~]# redis-cli -h db01 -p 6381 CLUSTER REPLICATE 5cb6895305520e6a0aa4198a6ea5f2c087530b41
OK
[root@db01 ~]# redis-cli -h db02 -p 6381 CLUSTER REPLICATE aa9da67a594dfb357195f12ca4c44001804ee470
OK
[root@db01 ~]# redis-cli -h db03 -p 6381 CLUSTER REPLICATE d03cb38d612802aead8f727b1726a3359c241818
OK
Redis Cluster测试集群
我们使用常规插入 redis 数据的方式往集群里写入数据看看会发生什么
[root@db01 ~]# redis-cli -h db01 -p 6380 set k1 v1
(error) MOVED 12706 10.0.0.53:6380
结果提示 error, 但是给出了集群另一个节点的地址
那么这条数据到底有没有写入呢? 我们登录这两个节点分别查看
[root@db01 ~]# redis-cli -h db03 -p 6380 get k1
(nil)
结果没有,这是因为使用集群后由于数据被分片了,所以并不是说在那台机器上写入数据就会在哪台机
器的节点上写入,集群的数据写入和读取就涉及到了另外一个概念,ASK 路由
ASK路由介绍
在集群模式下,Redis 接受任何键相关命令时首先会计算键对应的槽,再根据槽找出所对应的节点
如果节点是自身,则处理键命令;
否则回复 MOVED 重定向错误,通知客户端请求正确的节点,这个过程称为 Mover 重定向
[root@db01 ~]# redis-cli -c -h db01 -p 6380
db01:6380> get k_1
"v_1"
db01:6380> get k_100
-> Redirected to slot [5541] located at 10.0.0.52:6380
"v_100"
10.0.0.52:6380> get k_1000
-> Redirected to slot [79] located at 10.0.0.51:6380
"v_1000"
10.0.0.51:6380>
模拟故障转移
至此,我们已经手动的把一个 redis 高可用的集群部署完毕了, 但是还没有模拟过故障
这里我们就模拟故障,停掉期中一台主机的 redis 节点,然后查看一下集群的变化
我们使用暴力的 kill -9 杀掉 db02 上的 redis 集群节点,然后观察节点状态
理想情况应该是 db01 上的 6381 从节点升级为主节点
在 db01 上查看集群节点状态
虽然我们已经测试了故障切换的功能,但是节点修复后还是需要重新上线
所以这里测试节点重新上线后的操作
重新启动 db02 的 6380,然后观察日志
观察db01上的日志
这时假如我们想让修复后的节点重新上线,可以在想变成主库的从库执行 CLUSTER FAILOVER 命令
这里我们在 db02 的 6380 上执行
使用工具搭建部署 Redis Cluster
redis-trib.rb 是采用 Ruby 实现的 redis 集群管理工具,内部通过 Cluster 相关命令帮我们简化集群
创建、检查、槽迁移和均衡等常见运维操作,使用前要安装 ruby 依赖环境
yum makecache fast
yum install rubygems
gem sources --remove https://rubygems.org/
gem sources -a http://mirrors.aliyun.com/rubygems/
gem update –system
gem install redis -v 3.3.5
我们可以停掉所有的节点,然后清空数据,恢复成一个全新的集群,所有机器执行命令
pkill redis
rm -rf /data/redis_cluster/redis_6380/*
rm -rf /data/redis_cluster/redis_6381/*
全部清空之后启动所有的节点,所有机器执行
sh redis_shell.sh start 6380
sh redis_shell.sh start 6381
db01执行创建集群命令
cd /opt/redis_cluster/redis/src/
./redis-trib.rb create --replicas 1 10.0.0.51:6380 10.0.0.52:6380 10.0.0.53:6380 10.0.0.51:638110.0.0.52:6381 10.0.0.53:6381
检查集群完整性
./redis-trib.rb check 10.0.0.51:6380
./redis-trib.rb rebalance 10.0.0.51:6380
检查槽位是否分配合理误差2%以内