搭建Redis高可用群集

redis群集简述

redis3.0版本以上开始支持cluster,采用的是hash slot(hash槽),可以将多个redis实例整合在一起,形成一个群集,也就是将数据分散到几群的多台机器上。

redis cluster原理

Redis Cluster是一个无中心的结构,每个节点都保存数据和整个集群的 状态,每个节点都会保存其他节点的信息,知道其他节点所负责的槽,并且会与其他节点定时发送心跳信息,能够及时感知群集中的异常的节点

集群角色分为master和slave,master之间分配 slots。一共16384个slot,slave向他指定的master同步数据,实现备份,当其中的一个master宕机时,该master的slave将提升为master,以保证集群的slot的完整,当其中某一个master和slave都宕机了,该集群的slot不完整,此时,集群失效。

如果手动搭建集群,每个master所分配的slot我们可以自定义分配多少;如果是使用redis-cli --cluster命令自动搭建集群,则master的slot也是自动分配

redis cluster解决了什么问题

当遇到宕机、内存、并发、流量等瓶颈时,可以采用Cluster架构方案达到负载均衡目的。

redis cluster的数据分布

分布式数据库首先要解决把整个数据库集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上;
每个节点负责整体数据的一个子集,需要关注的是数据分片规则,Redis Cluster采用哈希分片规则(即上面提到的分配slot)。

redis cluster 的通讯流程

在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否出现故障灯状态信息,redis 集群采用Gossip(流言)协议(类似网络里面的ospf协议),Gossip 协议工作原理就是节点彼此不断交换信息,一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播。

通信过程:

1)集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信,防火墙放行(端口号+10000,因为做好集群后会开启新的端口,就是10000+端口号,例如下面的16380,16381)

2)每个节点在固定周期内通过特定规则选择结构节点发送ping 消息

3)接收到 ping 消息的节点用 pong消息作为响应。集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会打成一致的状态,当节点出现故障,新节点加入,主从角色变化等,它能够给不断的ping/pong消息,从而达到同步目的。

常见 Gossip 消息分为:ping、 pong、 meet、 fail 等

meet 消息:用于通知新节点加入,消息发送者通知接受者加入到当前集群,meet 消息通信正常完成后,接收节点会加入到集群中并进行ping、 pong 消息交换

ping 消息:集群内交换最频繁的消息,集群内每个节点每秒想多个其他节点发送 ping 消息,用于检测节点是否在线和交换彼此信息。

Pong 消息:当接收到 ping,meet 消息时,作为相应消息回复给发送方确认消息正常通信,节点也可以向集群内广播自身的 pong 消息来通知整个集群对自身状态进行更新。

fail 消息:当节点判定集群内另一个节点下线时,回向集群内广播一个fail 消息,其他节点收到 fail 消息之后把对应节点更新为下线状态。

redis集群的部署

所需环境:3主3从

主机 系统 描述
192.168.10.3 Centos7.4 redis1:开启2个redis进程,一个做master,一个做slave
192.168.10.4 Centos7.4 redis2:开启2个redis进程,一个做master,一个做slave
192.168.10.8 Centos7.4 redis3:开启2个redis进程,一个做master,一个做slave

准备基础环境

redis1:

创建集群的安装目录和数据的存放目录

[root@redis1 ~]# mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid}
[root@redis1 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381}

下载解压并安装redis源码包

wget http://download.redis.io/releases/redis-5.0.6.tar.gz
tar zxf redis-5.0.6.tar.gz -C /opt/redis_cluster/
ln -s /opt/redis_cluster/redis-5.0.6  /opt/redis_cluster/redis  #做好软连接,方便自己管理 
cd redis
make && make install

准备配置文件,添加以下内容,
添加并开启集群功能后,会在/data/redis_cluster目录生成对应的新集群文件

cat > /opt/redis_cluster/redis_6380/conf/redis_6380.conf <<EOF
bind 192.168.10.3
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/"  # 开启redis后,生成所有的配置文件存放位置
cluster-enabled yes                   # 开启集群功能
cluster-config-file clusters_6380.conf   # 集群文件
cluster-node-timeout 15000				# 集群超时时间
EOF

复制redis_6380的配置文件给redis_6381

cp /opt/redis_cluster/redis_6380/conf/redis_6380.conf /opt/redis_cluster/redis_6381/conf/redis_6381.conf

复制完,修改一下地方

sed -i 's:6380:6381:g' /opt/redis_cluster/redis_6381/conf/redis_6381.conf

开启两个redis服务

