redis cluster部署和故障模拟

redis cluster

redis cluster介绍

redis Custer是redis的分布式解决方案,在3.0版本正式推出
当遇到单机,内存,并发,流量等瓶颈时,可以采用cluster架构方案达到副在均衡目的
redis Cluster之前的分布式方案有两种:

1.客户端分区方案,优点分区逻辑可控,缺点是需要自己处理数据路由,高可用和故障转移等.
2.代理方案,有点是简化客户端分布式逻辑和升级维护便利,缺点加重架构部署性能消耗.

官方提供的redis Cluster集群方案,很好的解决了集群方面的问题

数据分布

分布式数据库首先要解决把整个数据库集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整体数据的一个子集,需要关注的是数据分布规则,redis Cluster采用哈系分片规则.

image.png

Redis Cluster 通讯流程

在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否出现故障灯状态信息,redis 集群采用 Gossip(流言)协议,Gossip 协议工作原理就是节点彼此不断交换信息,一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播。
通信过程:
1)集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信,通信端口在基础端口上家10000.
2)每个节点在固定周期内通过特定规则选择结构节点发送 ping 消息
3)接收到 ping 消息的节点用 pong 消息作为响应。集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会打成一致的状态,当节点出现故障,新节点加入,主从角色变化等,它能够给不断的ping/pong消息,从而达到同步目的。

cluster架构

image.png

部署cluster

创建相关目录和配置文件

[root@db01 ~]# mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,pid,logs}  ##创建配置目录
[root@db01 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381} ##创建数据目录
[root@db01 ~]# cat /opt/redis_cluster/redis_6380/conf/redis_6380.conf ##编写配置文件
bind 172.16.210.53
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
EOF
[root@db01 ~]# cd /opt/redis_cluster/
[root@db01 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf ##复制配置文件
[root@db01 redis_cluster]# sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.con ##修改配置文件端口
[root@db01 redis_cluster]# rsync -avz /opt/redis_cluster/redis_638* 172.16.210.54:/opt/redis_cluster/ ##将配置文件同步到54主机
[root@db01 redis_cluster]# rsync -avz /opt/redis_cluster/redis_638* 172.16.210.55:/opt/redis_cluster/ ##将配置文件同步到55主机

配置文件说明

cluster-enabled yes  ##激活集群模式
cluster-config-file nodes_6380.conf  ##集群的配置文件
cluster-node-timeout 15000  ##集群的超时时间

编写启动脚本

[root@db01 ~]# cat 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
[root@db01 ~]# scp redis_shell.sh 172.16.210.54:~ 
[root@db01 ~]# scp redis_shell.sh 172.16.210.55:~ ##把脚本传给其他主机

脚本用法: 脚本名 执行动作(start|stop|restart) 端口号

启动服务

[root@db01 ~]# bash redis_shell.sh start  6380  ##脚本加执行操作和端口号
root      2944     1  0 6月12 ?       00:03:39 redis-server 172.16.210.53:6379
root      4200  3945  0 09:04 pts/0    00:00:00 bash redis_shell.sh start 6380
root      4208     1  0 09:04 ?        00:00:00 redis-server 172.16.210.53:6380 [cluster]
root      4210  4200  0 09:04 pts/0    00:00:00 grep redis

配置54主机

在54主机上操作

[root@db02 ~]#find /opt/redis_cluster/redis_638* -type f -name "*.conf" | xargs sed -i "/bind/s#53#54#g" ##修改配置文件的地址
[root@db02 conf]# mkdir -p /data/redis_cluster/redis_{6380,6381} ##创建数据目录
[root@db02 ~]# bash redis_shell.sh start 6380 ##启动服务
root      2313  2187  0 09:17 pts/0    00:00:00 bash redis_shell.sh start 6380
root      2321     1  0 09:17 ?        00:00:00 redis-server 172.16.210.54:6380 [cluster]
root      2323  2313  0 09:17 pts/0    00:00:00 grep redis
[root@db02 ~]# bash redis_shell.sh start 6381
root      2321     1  0 09:17 ?        00:00:00 redis-server 172.16.210.54:6380 [cluster]
root      2326  2187  0 09:17 pts/0    00:00:00 bash redis_shell.sh start 6381
root      2334     1  0 09:17 ?        00:00:00 redis-server 172.16.210.54:6381 [cluster]
root      2336  2326  0 09:17 pts/0    00:00:00 grep redis

配置55主机

在55主机上操作

[root@db02 ~]# find /opt/redis_cluster/redis_638* -type f -name "*.conf" | xargs sed -i "/bind/s#53#55#g" ##修改配置文件的地址
[root@db02 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381} ##创建数据目录
[root@db03 ~]# bash redis_shell.sh start 6380 ##启动服务
root      2175  2067  0 09:21 pts/0    00:00:00 bash redis_shell.sh start 6380
root      2183     1  0 09:21 ?        00:00:00 redis-server 172.16.210.55:6381 [cluster]
root      2185  2175  0 09:21 pts/0    00:00:00 grep redis
[root@db03 ~]# bash redis_shell.sh start 6381 ##启动服务
]root      2183     1  0 09:21 ?        00:00:00 redis-server 172.16.210.55:6380 [cluster]
root      2188  2067  0 09:21 pts/0    00:00:00 bash redis_shell.sh start 6380
root      2196     1  0 09:21 ?        00:00:00 redis-server 172.16.210.55:6381 [cluster]
root      2198  2188  0 09:21 pts/0    00:00:00 grep redis

