一、集群模式
1.1 集群模式的作用
redis 为了提高项目响应速度,经常把热点数据(项目中经常访问的数据)保存到缓存中不是直接从数据库获取。一般大型网站存在28定律,80%的访问量集中在20%的业务,20%业务产生的数据就是热点数据,大型网站热点数据量往往是巨大,单台的缓存服务器是无法满足需求的(单台服务器内存有限),使用多台进行集群作为缓存服务器。
1)高可用,防止单点故障
2)高性能,集群后,集群中每个一节点和单机版能力同级的
3)扩展方便,按需动态增加或者减少集群中节点的数量
4)解决的master写压力 (使用集群可以多个主节点同时写)
1.2 集群模式的优缺点
优点:
1、无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。
2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
3、可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。
假如1000个节点 16384 一个节点上只放 16.3 槽 数据更均匀的存放不同的服
务器,假如该服务器的内存全用来缓存,能缓存的数据会更多
4、高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本
5、实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成
Slave到 Master 的角色提升。
Gossip (疫情传播算法)过程是由种子节点发起,当一个种子节点有状态需要更新到网络中的其他节点时,它会随机的选择周围几个节点散播消息,收到消息的节点也会重复该过程,直至最终网络中所有的节点都收到了消息。
缺点:
1、资源隔离性较差,容易出现相互影响的情况(多个应用同时使用一个redis集群时,可能会出现)。
2、数据通过异步复制,不保证数据的强一致性
3、自动故障切换时,集群状态fail 无法对外提供服务
二、集群模式的实现
2.1 集群模式规划图
2.2 集群模式的具体配置
2.2.1 具体配置
在3台redis服务器创建集群目录,在allsession中执行:
mkdir /usr/redis/cluster
查看,在allsession中执行:
ls /usr/redis/
分别在redis1,redis2,redis3执行:
mkdir /usr/redis/cluster/8001 /usr/redis/cluster/8002 redis1执行
ls /usr/redis/cluster
mkdir /usr/redis/cluster/8003 /usr/redis/cluster/8004 redis2执行
mkdir /usr/redis/cluster/8005 /usr/redis/cluster/8006 redis3执行
复制配置文件到集群节点目录下,在redis1操作:
cp /usr/redis/redis-5.0.5/redis.conf /usr/redis/cluster/8001/
修改配置文件,配置集群:
vim /usr/redis/cluster/8001/redis.conf
具体配置
bind 本机ip //默认ip为127.0.0.1 需要改为其他节点机器可访问的ip 否则创建集群时无法访问对应的端口,无法创建集群
:69 bind 192.168.140.41
: 92 port 8001
:136 daemonize yes //redis后台运行
:158 pidfile /var/run/redis_8001.pid //保存进程id
:699 appendonly yes //aof日志开启 有需要就开启,它会每次写操作都记录一条日志
:729 appendonly everysec
: 832 appendonly everysec //开启集群 把注释#去掉
:840 cluster-config-file nodes_8001.conf //集群的配置 配置文件首次启动自动生成
:846 cluster-node-timeout 15000 //请求超时 默认15秒,可自行设置
复制已经配置好的文件到其他集群节点下:
在redis1执行 将redis1中文件cp到redis2、redis3中
远程登录: 方式一 :scp 方式二:ssh
复制已经配置好的文件到其他集群节点下:
方式一:操作
redis1执行
cp /usr/redis/cluster/8001/redis.conf /usr/redis/cluster/8002/
scp /usr/redis/cluster/8001/redis.conf 192.168.140.42:/usr/redis/cluster/8003/
scp /usr/redis/cluster/8001/redis.conf 192.168.140.43:/usr/redis/cluster/8005/
在redis2中执行
ls /usr/redis/cluster/8003/
scp /usr/redis/cluster/8003/redis.conf /usr/redis/cluster/8004/
在redis3中执行
ls /usr/redis/cluster/8005/
scp /usr/redis/cluster/8005/redis.conf /usr/redis/cluster/8006/
修改redis.conf配置文件(8002、8003、8004、8005、8006)
在redis1中操作(redis2、redis3类似)
vim /usr/redis/cluster/8002/redis.conf
:69 看IP是否需要改 (01-02、03-04、05-06一致)
输入 :%s/8001/8002/g 将文件中8001替换为8002 8003 8004 8005 8006
:92 :158 :840 查看全部替换为8002
redis1中操作:ssh 192.168.140.42
在redis2的test811文件夹下添加文件和文件夹
redis2中操作: ls
2.2.2 启动所有节点,创建集群,测试集群
启动所有节点:
redis1执行:
/usr/redis/bin/redis-server /usr/redis/cluster/8001/redis.conf
/usr/redis/bin/redis-server /usr/redis/cluster/8002/redis.conf
ps -ef |grep redis |grep -v grep 查看是否启动成功
redis2执行:
/usr/redis/bin/redis-server /usr/redis/cluster/8003/redis.conf
/usr/redis/bin/redis-server /usr/redis/cluster/8004/redis.conf
ps -ef |grep redis |grep -v grep 查看是否启动成功
redis3执行:
/usr/redis/bin/redis-server /usr/redis/cluster/8005/redis.conf
/usr/redis/bin/redis-server /usr/redis/cluster/8006/redis.conf
ps -ef |grep redis |grep -v grep 查看是否启动成功
创建集群:
语法:
redis-cli --cluster 执行是集群操作
create 创建集群
ip:port ip:port 参与集群的所有节点 中间用空格分割
--cluster-replicas 1 执行集群中一个主节点的从节点个数(当前总结是6,1主1从,最终为3主,3从)
/usr/redis/bin/redis-cli --cluster create 192.168.140.41:8001 192.168.140.41:8002 192.168.140.42:8003 192.168.140.42:8004 192.168.140.43:8005 192.168.140.43:8006 --cluster-replicas 1
看到该提示,说明成功
2.2.3 测试:
客户端连接集群:
语法:
redis-cli -c 连接集群
-h ip/host 指定要连接的主机或者IP
-p port 指定主机上redis实例端口
redis1上操作
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8001 -c
cluster info 提供当前集群节点状态信息
cluster nodes 获取集群节点配置(显示主从配置信息)
2.2.4 启动关闭集群脚本:
上面步骤知道了集群启动和关闭,如果要频繁的启动或关闭,非常麻烦,所以使用启动关闭脚本,来完成集群的启动和关闭。
创建一个脚本文件夹存放脚本文件
mkidr shelldir
创建脚本文件
vim shelldir/redis-start-stop.sh
编写脚本文件
#!/bin/bash
# 判断redis进程是否运行
#定义一个变量并赋值为当前服务器运行redis-server进程的数量
redisServerNum=`ps -ef |grep redis-server |grep -v grep|wc -l`
#判断当前服务器有没有redis服务进程在运行 如果没有启动,如果有关闭
if [ $redisServerNum == 0 ]; then
echo 'redis集群开始启动'
ssh 192.168.140.41 /usr/redis/bin/redis-server /usr/redis/cluster/8001/redis.conf
ssh 192.168.140.41 /usr/redis/bin/redis-server /usr/redis/cluster/8002/redis.conf
ssh 192.168.140.42 /usr/redis/bin/redis-server /usr/redis/cluster/8003/redis.conf
ssh 192.168.140.42 /usr/redis/bin/redis-server /usr/redis/cluster/8004/redis.conf
ssh 192.168.140.43 /usr/redis/bin/redis-server /usr/redis/cluster/8005/redis.conf
ssh 192.168.140.43 /usr/redis/bin/redis-server /usr/redis/cluster/8006/redis.conf
echo 'redis集群启动完毕'
else
echo 'redis集群开始关闭'
ssh 192.168.140.41 /usr/redis/bin/redis-cli -h 192.168.140.41 -p 8001 shutdown
ssh 192.168.140.41 /usr/redis/bin/redis-cli -h 192.168.140.41 -p 8002 shutdown
ssh 192.168.140.42 /usr/redis/bin/redis-cli -h 192.168.140.42 -p 8003 shutdown
ssh 192.168.140.42 /usr/redis/bin/redis-cli -h 192.168.140.42 -p 8004 shutdown
ssh 192.168.140.43 /usr/redis/bin/redis-cli -h 192.168.140.43 -p 8005 shutdown
ssh 192.168.140.43 /usr/redis/bin/redis-cli -h 192.168.170.43 -p 8006 shutdown
echo 'redis集群关闭完毕'
fi
给脚本赋权限
chmod u+x shelldir/redis-start-stop.sh
可以反复执行,启动或者关闭
./shelldir/redis-start-stop.sh
2.2.5 cluster原理(集群实现细节)
一、节点-槽-值的关系
使用脚本启动集群
/root/shelldir/redis-start-stop.sh
连接集群
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8001
使用cluster info 查看集群状态信息
使用cluster nodes 查看节点主从信息
从上图可以看出主从关系:
槽slot:redis存放数据的单位 槽的总数量是16384 在创建集群会按照配置的主节点数量,大概平均分配在不同的节点上
当前登录的节点显示myself
槽和值的关系:
redis中存放数据都是键值对方式进行存储,所有的数据类型存入redis时都有对应的key, 每次向redis写入数据时,redis会根据key的值使用CRC16算法进行计算得到一个数字,再使用该数字对16384取余,余数是几就会把该数据放入该槽中。
使用客户端连接执行下面命令,如果set没有跳转就使用get:
槽 主节点 从节点 槽
set aaa 111 10439 8004 8001 0-5460
set bbb 222 5287 8003 8006 5461-10922
set ddd 444 11367 8005 8002 10923-16383
key所在的卡槽不在这个节点所在的范围 通过get进行跳转
数据(key-value) 槽 节点
CRC16('aaa')%16384=10439 10439 8003[5461-10922]
CRC16('bbb')%16384=5287 5287 8001[ 0-5460 ]
CRC16('ddd')%16384=11367 5287 8005[ 10923-16383 ]
二、集群架构的实现细节
- 所有的redis节点相互都是互联的,内部使用(ping-pong)机制。
- 集群某一个节点如果失败fail,并不是一个节点说了算,而是集群中超过半数的节点都和该节点无法通信,表明该节点失败fail
- 客户端连接集群时,不需要连接集群所有节点,只需要连接集群中任意一个节点
- 每个节点都会保存各自的数据和整个集群的状态
三、集群的自动故障切换
在创建集群时,为了保证集群的高可用,设置了1主1从,实际工作使用过程中,可以设置1主多从,让集群具有更高可用性。平时进行数据读写时都是主节点来执行,从节点使用主从同步,备份主节点数据,当主机点意外宕机,从节点就会自动转换为主节点,当前主节点保存的数据就可以正常的读写。如果主节点恢复,自动变为从节点。
当前集群中的主从关系:
主节点 从节点
8004 8001
8003 8006
8005 8002
让8004节点宕机(直接使用下面命令关闭8004 redis实例)
/usr/redis/bin/redis-cli -h 192.168.140.42 -p 8004 shutdown
ps -ef |grep redis-server |grep -v grep 就剩8002
等待一定时长 后,使用除了8004之外的其他节点进行连接
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8002 -c
cluster info 发现ok
然后使用cluster nodes
发现 8001变为主节点 8004还处于失败状态
退出 quit
在redis2中 让8004恢复正常
/usr/redis/bin/redis-server /usr/redis/cluster/8004/redis.conf
稍等后查看节点主从情况
这就是自动故障替换 即当master宕机后自动将他的从节点转换为master
当前集群中的主从关系变为:
主节点 从节点
8001 8004
8003 8006
8005 8002
四、集群的失败
1、当没有从节点的主节点宕机,集群状态会失败
当前集群中的主从关系变为:
主节点 从节点
8001 8004
8003 8006
8005 8002
先让8006 从节点宕机
/usr/redis/bin/redis-cli -h 192.168.140.43 -p 8006 shutdown
在redis中查看 ps -ef |grep redis-server |grep -v grep
使用除了8006任意节点进行连接:
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8002 -c
cluster info 发现 ok
cluster nodes 发现 8006 slave,fail
在让8003宕机
/usr/redis/bin/redis-cli -h 192.168.140.42 -p 8003 shutdown
使用除了8003、8006任意节点进行连接:
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8002 -2
cluster info
cluster nodes 发现 8006 slave,fail 8003 master,fail
2、当超过半数的主节点同时宕机,集群状态会失败
上面演示效果时,把8003和8006关掉了,再次启动他们,让集群正常
/usr/redis/bin/redis-server /usr/redis/cluster/8003/redis.conf
/usr/redis/bin/redis-server /usr/redis/cluster/8006/redis.conf
让两个主节点同时宕机,中间间隔不能超过15秒:
当前集群中的主从关系变为:
主节点 从节点
8001 8004
8003 8006
8005 8002
让8003 8005 宕机
/usr/redis/bin/redis-cli -c -h 192.168.140.42 -p 8003 shutdown
/usr/redis/bin/redis-cli -c -h 192.168.140.43 -p 8005 shutdown
使用除了8003和8005节点进行连接:
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8002 -c
三、密钥免密登录
上面每次复制文件时,都必须输入正确密码,向远程服务器复制了4次,需要输入4次密码,能不能不用输入密码,来完成复制或者远程登录
一般在使用ssh 或者是scp命令时,要免密登录
具体使用:
ls -a 在当前登录用户的主目录查看 发现一个.ssh目录 这个目录就是生成公钥和私钥目录,如果从来没有执行ssh或者scp 就没有该目录
ls .ssh/ 发现只有一个kwon_hosts
ssh-keygen -t rsa 使用rsa加密方式生成公钥和私钥 (非对称加密) 回车3次
ls .ssh/ 多出来两个文件
id_rsa 私钥文件(不用于传输) id_rsa.pub pub=public 公钥文件(用于传输)
私钥加密的内容,必须是公钥解密 公钥加密的内容,必须是私钥解码
cat .ssh/id_rsa.pub 查看公钥内容
ssh-copy-id 192.168.140.42 发送公钥到要免密登录的服务器上,第一次发送公钥是需要密码 没有执行前,可以查看远程服务器是否存在公钥文件
ls -a 在redis2执行 发现有.ssh目录
ls .ssh 在redis2执行 发现有 authorized_keys
cat .ssh/authorized_keys
ssh 192.168.140.42 再执行远程登录ssh或者远程scp 发现不需要输入密码,具体原理如下
四、集群模式启动失败修复
当之前集群模式配置正常后,由于某种原因造成启动失败后的修复
在allsession中输入:
rm -rf appendonly.aof dump.rdb nodes-800*
移除appendonly.aof 、dump.rdb 、和以nodes-800开头的文件
再一次输入启动脚本,启动所有节点:
./shelldir/redis-start-stop.sh
在通过下面指令使客户端连接到服务器:
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8001
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8002
重新创建集群:
/usr/redis/bin/redis-cli --cluster create 192.168.140.41:8001 192.168.140.41:8002 192.168.140.42:8003 192.168.140.42:8004 192.168.140.43:8005 192.168.140.43:8006 --cluster-replicas 1
随便连接一个节点查看集群的状态
/usr/redis/bin/redis-cli -c -h 192.168.140.41 -p 8001
cluster info