告知:
一、手动搭建部署群集(手动搭建集群便于理解集群创建的流程和细节,不过手动搭建集群需要很多步骤)
二、使用工具自动搭建部署Redis Cluster(方便快速搭建集群)
Redis Cluster 是 redis的分布式解决方案,在3.0版本正式推出当遇到单机、内存、并发、流量等瓶颈时,可以采用Cluster架构方案达到负载均衡目的。
Redis Cluster之前的分布式方案有两种:
1)客户端分区方案:优点分区逻辑可控,缺点是需要自己处理数据路由,高可用和故障转移等。
2)代理方案:优点是简化客户端分布式逻辑和升级维护便利,缺点加重架构部署和性能消耗。
官方提供的 Redis Cluster集群方案,很好的解决了集群方面的问题
分布式数据库首先要解决把整个数据库集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整体数据的一个子集,需要关注的是数据分片规则,Redis Cluster采用哈希分片规则。
redis-1(主) | 192.168.1.128 |
---|---|
redis-2(从) | 192.168.1.129 |
redis-3(从) | 192.168.1.134 |
目录规划
redis安装目录
/opt/redis_cluster/redis_{PORT}/{conf,logs,pid}
redis数据目录
/data/redis_cluster/redis_{PORT}/redis_{PORT}.rdb
redis运维脚本
/root/scripts/redis_shell.sh
先部署一台服务器上的2个集群节点,把文件发送到其他主机修改IP地址,启动服务
预先创建规划好的目录
redis-1 ~]# mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid} #创建安装目录
redis-1 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381} #创建数据目录
先安装redis
redis-1 ~]# mkdir /data/soft #准备安装和数据目录
redis-1 ~]# cd /data/soft
redis-1 soft]# wget http://download.redis.io/releases/redis-5.0.7.tar.gz #下载redis安装包
redis-1 soft]# tar zxf redis-5.0.7.tar.gz -C /opt/redis_cluster/ #解压redis到/opt/redis_cluster/
redis-1 soft]# ln -s /opt/redis_cluster/redis-5.0.7/ /opt/redis_cluster/redis
redis-1 soft]# cd /opt/redis_cluster/redis
redis-1 redis]# make && make install #编译安装redis
编写配置文件
redis-1 ~]# vim /opt/redis_cluster/redis_6380/conf/redis_6380.conf #编写配置文件
bind 192.168.1.128
port 6380
daemonize yes
pidfile "/opt/redis_cluster/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_cluster/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_cluster/redis_6380/"
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
redis-1 ~]# cd /opt/redis_cluster/
redis-1 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
redis-1 redis_cluster]# sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.conf
redis-1 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-1 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
复制redis1的安装和数据目录到redis2、redis3
redis-1 ~]# ssh-keygen -t rsa
redis-1 ~]# ssh-copy-id [email protected]
redis-1 ~]# ssh-copy-id [email protected]
redis-1 ~]# scp -rp /opt/redis_cluster/ [email protected]:/opt
redis-1 ~]# scp -rp /opt/redis_cluster/ [email protected]:/opt
redis-2 ~]# cd /opt/redis_cluster/redis
redis-2 redis]# make install
redis-2 ~]# find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "s#128#129#g"
redis-2 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381}
redis-2 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-2 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
redis-3 ~]# cd /opt/redis_cluster/redis
redis-3 redis]# make install
redis-3 ~]# find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "s#128#134#g"
redis-3 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381}
redis-3 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-3 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
当把所有节点都启动后查看进程会有cluster的字样
redis-1 ~]# ps aux | grep redis
root 7003 0.0 0.7 153836 7716 ? Ssl 19:04 0:00 redis-server 192.168.1.128:6380 [cluster]
root 7005 0.0 0.7 153836 7716 ? Ssl 19:04 0:00 redis-server 192.168.1.128:6381 [cluster]
root 7131 0.0 0.0 112664 972 pts/0 R+ 19:07 0:00 grep --color=auto redis
但是登录后执行CLUSTER NODES命令会发现只有每个节点自己的ID,目前集群内的节点还没有互相发现,所以搭建redis集群我们第一步要做的就是让集群内的节点互相发现
登录redis(redis登录和脚本登录(脚本登录需提前编写运维脚本)):
redis-cli -c -h 192.168.1.128 -p 6380 #redis登录
sh /root/scripts/redis_shell.sh login 6380 #脚本登录(需提前编写运维脚本)
编写运维脚本
redis-1 ~]# vim redis_shell.sh
#!/bin/bash
USAG(){
echo "sh $0 {start|stop|restart|login|ps|tail} PORT"
}
if [ "$#" = 1 ]
then
REDIS_PORT='6379'
elif
[ "$#" = 2 -a -z "$(echo "$2"|sed 's#[0-9]##g')" ]
then
REDIS_PORT="$2"
else
USAG
exit 0
fi
REDIS_IP=$(hostname -I|awk '{print $1}')
PATH_DIR=/opt/redis_cluster/redis_${REDIS_PORT}/
PATH_CONF=/opt/redis_cluster/redis_${REDIS_PORT}/conf/redis_${REDIS_PORT}.conf
PATH_LOG=/opt/redis_cluster/redis_${REDIS_PORT}/logs/redis_${REDIS_PORT}.log
CMD_START(){
redis-server ${PATH_CONF}
}
CMD_SHUTDOWN(){
redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT} shutdown
}
CMD_LOGIN(){
redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT}
}
CMD_PS(){
ps -ef|grep redis
}
CMD_TAIL(){
tail -f ${PATH_LOG}
}
case $1 in
start)
CMD_START
CMD_PS
;;
stop)
CMD_SHUTDOWN
CMD_PS
;;
restart)
CMD_START
CMD_SHUTDOWN
CMD_PS
;;
login)
CMD_LOGIN
;;
ps)
CMD_PS
;;
tail)
CMD_TAIL
;;
*)
USAG
esac
redis-1 ~]# chmod +x redis_shell.sh
192.168.1.128:6380> CLUSTER NODES
3f2038bea39b121230d015a7f6db438f5e4bbfcf :6380@16380 myself,master - 0 0 0 connected
在执行节点发现命令之前我们先查看一下集群的数据目录会发现有生成集群的配置文件,查看后发现只有自己的节点内容,等节点全部发现后会把所发现的节点ID写入这个文件
集群模式的Redis除了原有的配置文件之外又加了一份集群配置文件当集群内节点,信息发生变化,如添加节点、节点下线、故障转移等,节点会自动保存集群状态到配置文件。需要注意的是,Redis自动维护集群配置文件,不需要手动修改,防止节点重启时产生错乱。
节点发现使用命令: CLUSTER MEET {IP} {PORT}
提示:在集群内任意一台机器执行此命令就可以
redis-1 ~]# sh redis_shell.sh login 6380
192.168.1.128:6380> CLUSTER MEET 192.168.1.128 6381
OK
192.168.1.128:6380> CLUSTER MEET 192.168.1.129 6380
OK
192.168.1.128:6380> CLUSTER MEET 192.168.1.129 6381
OK
192.168.1.128:6380> CLUSTER MEET 192.168.1.134 6380
OK
192.168.1.128:6380> CLUSTER MEET 192.168.1.134 6381
OK
节点都发现完毕后我们再次查看集群配置文件,可以看到,发现到的节点的ID被写入到了集群的配置文件里
192.168.1.128:6380> CLUSTER NODES
dbf036326ee6236101dd0192709e30fb9bd4d204 192.168.1.129:6381@16381 master - 0 1596025555733 0 connected
79837fd103d7336ca9110330b62a05ba1aef7446 192.168.1.134:6381@16381 master - 0 1596025555000 5 connected
4df4831d147a1f2fe84f892a1c912ae53d5885df 192.168.1.134:6380@16380 master - 0 1596025553718 4 connected
3f2038bea39b121230d015a7f6db438f5e4bbfcf 192.168.1.128:6380@16380 myself,master - 0 1596025556000 2 connected
1b73f239763a259484d7d14a0a8bd48e851e761a 192.168.1.128:6381@16381 master - 0 1596025556739 1 connected
2a076272c3b2dbb473a274ca5d13b3090859f9b2 192.168.1.129:6380@16380 master - 0 1596025554000 3 connected
在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否出现故障灯状态信息,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-1 ~]# sh redis_shell.sh login 6380
192.168.1.128:6380> set k1 v1
(error) CLUSTERDOWN Hash slot not served
192.168.1.128: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:2
cluster_stats_messages_ping_sent:137
cluster_stats_messages_pong_sent:145
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:287
cluster_stats_messages_ping_received:145
cluster_stats_messages_pong_received:142
cluster_stats_messages_received:287
前面说了,我们虽然有6个节点,但是真正负责数据写入的只有3个节点,其他3个节点只是作为主节点的从节点,也就是说,只需要分配期中三个节点的槽位就可以了
分配槽位需要在每个主节点上来配置,有2种分配槽位的方法:
1)分别登录到每个主节点的客户端来执行命令
2)在其中一台机器上用redis客户端远程登录到其他机器的主节点上执行命令
每个节点执行命令:
redis-1 ~]# redis-cli -h 192.168.1.128 -p 6380 cluster addslots {0..5461}
OK
redis-1 ~]# redis-cli -h 192.168.1.129 -p 6380 cluster addslots {5462..10922}
OK
redis-1 ~]# redis-cli -h 192.168.1.134 -p 6380 cluster addslots {10923..16383}
OK
分配完所有槽位之后我们再查看一下集群的节点状态和集群状态,可以看到三个节点都分配了槽位,而且集群的状态是OK的
redis-1 ~]# redis-cli -h 192.168.1.134 -p 6380 cluster nodes
4df4831d147a1f2fe84f892a1c912ae53d5885df 192.168.1.134:6380@16380 myself,master - 0 1595996991000 4 connected 10923-16383
79837fd103d7336ca9110330b62a05ba1aef7446 192.168.1.134:6381@16381 master - 0 1595996998701 5 connected
1b73f239763a259484d7d14a0a8bd48e851e761a 192.168.1.128:6381@16381 master - 0 1595996997692 1 connected
3f2038bea39b121230d015a7f6db438f5e4bbfcf 192.168.1.128:6380@16380 master - 0 1595997000715 2 connected 0-5461
2a076272c3b2dbb473a274ca5d13b3090859f9b2 192.168.1.129:6380@16380 master - 0 1595996997000 3 connected 5462-10922
dbf036326ee6236101dd0192709e30fb9bd4d204 192.168.1.129:6381@16381 master - 0 1595996999708 0 connected
redis-1 ~]# redis-cli -h 192.168.1.128 -p 6380 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:2272
cluster_stats_messages_pong_sent:2557
cluster_stats_messages_sent:4829
cluster_stats_messages_ping_received:2552
cluster_stats_messages_pong_received:2272
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:4829
虽然这时候集群是可用的了,但是整个集群只要有一台机器坏掉了,那么整个集群都是不可用的,所以这时候需要用到其他三个节点分别作为现在三个主节点的从节点,以应对集群主节点故障时可以进行自动切换以保证集群持续可用。
注意:
1)不要让从节点复制本机器的主节点,,因为如果那样的话机器挂了集群还是不可用状态,所以复制节点要复制其他服务器的主节点.
2)使用redis-trid工具自动分配的时候会出现复制节点和主节点在同一台机器上的情况,需要注意
这里采用在一台机器上使用redis客户端远程操作集群其他节点
注意:
1)需要执行命令的是每个服务器的从节点
2)注意主从的ID不要搞混了.
配置群集高可用:
redis-1 ~]# redis-cli -h 192.168.1.128 -p 6381 cluster replicate 2a076272c3b2dbb473a274ca5d13b3090859f9b2 #(第二台主机6380的id)
OK
redis-1 ~]# redis-cli -h 192.168.1.129 -p 6381 cluster replicate 4df4831d147a1f2fe84f892a1c912ae53d5885df #(第三台主机6380的id)
OK
redis-1 ~]# redis-cli -h 192.168.1.134 -p 6381 cluster replicate 3f2038bea39b121230d015a7f6db438f5e4bbfcf #(第一台主机6380的id)
OK
Redis Cluster测试集群,往redis集群里写入数据
redis-1 ~]# redis-cli -c -h 192.168.1.134 -p 6381
192.168.1.134:6381> set k1 v1
-> Redirected to slot [12706] located at 192.168.1.134:6380
OK
192.168.1.134:6380> get k1
"v1"
1)Redis Cluster测试集群
我们使用常规插入redis数据的方式往集群里写入数据看看会发生什么
redis1 ~]# redis-cli -h 192.168.1.128 -p 6380 set k1 v1
(error) MOVED 12706 192.168.1.10:6380
结果提示error, 但是给出了集群另一个节点的地址
那么这条数据到底有没有写入呢? 我们登录这两个节点分别查看
redis1 ~]# redis-cli -h 192.168.1.134 -p 6380 get k1
(nil)
结果没有,这是因为使用集群后由于数据被分片了,所以并不是说在那台机器上写入数据就会在哪台机器的节点上写入,
集群的数据写入和读取就涉及到了另外一个概念,ASK路由
2)Redis Cluster ASK路由介绍
在集群模式下,Redis接受任何键相关命令时首先会计算键对应的槽,再根据槽找出所对应的节点
如果节点是自身,则处理键命令;
否则回复MOVED重定向错误,通知客户端请求正确的节点,这个过程称为Mover重定向.
知道了ask路由后,我们使用-c选项批量插入一些数据
redis1 ~]# cat input_key.sh
#!/bin/bash
for i in $(seq 1 1000)
do
redis-cli -c -h 192.168.1.128 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"
done
写入后我们同样使用-c选项来读取刚才插入的键值,然后查看下redis会不会帮我们路由到正确的节点上
redis1 ~]# redis-cli -c -h redis1 -p 6380
redis1:6380> get k_1
"v_1"
redis1:6380> get k_100
-> Redirected to slot [5541] located at 192.168.1.129:6380
"v_100"
192.168.1.129:6380> get k_1000
-> Redirected to slot [79] located at 192.168.1.128:6380
"v_1000"
192.168.1.128:6380>
至此,redis高可用集群已经部署完毕了,我们在这里就模拟故障,停掉期中一台主机的redis节点,然后查看一下集群的变化。使用暴力的kill -9(真实环境禁止使用,建议使用kill或pkill)杀掉 redis2上的redis集群节点,然后观察节点状态。
理想情况应该是redis1上的6381从节点升级为主节点,在redis1上查看集群节点状态
redis-2 ~]# pkill redis-server #中止redis2的服务
redis-2 ~]# netstat -anpt | grep redis
redis-1 ~]# sh redis_shell.sh tail 6380 #查看日志
7003:M 29 Jul 2020 20:32:16.958 * Background saving started by pid 45019
45019:C 29 Jul 2020 20:32:16.960 * DB saved on disk
45019:C 29 Jul 2020 20:32:16.960 * RDB: 2 MB of memory used by copy-on-write
7003:M 29 Jul 2020 20:32:17.018 * Background saving terminated with success
7003:M 29 Jul 2020 20:32:17.018 * Synchronization with replica 192.168.1.134:6381 succeeded
7003:M 29 Jul 2020 20:39:17.117 * Marking node 2a076272c3b2dbb473a274ca5d13b3090859f9b2 as failing (quorum reached).
7003:M 29 Jul 2020 20:39:17.117 * Marking node dbf036326ee6236101dd0192709e30fb9bd4d204 as failing (quorum reached).
7003:M 29 Jul 2020 20:39:17.117 # Cluster state changed: fail
7003:M 29 Jul 2020 20:39:17.926 # Failover auth granted to 1b73f239763a259484d7d14a0a8bd48e851e761a for epoch 6
7003:M 29 Jul 2020 20:39:17.966 # Cluster state changed: ok
……
虽然我们已经测试了故障切换的功能,但是节点修复后还是需要重新上线,所以这里测试节点重新上线后的操作。
重新启动redis2的6380,然后观察日志,观察redis1上的日志,这时假如我们想让修复后的节点重新上线,可以在想变成主库的从库执行CLUSTER FAILOVER命令,这里我们在redis2的6380上执行
重启redis2的服务,redis-2重回master
redis-2 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-2 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
redis-2 ~]# redis-cli -h 192.168.1.129 -p 6380 CLUSTER FAILOVER #redis2重回master
手动搭建集群便于理解集群创建的流程和细节,不过手动搭建集群需要很多步骤,当集群节点众多时,必然会加大搭建集群的复杂度和运维成本,因此官方提供了 redis-trib.rb的工具方便我们快速搭建集群。redis-trib.rb是采用 Ruby 实现的 redis 集群管理工具,内部通过 Cluster相关命令帮我们简化集群创建、检查、槽迁移和均衡等常见运维操作,使用前要安装 ruby 依赖环境
停掉所有的节点,然后清空数据,恢复成一个全新的集群,所有机器执行命令
pkill redis
rm -rf /data/redis_cluster/redis_6380/*
rm -rf /data/redis_cluster/redis_6381/*
全部清空之后启动所有的节点,所有机器执行
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
!!!注意:新版本redis不需安装,直接采用步骤——————>2、
1、安装命令:
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
redis1执行创建集群命令
cd /opt/redis_cluster/redis/src/
./redis-trib.rb create --replicas 1 192.168.1.128:6380 192.168.1.129:6380 192.168.1.129:6380 192.168.1.128:6381 192.168.1.104:6381 192.168.1.104:6381
检查集群完整性
./redis-trib.rb check 192.168.1.128:6380
创建群集:
redis-1 ~]# redis-cli --cluster create --cluster-replicas 1 192.168.1.128:6380 192.168.1.129:6380 192.168.1.134:6380 192.168.1.128:6381 192.168.1.129:6381 192.168.1.134:6381
检查完整性:
redis-1 ~]# redis-cli --cluster check 192.168.1.128:6380
查看节点信息:
redis-1 ~]# redis-cli -c -h 192.168.1.128 -p 6380
192.168.1.128:6380> cluster nodes
66960aea43bf76f39408cb6e92460ef5935b186d 192.168.1.134:6381@16381 slave 536221568b25ad1c14b211fd8f9a5455451b87db 0 1596032305315 6 connected
45ba6bfbf452a2fd48baf338264abce43e3538d6 192.168.1.134:6380@16380 master - 0 1596032303300 3 connected 10923-16383
536221568b25ad1c14b211fd8f9a5455451b87db 192.168.1.129:6380@16380 master - 0 1596032304306 2 connected 5461-10922
f692d37f9985752b50faf534b958a1c3cf15eb11 192.168.1.129:6381@16381 slave a63dd72d72dcd7b91c15e575d4b79a890aa217fa 0 1596032303000 5 connected
a63dd72d72dcd7b91c15e575d4b79a890aa217fa 192.168.1.128:6380@16380 myself,master - 0 1596032301000 1 connected 0-5460
40c8b52eba1485493a25b3c4c70bba5aa5a60908 192.168.1.128:6381@16381 slave 45ba6bfbf452a2fd48baf338264abce43e3538d6 0 1596032303000 4 connected