检查3台主机的启动状态

53主机

[root@db01 ~]# ps -ef | grep redis
root      4262     1  0 09:23 ?        00:00:00 redis-server 172.16.210.53:6380 [cluster]
root      4275     1  0 09:23 ?        00:00:00 redis-server 172.16.210.53:6381 [cluster]
root      4291  3945  0 09:23 pts/0    00:00:00 grep --color=auto redis

54主机

[root@db02 ~]# ps -ef | grep redis
root      2321     1  0 09:17 ?        00:00:00 redis-server 172.16.210.54:6380 [cluster]
root      2334     1  0 09:17 ?        00:00:00 redis-server 172.16.210.54:6381 [cluster]
root      2345  2187  0 09:24 pts/0    00:00:00 grep --color=auto redis

55主机

[root@db03 ~]# ps -ef | grep redis
root      2183     1  0 09:21 ?        00:00:00 redis-server 172.16.210.55:6381 [cluster]
root      2196     1  0 09:21 ?        00:00:00 redis-server 172.16.210.55:6380 [cluster]
root      2205  2067  0 09:23 pts/0    00:00:00 grep --color=auto redis

集群命令

查看集群节点

[root@db01 ~]# bash redis_shell.sh login 6380
172.16.210.53:6380> CLUSTER NODES
3eedc5953af49bad9704d307194cd1cd101935f4 :6380 myself,master - 0 0 0 connected

发现集群节点

172.16.210.53:6380> CLUSTER MEET 172.16.210.53 6381
OK
172.16.210.53:6380> CLUSTER MEET 172.16.210.54 6380
OK
172.16.210.53:6380> CLUSTER MEET 172.16.210.54 6381
OK
172.16.210.53:6380> CLUSTER MEET 172.16.210.55 6380
OK
172.16.210.53:6380> CLUSTER MEET 172.16.210.55 6381
OK
##以此把所有节点加入进来

再次使用查看集群节点命令

172.16.210.53:6380> CLUSTER NODES
2c5c48d5c28dd2376b28cf06182ce121d6c62826 172.16.210.54:6380 master - 0 1592117997778 1 connected
10ffb69d3ff475fb3532dda5bce8b9c1d25fc7e2 172.16.210.54:6381 master - 0 1592117993655 5 connected
19196c490965066887e11e206f303bfc8b080616 172.16.210.55:6381 master - 0 1592117994790 4 connected
c10246cc353355edf12063ad0911d39b8b560271 172.16.210.53:6381 myself,master - 0 0 0 connected
3eedc5953af49bad9704d307194cd1cd101935f4 172.16.210.53:6380 master - 0 1592117993654 3 connected
2d304c2691ae2053ed8f943b7e1bca2ad5ced7d8 172.16.210.55:6380 master - 0 1592117992653 2 connected 
##此时,所有节点就已经连接成功