[root@redis1 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf 
[root@redis1 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf 
[root@redis1 redis]# netstat -anpt | grep redis
tcp        0      0 192.168.10.3:6380       0.0.0.0:*               LISTEN      41834/redis-server  
tcp        0      0 192.168.10.3:6381       0.0.0.0:*               LISTEN      41845/redis-server  
tcp        0      0 192.168.10.3:16380      0.0.0.0:*               LISTEN      41834/redis-server  
tcp        0      0 192.168.10.3:16381      0.0.0.0:*               LISTEN      41845/redis-server  
[root@redis1 redis]# 

redis2 和 redis3:

1.复制redis1的安装和数据目录到redis2、redis3
并且创建集群配置配置文件存放的目录

[root@redis1 ~]# scp -rp /opt/redis_cluster/ [email protected]:/opt
[root@redis1 ~]# scp -rp /opt/redis_cluster/ [email protected]:/opt
[root@redis2 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381}
[root@redis3 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381}

2.在/opt/redis_cluster/redis目录安装redis

cd /opt/redis_cluster/redis
make install 

3.修改配置文件

find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#192.168.10.3#192.168.10.4#g"

find /opt/redis_cluster/redis_638* -type f -name "*.conf" -exec sed -i "/bind/s:192.168.10.3:192.168.10.8:g" {} \;

4.启动服务

[root@redis2 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf 
[root@redis2 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf 
[root@redis2 ~]# netstat -anpt|grep redis
tcp        0      0 192.168.10.4:6380       0.0.0.0:*               LISTEN      37776/redis-server  
tcp        0      0 192.168.10.4:6381       0.0.0.0:*               LISTEN      37787/redis-server  
tcp        0      0 192.168.10.4:16380      0.0.0.0:*               LISTEN      37776/redis-server  
tcp        0      0 192.168.10.4:16381      0.0.0.0:*               LISTEN      37787/redis-server  
[root@redis2 ~]# 

[root@redis3 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf 
[root@redis3 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf 
[root@redis3 ~]# netstat -anpt | grep redis
tcp        0      0 192.168.10.8:6380       0.0.0.0:*               LISTEN      40760/redis-server  
tcp        0      0 192.168.10.8:6381       0.0.0.0:*               LISTEN      40771/redis-server  
tcp        0      0 192.168.10.8:16380      0.0.0.0:*               LISTEN      40760/redis-server  
tcp        0      0 192.168.10.8:16381      0.0.0.0:*               LISTEN      40771/redis-server  
[root@redis3 ~]# 

到这里,集群基本环境已经搭建好了

下面开始,进入正题

手动配置节点发现

集群模式的Redis除了原有的配置文件之外又加了一份集群配置文件.当集群内节点信息发生变化,如添加节点,节点下线,故障转移等.节点会自动保存集群状态到配置文件.需要注意的是,Redis自动维护集群配置文件,不需要手动修改,以免节点重启时产生错乱.

添加redis_cluster管理脚本

#!/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(){

提示:在集群内任意一台机器执行此命令就可以

[root@redis1 ~]# sh redis_shell.sh login 6380
192.168.10.3:6380> CLUSTER MEET 192.168.10.3 6381
OK
192.168.10.3:6380> CLUSTER MEET 192.168.10.4 6380
OK
192.168.10.3:6380> CLUSTER MEET 192.168.10.4 6381
OK
192.168.10.3:6380> CLUSTER MEET 192.168.10.8 6381
OK
192.168.10.3:6380> CLUSTER MEET 192.168.10.8 6380
OK
192.168.10.3:6380> CLUSTER NODES
93a93e60113732632ca9b2ac374a00fa3df95f0b 192.168.10.3:6381@16381 master - 0 1589639820000 0 connected
641138a19d87c33537f67798a9b081c63d675def 192.168.10.4:6380@16380 master - 0 1589639820712 2 connected
3abecec25168c2fecb64ed02d3301e9df1f7adde 192.168.10.4:6381@16381 master - 0 1589639821720 3 connected
91df6dd3ed4edff57b7a5bd91badb2772787ce47 192.168.10.8:6380@16380 master - 0 1589639819000 5 connected
46046332955b6b77d0805e6fb4427ea4e12aa886 192.168.10.8:6381@16381 master - 0 1589639819000 4 connected
586a50643f5e5b091958254a5ed440a038e96e61 192.168.10.8:6380@16380 myself,master - 0 1589639818000 1 connected
192.168.10.3:6380> 

节点都发现完毕后我们再次查看集群配置文件
可以看到,发现到的节点的ID也被写入到了集群的配置文件里,注意,此时他们每个节点还都是master;
在这里插入图片描述

Redis Cluster手动分配槽位

虽然节点之间已经互相发现了,但是此时集群还是不可用的状态,因为并没有给节点分配槽位,而且必须是所有的槽位都分配完毕后整个集群才是可用的状态.
反之,也就是说只要有一个槽位没有分配,那么整个集群就是不可用的.
在这里插入图片描述
分配槽位需要在每个主节点上来配置,此时有2种方法执行:

  • 分别登录到每个主节点的客户端来执行命令
  • 在其中一台机器上用redis客户端远程登录到其他机器的主节点上执行命令
[root@redis1 ~]# redis-cli -h 192.168.10.4 -p 6380 cluster addslots {0..5461}
OK
[root@redis1 ~]# redis-cli -h 192.168.10.3 -p 6380 cluster addslots {5462..10922}
OK
[root@redis1 ~]# redis-cli -h 192.168.10.8 -p 6380 cluster addslots {10923..16383}
OK

分配完节点后,再来看集群状态,变成了ok,
集群是可以用了,但是还得划分从服务器,实现高可用
在这里插入图片描述

手动配置集群高可用

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

大忌:一定不要在一台主机上配置主从,否则,一旦宕机,主从全部不能使用,集群也就不能在使用。

在从节点上分配对应的主节点

一定要细心,不要给错 id;
且一定要 交叉着分配.

[root@redis1 ~]# redis-cli -h 192.168.10.3 -p 6381 cluster replicate 641138a19d87c33537f67798a9b081c63d675def
OK
[root@redis1 ~]# redis-cli -h 192.168.10.4 -p 6381 cluster replicate 91df6dd3ed4edff57b7a5bd91badb2772787ce47
OK
[root@redis1 ~]# redis-cli -h 192.168.10.8 -p 6381 cluster replicate 586a50643f5e5b091958254a5ed440a038e96e61
OK

完成后,再看集群状态,6381全部变成了slave
在这里插入图片描述

验证集群的高可用

执行脚本创建100个key
登录任意一个节点查看,都可见
脚本:例如在192.168.10.4节点上写入了100个key

#!/bin/bash
for i in {1..100}
do
	redis-cli -c -h 192.168.10.4 -p 6380 set k$i v$i
done

在redis1上登录查看key
注意:查看完会自动跑到存放这个key的节点上

[root@redis1 ~]# sh redis_shell.sh login 6380
192.168.10.3:6380> get k50   
"v50"
192.168.10.3:6380> get k99
-> Redirected to slot [13293] located at 192.168.10.8:6380
"v99"
192.168.10.8:6380> get k22
-> Redirected to slot [7804] located at 192.168.10.3:6380
"v22"
192.168.10.3:6380> 

现在,模拟一个master宕机,看看slave会不会变成master
在redis2:192.168.10.4上关掉redis-server
pkill redis-server
查看日志和群集状态
关掉redis上服务后,相当于6台节点坏了1主1从,不过不影响,192.168.10.4的master的从服务器在10.3上,所以在192.168.10.3会有6381的节点变成master,这时候,集群里面还是3个主节点,依然可用;
在这里插入图片描述
过了一段时间,管理员和运维人员修好后,redis2可以正常使用了

[root@redis2 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf 
[root@redis2 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf

这时候,原来的master不会抢占回来,和keepalived不同,需要手动切换
redis-cli -c -h 192.168.10.4 -p 6380 cluster failover
再来看集群状态
在这里插入图片描述
再看,都切换了回来

自动搭建部署Redis Cluster

首先,我们需要还原最初的原始环境,我们前面也说过了,redis集群的配置信息都收集在自己的一个单独的存放位置/data/redis_cluster/redis_638*/nodes_cluster.conf;
他记录了每台节点的连接信息,
所以,我们先停掉所有的服务,删掉这个文件就好了
下面内容在每台主机都要做:
pkill redis
rm -rf /data/redis_cluster/redis_6380/*
rm -rf /data/redis_cluster/redis_6381/*

在重启redis服务,就回到了上边我们刚刚准备好的基础环境那里,
同理,在每一台都要做

#开启6个节点
sh redis_shell.sh start 6380
sh redis_shell.sh start 6381

自动创建集群

在这6个节点任何一台做都可以,
这里以redis1为例

[root@redis1 ~]# redis-cli --cluster create 192.168.10.3:6380 192.168.10.4:6380 192.168.10.8:6380 192.168.10.3:6381 192.168.10.4:6381 192.168.10.8:6381 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.10.4:6381 to 192.168.10.3:6380
Adding replica 192.168.10.8:6381 to 192.168.10.4:6380
Adding replica 192.168.10.3:6381 to 192.168.10.8:6380
M: acc68368ced4fcbeb6d069bef5633ceca633653f 192.168.10.3:6380
   slots:[0-5460] (5461 slots) master
M: 31c7fcdfcc1ae7b5b3495b304f66e82a6804c4d2 192.168.10.4:6380
   slots:[5461-10922] (5462 slots) master
M: 09003c83714dadea471b8c1ffece10f0242bd631 192.168.10.8:6380
   slots:[10923-16383] (5461 slots) master
S: e44dff5e79b57a472a360205580bf618bea61ae1 192.168.10.3:6381
   replicates 09003c83714dadea471b8c1ffece10f0242bd631
S: d7449102287fb416956c85f2572e46217e09bafb 192.168.10.4:6381
   replicates acc68368ced4fcbeb6d069bef5633ceca633653f
S: 20f9f11c9ccd4eadf418a43d0f2b8eeaace30e8e 192.168.10.8:6381
   replicates 31c7fcdfcc1ae7b5b3495b304f66e82a6804c4d2
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 192.168.10.3:6380)
M: acc68368ced4fcbeb6d069bef5633ceca633653f 192.168.10.3:6380
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 20f9f11c9ccd4eadf418a43d0f2b8eeaace30e8e 192.168.10.8:6381
   slots: (0 slots) slave
   replicates 31c7fcdfcc1ae7b5b3495b304f66e82a6804c4d2
M: 31c7fcdfcc1ae7b5b3495b304f66e82a6804c4d2 192.168.10.4:6380
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: e44dff5e79b57a472a360205580bf618bea61ae1 192.168.10.3:6381
   slots: (0 slots) slave
   replicates 09003c83714dadea471b8c1ffece10f0242bd631
M: 09003c83714dadea471b8c1ffece10f0242bd631 192.168.10.8:6380
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: d7449102287fb416956c85f2572e46217e09bafb 192.168.10.4:6381
   slots: (0 slots) slave
   replicates acc68368ced4fcbeb6d069bef5633ceca633653f
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered

可以看出,已经自动分配的槽(slots),而且谁做主,谁做从也给分配好了,而且也是交叉这互为主从,没有在集中在同一节点

配置完成,可以使用redis-cli --cluster check 192.168.10.3:6380 检查群集完整性

在这里插入图片描述

总结一:redis cluster 常用的命令

集群(cluster)

CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。 

节点(node)

CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。 

槽(slot)

CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。 

键 (key)

CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。

总结二:更深入的了解redis

redis cluster就说那么多了,学到现在,自己捋了捋,redis应该应用到什么场景下,以前只知道redis做缓存性能很好,但这还远远不够。
更多内容参考另外关于redis的博客:
redis的持久化配置与主从复制
redis在网站架构中做缓存服务器(nginx+tomcat+redis+mysql)

redis应用场景还有:

  • 天然计数器
    可以对 String 进行自增自减运算,从而实现计数器功能。Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。如统计抖音热门视频的播放量,点赞量,评论数等各种需要运算统计的领域

  • 缓存
    将热点数据放到内存里面,来降低用户的等待时间,加快数据的访问速度,还可以设置内存的最大使用量以及淘汰策略来保证缓存的命中率

  • 会话缓存
    网站架构通常用的就是负载均衡群集,但是同一用户多次访问此页面,会被调度到其他的web节点服务器上,占用不必要的session会话,redis可以实现web集群共享session会话

  • 全页缓存
    除了基本的会话外,redis好提供了简便的FPC平台,不过需要和其他的插件结合用,如:WordPress用户来说,wp-redis插件可以帮助你做以最快的速度加载你之前浏览过的网页

  • 消息队列(发布/订阅功能)
    一大新型行业直播的流行,短视频时代轰天铺地,说不定你就被那个主播所吸引,比如虎牙直播就有的订阅,关注功能,只要你关注的人发布了直播,你的不管是客户端还是移动端就会收到开播提醒的功能

  • 其他
    通过自己所支持的数据类型,功能繁多,如:商场券过期时间与string字符串有关,刷礼物的大哥榜一榜二榜三和 list(列表)和 zset(有序集合)有关等

下一篇还有一点点:《redis集群扩容与收缩和集群部署完的优化》

原创文章 59 获赞 20 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43815140/article/details/106163920