分配槽位

虽然节点之间已经互相发现了.但是此时集群还是不可用的状态,因为并没有给节点分配槽位,而却必须是所有的槽位都分配完毕后整个集群才是可用的状态
反之,也就是说只要有一个槽位没有分配,那么整个集群就是不可用的
尝试插入数据

[root@db01 ~]# bash redis_shell.sh login 6380
172.16.210.53:6380> set k1 v1
(error) CLUSTERDOWN Hash slot not served

分配槽位的方法

分配槽位需要在每个主节点上来配置,此时有2中方法执行:
1.分别登录到每个主节点的客户端来执行命令
2.在其中一台机器上用redis客户端远程登录到其他机器的主节点上执行命令

在53节点执行命令

[root@db01 ~]# redis-cli -h 172.16.210.53  -p 6380 cluster addslots {0..5461}
[root@db01 ~]# redis-cli -h 172.16.210.54  -p 6380 cluster addslots {5462..10922}
OK
[root@db01 ~]# redis-cli -h 172.16.210.55 -p 6380 cluster addslots {10923..16383}

分配问所有槽位后我们查看一下集群的状态

[root@db01 ~]# redis-cli -h 172.16.210.53 -p 6380
172.16.210.53: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:5
cluster_my_epoch:3
cluster_stats_messages_sent:1648
cluster_stats_messages_received:1132

可以看到cluster_state是ok的,证明我们集群状态是ok的

配置高可用

虽然这时候集群是可用的了,但是整个集群只要有一台机器坏掉了,那么整个集群都是不可用的.
所以这时候需要用到其他三个节点分别作为现在三个主节点的从节点,以应对集群主节点故障时可以进行自动切换以保证集群持续可用.

注意:
不要让复制节点复制本机器的主节点, 因为如果那样的话机器挂了集群还是不可用状态, 所以复制节点要复制其他服务器的主节点.

在53节点上操作

注意:
1.需要执行命令的是每个服务器的从节点
2.注意主从的ID不要搞混了

172.16.210.53:6380> CLUSTER NODES
2c5c48d5c28dd2376b28cf06182ce121d6c62826 172.16.210.54:6380 master - 0 1592124516322 1 connected 5462-10922
c10246cc353355edf12063ad0911d39b8b560271 172.16.210.53:6381 master - 0 1592124516471 0 connected
10ffb69d3ff475fb3532dda5bce8b9c1d25fc7e2 172.16.210.54:6381 master - 0 1592124510278 5 connected
19196c490965066887e11e206f303bfc8b080616 172.16.210.55:6381 master - 0 1592124511280 4 connected
3eedc5953af49bad9704d307194cd1cd101935f4 172.16.210.53:6380 myself,master - 0 0 3 connected 0-5461
2d304c2691ae2053ed8f943b7e1bca2ad5ced7d8 172.16.210.55:6380 master - 0 1592124515371 2 connected 10923-16383
[root@db01 ~]# redis-cli -h 172.16.210.53 -p 6381 cluster replicate 2c5c48d5c28dd2376b28cf06182ce121d6c62826
OK
[root@db01 ~]# redis-cli -h 172.16.210.54 -p 6381 cluster replicate 2d304c2691ae2053ed8f943b7e1bca2ad5ced7d8
OK
[root@db01 ~]# redis-cli -h 172.16.210.55 -p 6381 cluster replicate 3eedc5953af49bad9704d307194cd1cd101935f4
OK

插入数据测试:

[root@db01 ~]# redis-cli -h 172.16.210.53 -p 6380 
172.16.210.53:6380> set k1 v1
(error) MOVED 12706 172.16.210.55:6380

提示报错:(error) MOVED 12706 172.16.210.55:6380

这是因为集群由于数据被分片了,所以并不是说在那台机器上写入数据就会在那台机器的节点上写入,集群的数据写入和读取就涉及到另外一个概念,ASK路由

Redis Cluster ASK路由

image.png

在集群模式下,Redis接受任何键相关命令时首先会计算键对应的槽,再根据槽找出所对应的节点
如果节点是自身,则处理键命令;
否则回复MOVED重定向错误,通知客户端请求正确的节点,这个过程称为Mover重定向.

知道了ask路由后,我们使用-c选项批量插入一些数据

[root@db01 ~]# redis-cli -c -h 172.16.210.53 -p 6380
172.16.210.53:6380> set k4 v4
-> Redirected to slot [8455] located at 172.16.210.54:6380  ##这条信息提示我们数据是插在54主机的
OK
172.16.210.54:6380> keys *
1) "k4"

编写插入脚本测试

[root@db01 ~]# vim for_redis.sh
#!/bin/bash
for i in {1..1000}
do
    
    redis-cli -c -h  172.16.210.54 -p 6380 set k_${i} v_${i}
done
[root@db01 ~]# bash for_redis.sh ##执行插入命令

分别在三台主机查看数据分布情况

主机53

root@db01 ~]# bash redis_shell.sh login 6380
172.16.210.53:6380> keys * 
--
---
339) "k_314"
340) "k_365"
341) "k_116"  ##插入了341条数据

主机54

[root@db02 ~]# bash redis_shell.sh login 6380  
172.16.210.54:6380> keys * 
--
--
324) "k_378"
325) "k_534"
326) "k_144"
327) "k_220" ##插入了327条数据

主机55

[root@db03 ~]# bash redis_shell.sh login 6380
172.16.210.55:6380> keys * 
--
--
334) "k_980"
335) "k_146"
336) "k_594" 
##插入了336条数据

因为有些数据是之前测试插入的,所以这次脚本测试,可以看到数据很平均的插入到了每个节点

故障模拟演练

停掉53主机的主节点

 [root@db01 ~]# bash redis_shell.sh stop 6380
root      4730     1  0 16:34 ?        00:00:22 redis-server 172.16.210.53:6381 [cluster]
root      4901  4844  0 20:51 pts/0    00:00:00 redis-cli -c -h 172.16.210.53 -p 6380
root     16036  4924  0 21:29 pts/1    00:00:00 bash redis_shell.sh stop 6380
root     16045 16036  0 21:29 pts/1    00:00:00 grep redis

登录53主机的从节点查看状态

[root@db01 ~]# bash redis_shell.sh login 6381
172.16.210.53:6381> CLUSTER INFO
cluster_state:ok   ##可以看到状态还是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_sent:1010
cluster_stats_messages_received:172
image.png

可以看到原本53主机的主节点槽位成功转移到了55主机的从节点

172.16.210.53:6381> set czq 19
-> Redirected to slot [2847] located at 172.16.210.55:6381
OK
172.16.210.55:6381> get czq
"19"  ##也可以成功插入数据

再次测试:把其他主机的主节点都关闭

因为我们在配置文件中设置了集群的超时时间是15秒,所以每次听掉一个主节点,最好是15秒停一个

[root@db02 ~]# bash redis_shell.sh stop 6380
root      2556     1  0 16:35 ?        00:00:21 redis-server 172.16.210.54:6381 [cluster]
root      2713  2662  0 21:40 pts/1    00:00:00 bash redis_shell.sh stop 6380
root      2722  2713  0 21:40 pts/1    00:00:00 grep redis
[root@db03 ~]# bash redis_shell.sh stop 6380
root      2360     1  0 16:34 ?        00:00:20 redis-server 172.16.210.55:6381 [cluster]
root      2511  2470  0 21:39 pts/1    00:00:00 bash redis_shell.sh stop 6380
root      2520  2511  0 21:39 pts/1    00:00:00 grep redis

查看集群状态

[root@db01 ~]# bash redis_shell.sh login 6381
172.16.210.53:6381> CLUSTER INFO
cluster_state:ok  ##状态是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:8
cluster_my_epoch:7
cluster_stats_messages_sent:17008
cluster_stats_messages_received:2007
image.png

可以看到槽位也自动转移到了每台主机的从节点

查看数据

[root@db01 ~]# bash redis_shell.sh login 6381
172.16.210.53:6381> keys * 
--
--
3315) "k_9465"
3316) "k_8258"
3317) "k_6556"  

可以看到原来的数据也还在

你可能感兴趣的:(redis cluster部署和故障模拟)