一、 持久化
1.RDB持久化和AOF持久化
RDB: 类似于快照,当前内存里的数据的状态持久化到硬盘
优点:压缩格式/恢复速度快
缺点:不是实时的,可能会丢数据,操作比较重量
AOF:类似于mysql的binlog,可以设置成每秒/每次操作都以追加的形式保存在日志文件中
优点:安全,最多只损失1秒的数据,具备一定的可读性
缺点:文件比较大,恢复速度慢
2.RDB持久化流程图
3.配置RDB持久化
save 900 1
save 300 10
save 60 10000
dbfilename redis.rdb
dir /data/redis_6379/
4.RDB持久化结论:
没配置save参数时:
1.shutdown/pkill/kill都不会持久化保存
2.可以手动执行bgsave
配置save参数时:
1.shutdown/pkill/kill均会自动触发bgsave持久化保存数据
2.pkill -9 不会触发持久化
恢复时:
1.持久化数据文件名要和配置文件里定义的一样才能被识别
2.RDB文件只有一个数据文件,迁移和备份只要这一个RDB文件即可
注意:
RDB高版本兼容低版本,低版本不能兼容高版本
3.x >> 5.X >> OK
5.x >> 3.x >> NoOK
日志内容:
8952:M 13 Apr 2020 17:33:12.947 # User requested shutdown...
8952:M 13 Apr 2020 17:33:12.947 * Saving the final RDB snapshot before exiting.
8952:M 13 Apr 2020 17:33:12.947 * DB saved on disk
8952:M 13 Apr 2020 17:33:12.947 * Removing the pid file.
8952:M 13 Apr 2020 17:33:12.947 # Redis is now ready to exit, bye bye...
4.AOF流程图
5.AOF持久化配置
appendonly yes
appendfilename "redis.aof"
appendfsync everysec
6.AOF重写机制
实验流程:
执行的命令 aof记录 redis里的数据
set k1 v1 set k1 k1
set k2 v2 set k1 k1 k2
set k2
set k3 v3 set k1 k1 k2 k3
set k2
set k3
del k1 set k1 k2 k3
set k2
set k3
del k1
del k2 set k1 k3
set k2
set k3
del k1
del k2
aof文件里实际有意义的只有一条记录:
set k3
操作命令:
重写AOF
BGREWRITEAOF
7.AOF和RDB读取实验
实验背景:
aof和rdb同时存在,redis重启会读取哪一个数据?
实验步骤:
set k1 v1
set k2 v2
bgsave rbd保存 k1 k2
mv redis.rdb /opt/
flushall
set k3 v3
set k4 v4 aof保存 k3 k4
mv redis.aof /opt/
redis-cli shutdown
rm -rf /data/redis_6379/*
mv /opt/redis.aof /data/redis_6379/
mv /opt/redis.rdb /data/redis_6379/
systemctl start redis
实验结论:
当aof和rdb同时存在的时候,redis会优先读取aof的内容
8.AOF模拟故障
损坏实验结论:
1.aof修复命令不要用,因为他的修复方案非常粗暴,一刀切,从出错的地方到最后全部删除
2.任何操作之前,先备份数据
kill -9 实验:
for i in {1..10000};do redis-cli set key_${i} v_${i} && echo "${i} is ok";done
ps -ef|grep redis|grep -v grep|awk '{print "kill -9",$2}'
结论:
1.aof相对比较安全,最多丢失1秒数据
9.如果设置了过期时间,恢复数据后会如何处理?
1.aof文件会记录下过期时间
2.恢复的时候会去对比过期时间和当前时间,如果超过了,就删除key
3.key的过期时间不受备份影响
10.AOF和RDB如何选择
https://redis.io/topics/persistence
1.开启混合模式
2.开启aof
3.不开启rdb
4.rdb采用定时任务的方式定时备份
5.可以从库开启RDB进行备份
二、redis用户验证
1.配置密码认证功能
requirepass 123456
2.使用密码
第一种:
[root@db01 ~]# redis-cli
127.0.0.1:6379> set k1 v1
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> keys *
1) "k1"
第二种:
[root@db01 ~]# redis-cli -a '123456' get k1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"v1"
3.为什么redis的密码认证这么简单?
1.redis一般都部署在内网环境,默认是相对比较安全的
2.有同学担心密码写在配置文件里,不用担心,因为开发不允许SSH登陆到Linux服务器,但是可以远程连接Redis,所以设置密码还是有作用的
三、禁用或重命名危险命令
1.禁用危险命令
rename-command KEYS ""
rename-command SHUTDOWN ""
rename-command CONFIG ""
rename-command FLUSHALL ""
2.重命名危险命令
rename-command KEYS "QQ526195417"
rename-command SHUTDOWN ""
rename-command CONFIG ""
rename-command FLUSHALL ""
四、主从复制
1.快速部署第二台Redis服务器
ssh-keygen
ssh-copy-id 10.0.0.51
rsync -avz 10.0.0.51:/opt/redis_6379 /opt/
rsync -avz 10.0.0.51:/usr/local/bin/redis* /usr/local/bin/
rsync -avz 10.0.0.51:/usr/lib/systemd/system/redis.service /usr/lib/systemd/system/
sed -i 's#51#52#g' /opt/redis_6379/conf/redis_6379.conf
mkdir -p /data/redis_6379
groupadd redis -g 1000
useradd redis -u 1000 -g 1000 -M -s /sbin/nologin
chown -R redis:redis /opt/redis*
chown -R redis:redis /data/redis*
systemctl daemon-reload
systemctl start redis
报错总结:
1.在db01上执行了命令
2.配置文件里的密码没删掉
3.配置文件里的重命名参数没删掉
4.用户id和组id冲突
5.没有rsync
6.拷贝过来的配置文件没有修改IP地址
2.db01插入测试命令
for i in {1..1000};do redis-cli set key_${i} v_${i} && echo "${i} is ok";done
3.配置主从复制
方法1:临时生效
redis-cli -h 10.0.0.52 SLAVEOF 10.0.0.51 6379
方法2:写进配置文件永久生效
SLAVEOF 10.0.0.51 6379
4.检查复制进度
INFO replication
ROLE
4.主从复制流程
1.简单流程
1.从节点发送同步请求到主节点
2.主节点接收到从节点的请求之后,做了如下操作
- 立即执行bgsave将当前内存里的数据持久化到磁盘上
- 持久化完成之后,将rdb文件发送给从节点
3.从节点从主节点接收到rdb文件之后,做了如下操作
- 清空自己的数据
- 载入从主节点接收的rdb文件到自己的内存里
4.后面的操作就是和主节点实时的了
5.取消复制
SLAVEOF no one
6.主从复制注意
1.从节点只读不可写
2.从节点不会自动故障转移,他会一直尝试同步主节点,并且依然不可写
3.主从复制故障转移需要介入的地方
- 修改代码指向新主的IP
- 从节点需要执行slaveof no one
4.从库建立同步时会清空自己的数据,如果同步对象写错了,就清空了
5.从库也可以正常的RDB持久化
7.安全的操作
一定要做好数据备份,无论是主节点还是从节点,操作前最好做下备份
五、Redis Sentinel(哨兵)
1.哨兵的作用
1、监控
2、自动选主,切换( slaveof no one)
采用的是raft分布式一致性协议进行选主:数据节接近主,可以和大部分节点联系,少数服从多数。
(RAFT Paxos)
3、重构主从关系
4、应用透明
5、自动处理故障节点
6.解决主从复制需要人为干预的问题
7.提供了自动的高可用方案
画图:
2.目录和端口规划
redis节点 6379
哨兵节点 26379
3.部署3台redis单节点主从关系
db01操作
pkill redis
cat >/opt/redis_6379/conf/redis_6379.conf <<EOF
daemonize yes
bind 127.0.0.1 10.0.0.51
port 6379
pidfile "/opt/redis_6379/pid/redis_6379.pid"
logfile "/opt/redis_6379/logs/redis_6379.log"
dbfilename "redis.rdb"
dir "/data/redis_6379"
appendonly yes
appendfilename "redis.aof"
appendfsync everysec
EOF
systemctl start redis
redis-cli
db02和db03操作
ssh-keygen
ssh-copy-id 10.0.0.51
pkill redis
rm -rf /opt/redis*
rsync -avz 10.0.0.51:/usr/local/bin/redis-* /usr/local/bin
rsync -avz 10.0.0.51:/usr/lib/systemd/system/redis.service /usr/lib/systemd/system/
mkdir /opt/redis_6379/{conf,logs,pid} -p
mkdir /data/redis_6379 -p
cat >/opt/redis_6379/conf/redis_6379.conf <<EOF
daemonize yes
bind 127.0.0.1 $(ifconfig eth0|awk 'NR==2{print $2}')
port 6379
pidfile "/opt/redis_6379/pid/redis_6379.pid"
logfile "/opt/redis_6379/logs/redis_6379.log"
dbfilename "redis.rdb"
dir "/data/redis_6379"
appendonly yes
appendfilename "redis.aof"
appendfsync everysec
EOF
useradd redis -M -s /sbin/nologin
chown -R redis:redis /opt/redis*
chown -R redis:redis /data/redis*
systemctl daemon-reload
systemctl start redis
redis-cli
```javascript
## 4.配置主从复制
```javascript
redis-cli -h 10.0.0.52 slaveof 10.0.0.51 6379
redis-cli -h 10.0.0.53 slaveof 10.0.0.51 6379
redis-cli -h 10.0.0.51 info replication
5.部署哨兵节点-3台机器都操作
mkdir -p /data/redis_26379
mkdir -p /opt/redis_26379/{conf,pid,logs}
cat >/opt/redis_26379/conf/redis_26379.conf << EOF
bind $(ifconfig eth0|awk 'NR==2{print $2}')
port 26379
daemonize yes
logfile /opt/redis_26379/logs/redis_26379.log
dir /data/redis_26379
sentinel monitor myredis 10.0.0.51 6379 2
sentinel down-after-milliseconds myredis 3000
sentinel parallel-syncs myredis 1
sentinel failover-timeout myredis 18000
EOF
chown -R redis:redis /data/redis*
chown -R redis:redis /opt/redis*
cat >/usr/lib/systemd/system/redis-sentinel.service<<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/redis-sentinel /opt/redis_26379/conf/redis_26379.conf --supervised systemd
ExecStop=/usr/local/bin/redis-cli -h $(ifconfig eth0|awk 'NR==2{print $2}') -p 26379 shutdown
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl start redis-sentinel
redis-cli -h $(ifconfig eth0|awk 'NR==2{print $2}') -p 26379
关键配置解释:
sentinel monitor myredis 10.0.0.51 6379 2
# myredis主节点别名 主节点IP 端口 需要2个哨兵节点同意
sentinel down-after-milliseconds myredis 3000
# 认定服务器已经断线所需要的毫秒数
sentinel parallel-syncs myredis 1
# 向主节点发给复制操作的从节点个数,1表示轮训发起复制
sentinel failover-timeout myredis 18000
# 故障转移超时时间
6.哨兵注意
1.哨兵发起故障转移的条件是master节点失去联系,从节点挂掉不会发起故障转移
2.哨兵会自己维护配置文件,不需要手动修改
3.如果主从的结构发生变化,哨兵之间会自动同步最新的消息并且自动更新配置文件
4.哨兵启动完成之后,以后不要再自己去设置主从关系
7.验证主机点
redis-cli -h 10.0.0.51 -p 26379 SENTINEL get-master-addr-by-name myredis
8.哨兵的常用命令
redis-cli -h 10.0.0.51 -p 26379 SENTINEL get-master-addr-by-name myredis
redis-cli -h 10.0.0.51 -p 26379 SENTINEL master myredis
redis-cli -h 10.0.0.51 -p 26379 SENTINEL slaves myredis
redis-cli -h 10.0.0.51 -p 26379 SENTINEL ckquorum myredis
9.模拟故障转移
模拟方法:
关闭redis当前的主节点
观察其他2个节点会不会发生选举
查看哨兵配置文件会不会更新
查看从节点配置文件会不会更新
查看主节点能不能写入
查看从节点是否同步正常
流程:
1)在从节点列表中选出一个节点作为新的主节点,选择方法如下:
a)过滤:“不健康”(主观下线、断线)、5秒内没有回复过Sentinel节点ping响应、与主节点失联超过down-after-milliseconds*10秒。
b)选择slave-priority(从节点优先级)最高的从节点列表,如果存在则返回,不存在则继续。
c)选择复制偏移量最大的从节点(复制的最完整),如果存在则返回,不存在则继续。
d)选择runid最小的从节点
结论:
主节点挂掉,哨兵会选举新的主节点
在新主节点上执行slaveof no one
在从节点执行slave of 新主节点
自动更新哨兵配置
自动更新从节点配置
10.故障修复重新上线
启动单节点
检查是否变成从库
11.哨兵加权选举
查看权重
redis-cli -h 10.0.0.51 -p 6379 CONFIG GET slave-priority
redis-cli -h 10.0.0.52 -p 6379 CONFIG GET slave-priority
redis-cli -h 10.0.0.53 -p 6379 CONFIG GET slave-priority
暗箱操作:假如选中53作为最新的master
redis-cli -h 10.0.0.51 -p 6379 CONFIG SET slave-priority 0
redis-cli -h 10.0.0.52 -p 6379 CONFIG SET slave-priority 0
检查:
redis-cli -h 10.0.0.51 -p 6379 CONFIG GET slave-priority
redis-cli -h 10.0.0.52 -p 6379 CONFIG GET slave-priority
redis-cli -h 10.0.0.51 -p 26379 sentinel get-master-addr-by-name myredis
主动发生选举
redis-cli -h 10.0.0.51 -p 26379 sentinel failover myredis
redis-cli -h 10.0.0.51 -p 26379 sentinel get-master-addr-by-name myredi
六、Redis cluster分布式集群
1.哨兵的不足
1.主库写压力太大
2.资源利用率不高
3.连接过程繁琐,效率低
2.集群的重要概念
1.Redis集群,无论有几个节点,一共只有16384个槽位
2.所有的槽都必须被正确分配,哪怕有1个槽不正常,整个集群都不可用
3.每个节点的槽的顺序不重要,重要的是槽的数量
4.HASH算法足够平均,足够随机
5.每个槽被分配到数据的概率是大致相当的
6.集群的高可用依赖于主从复制
7.集群节点之间槽位的数量允许在2%的误差范围内
8.集群通讯会使用基础端口号+10000的端口,自动创建的,不是配置文件配置的,生产要注意的是防火墙注意要放开此端口
3.目录规划
主节点 6380
从节点 6381
4.db01的操作
#1.发送SSH认证,方便后面传输
ssh-keygen
ssh-copy-id 10.0.0.52
ssh-copy-id 10.0.0.53
#2.创建目录
pkill redis
mkdir -p /opt/redis_{6380,6381}/{conf,logs,pid}
mkdir -p /data/redis_{6380,6381}
#3.生成主节点配置文件
cat >/opt/redis_6380/conf/redis_6380.conf<<EOF
bind 10.0.0.51
port 6380
daemonize yes
pidfile "/opt/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_6380/"
appendonly yes
appendfilename "redis.aof"
appendfsync everysec
cluster-enabled yes 激活集群模式
cluster-config-file nodes_6380.conf 整个集群的配置文件
cluster-node-timeout 15000 故障转移时间 毫秒
EOF
#4.复制主节点的配置文件到从节点并更改端口号
cd /opt/
cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.conf
#5.更改授权为redis
chown -R redis:redis /opt/redis_*
chown -R redis:redis /data/redis_*
#6.生成主节点的systemd启动文件
cat >/usr/lib/systemd/system/redis-master.service<<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/redis-server /opt/redis_6380/conf/redis_6380.conf --supervised systemd
ExecStop=/usr/local/bin/redis-cli -h $(ifconfig eth0|awk 'NR==2{print $2}') -p 6380 shutdown
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
#7.复制master节点的启动文件给slave节点并修改端口号
cd /usr/lib/systemd/system/
cp redis-master.service redis-slave.service
sed -i 's#6380#6381#g' redis-slave.service
#8.重载并启动集群节点
systemctl daemon-reload
systemctl start redis-master
systemctl start redis-slave
ps -ef|grep redis
#9.把创建好的目录和启动文件发送给db02和db03
rsync -avz /opt/redis_638* 10.0.0.52:/opt/
rsync -avz /opt/redis_638* 10.0.0.53:/opt/
rsync -avz /usr/lib/systemd/system/redis-*.service 10.0.0.52:/usr/lib/systemd/system/
rsync -avz /usr/lib/systemd/system/redis-*.service 10.0.0.53:/usr/lib/systemd/system/
5.db02的操作
#1.替换db01发送过来的文件并修改IP地址
pkill redis
find /opt/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#52#g"
cd /usr/lib/systemd/system/
sed -i 's#51#52#g' redis-*.service
mkdir –p /data/redis_{6380,6381}
chown -R redis:redis /opt/redis_*
chown -R redis:redis /data/redis_*
systemctl daemon-reload
systemctl start redis-master
systemctl start redis-slave
ps -ef|grep redis
6.db03的操作
#1.替换db01发送过来的文件并修改IP地址
pkill redis
find /opt/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#53#g"
cd /usr/lib/systemd/system/
sed -i 's#51#53#g' redis-*.service
mkdir –p /data/redis_{6380,6381}
chown -R redis:redis /opt/redis_*
chown -R redis:redis /data/redis_*
systemctl daemon-reload
systemctl start redis-master
systemctl start redis-slave
ps -ef|grep redis
7.集群手动发现节点
CLUSTER NODES 查看集群成员信息
CLUSTER MEET IP PORT 发现节点
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.52 6380
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.53 6380
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.51 6381
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.52 6381
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.53 6381
redis-cli -h 10.0.0.51 -p 6380 CLUSTER NODES
8.集群手动分配槽位
1.槽位规划
db01:6380 5461 0-5460
db02:6380 5461 5461-10921
db03:6380 5462 10922-16383
2.分配槽位
redis-cli -h 10.0.0.51 -p 6380 CLUSTER ADDSLOTS {0..5460}
redis-cli -h 10.0.0.52 -p 6380 CLUSTER ADDSLOTS {5461..10921}
redis-cli -h 10.0.0.53 -p 6380 CLUSTER ADDSLOTS {10922..16383}
3.查看集群状态
redis-cli -h 10.0.0.51 -p 6380 CLUSTER NODES
redis-cli -h 10.0.0.51 -p 6380 CLUSTER INFO
9.手动分配复制关系
1.先获取集群节点信息
redis-cli -h 10.0.0.52 -p 6381 CLUSTER nodes
2.过滤删除不必要的信息
11d9be84c0388081d310da6df15f421482c6274a 10.0.0.51:6380
424f4ed9df9fe7a361d740de4626d7759e27e147 10.0.0.52:6380
34ed08bbc77d1994a52a5173da477fd2e89ea427 10.0.0.53:6380
3.画图
4.配置复制关系
redis-cli -h 10.0.0.51 -p 6381 CLUSTER REPLICATE db02的6380的ID
(11d9be84c0388081d310da6df15f421482c6274a)
redis-cli -h 10.0.0.52 -p 6381 CLUSTER REPLICATE db03的6380的ID
(424f4ed9df9fe7a361d740de4626d7759e27e147)
redis-cli -h 10.0.0.53 -p 6381 CLUSTER REPLICATE db01的6380的ID
(34ed08bbc77d1994a52a5173da477fd2e89ea427)
5.检查复制关系
redis-cli -h 10.0.0.51 -p 6381 CLUSTER NODES
七、集群写入数据
1.尝试插入一条数据
[root@db01 ~]# redis-cli -h 10.0.0.51 -p 6380
10.0.0.51:6380> set k1 v1
(error) MOVED 12706 10.0.0.53:6380
[root@db01 ~]# redis-cli -c -h 10.0.0.51 -p 6380
10.0.0.51:6380>
10.0.0.51:6380> set k4 v4
-> Redirected to slot [8455] located at 10.0.0.52:6380
OK
10.0.0.52:6380> keys *
1) "k4"
10.0.0.52:6380> get k4
"v4"
2.目前的现象
1.在db01的6380上插入数据提示错误
2.报错提示应该移动到db03的6380上
3.根据提示在db03的6380上执行相同的命令可以写入成功
4.db01的6380有的数据可以写入,有的不行
5.使用-c参数后,可以正常写入命令,并且由目标节点返回信息
3.问题原因
因为集群模式有ASK规则,加入-c参数后,会自动跳转到目标节点处理并由目标节点返回信息。
4.ASK路由流程图
八、验证集群hash算法是否足够随机足够平均
1.写入测试命令
for i in {1..1000};do redis-cli -c -h 10.0.0.51 -p 6380 set k_${i} v_${i} && echo "${i} is ok";done
2.验证足够平均
[root@db01 ~]# redis-cli -c -h 10.0.0.51 -p 6380 DBSIZE
(integer) 339
[root@db01 ~]# redis-cli -c -h 10.0.0.52 -p 6380 DBSIZE
(integer) 326
[root@db01 ~]# redis-cli -c -h 10.0.0.53 -p 6380 DBSIZE
(integer) 335
3.验证足够随机
redis-cli -c -h 10.0.0.51 -p 6380 keys \* > keys.txt
cat keys.txt |awk -F "_" '{print $2}'|sort -rn
4.允许节点的槽个数误差在2%以内的依据
[root@db01 ~]# redis-cli --cluster rebalance 10.0.0.51:6380
>>> Performing Cluster Check (using node 10.0.0.51:6380)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
*** No rebalancing needed! All nodes are within the 2.00% threshold.
5.检查集群健康状态
[root@db01 ~]# redis-cli --cluster info 10.0.0.51:6380
10.0.0.51:6380 (f765d849...) -> 3343 keys | 5461 slots | 1 slaves.
10.0.0.52:6380 (5ff2b711...) -> 3314 keys | 5461 slots | 1 slaves.
10.0.0.53:6380 (de167d13...) -> 3343 keys | 5462 slots | 1 slaves.
[OK] 10000 keys in 3 masters.
0.61 keys per slot on average.
九、使用工具自动部署redis集群-通用ruby法
1.安装依赖-只要在db01上操作
yum install -y rubygems
gem sources -a http://mirrors.aliyun.com/rubygems/
gem sources --remove http://rubygems.org/
gem install redis -v 3.3.3
2.还原集群环境
redis-cli -c -h 10.0.0.51 -p 6380 flushall
redis-cli -c -h 10.0.0.52 -p 6380 flushall
redis-cli -c -h 10.0.0.53 -p 6380 flushall
redis-cli -h 10.0.0.51 -p 6380 CLUSTER RESET
redis-cli -h 10.0.0.52 -p 6380 CLUSTER RESET
redis-cli -h 10.0.0.53 -p 6380 CLUSTER RESET
redis-cli -h 10.0.0.51 -p 6381 CLUSTER RESET
redis-cli -h 10.0.0.52 -p 6381 CLUSTER RESET
redis-cli -h 10.0.0.53 -p 6381 CLUSTER RESET
3.快速部署Redis集群
cd /opt/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:6381 10.0.0.52:6381 10.0.0.53:6381
十、使用工具自动部署redis集群-高科技版
1.还原集群状态
redis-cli -c -h 10.0.0.51 -p 6380 flushall
redis-cli -c -h 10.0.0.52 -p 6380 flushall
redis-cli -c -h 10.0.0.53 -p 6380 flushall
redis-cli -h 10.0.0.51 -p 6380 CLUSTER RESET
redis-cli -h 10.0.0.52 -p 6380 CLUSTER RESET
redis-cli -h 10.0.0.53 -p 6380 CLUSTER RESET
redis-cli -h 10.0.0.51 -p 6381 CLUSTER RESET
redis-cli -h 10.0.0.52 -p 6381 CLUSTER RESET
redis-cli -h 10.0.0.53 -p 6381 CLUSTER RESET
2.快速部署Redis集群
redis-cli --cluster create 10.0.0.51:6380 10.0.0.52:6380 10.0.0.53:6380 10.0.0.51:6381 10.0.0.52:6381 10.0.0.53:6381 --cluster-replicas 1
3.检查集群
redis-cli --cluster info 10.0.0.51:6380
十一、 使用工具扩容
1.需要考虑的问题
1.迁移时槽的数据会不会迁过去
2.迁移过程集群读写受影响吗
3.需要限速吗
4.如何确保迁移后的完整性
2.如何设计实验验证迁移过程是否受影响
1.迁移过程中,一个窗口读数据,一个窗口写数据
2.观察是否会中断
3.创建新节点
mkdir -p /opt/redis_{6390,6391}/{conf,logs,pid}
mkdir -p /data/redis_{6390,6391}
cd /opt/
cp redis_6380/conf/redis_6380.conf redis_6390/conf/redis_6390.conf
cp redis_6380/conf/redis_6380.conf redis_6391/conf/redis_6391.conf
sed -i 's#6380#6390#g' redis_6390/conf/redis_6390.conf
sed -i 's#6380#6391#g' redis_6391/conf/redis_6391.conf
redis-server /opt/redis_6390/conf/redis_6390.conf
redis-server /opt/redis_6391/conf/redis_6391.conf
ps -ef|grep redis
redis-cli -c -h 10.0.0.51 -p 6380 cluster meet 10.0.0.51 6390
redis-cli -c -h 10.0.0.51 -p 6380 cluster meet 10.0.0.51 6391
redis-cli -c -h 10.0.0.51 -p 6380 cluster nodes
4.扩容步骤
#重新分配槽位
redis-cli --cluster reshard 10.0.0.51:6380
#第一次交互:每个节点最终分配多少个槽
How many slots do you want to move (from 1 to 16384)? 4096
#第二次交互:接受节点的ID
What is the receiving node ID? 6390的ID
#第三次交互:哪些节点需要导出
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:all
#第四次交互:确认信息
Do you want to proceed with the proposed reshard plan (yes/no)? yes
5.验证命令
写命令
for i in {1..1000};do redis-cli -c -h 10.0.0.51 -p 6380 set k_${i} v_${i} && echo ${i} is ok;sleep 0.5;done
读命令
for i in {1..1000};do redis-cli -c -h 10.0.0.51 -p 6380 get k_${i};sleep 0.5;done
十 二、 使用工具收缩
1.缩容命令
#重新分配槽
redis-cli --cluster reshard 10.0.0.51:6380
#第一次交互:需要迁移多少个槽
How many slots do you want to move (from 1 to 16384)? 1365
#第三次交互:接受节点ID是多少
What is the receiving node ID? db01的6380的ID
#第三次交互:哪些节点需要导出
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: 6390的ID
Source node #2: done
#第四次交互:确认信息
Do you want to proceed with the proposed reshard plan (yes/no)? yes
重复上述操作,知道6390所有的槽都被分配完毕
2.检查命令
redis-cli --cluster info 10.0.0.51:6380
3.删除槽位
redis-cli --cluster del-node 10.0.0.51:6380 NodeID
4.归一再分配法
归一
把要缩容节点的数据都扔到其中一个节点
分配
然后利用集群重新负载均衡命令重新分配
redis-cli --cluster rebalance 10.0.0.51:6380
十三、模拟故障转移
1.关闭主节点,测试集群是否依然可用
10.0.0.51:6381> CLUSTER NODES
f765d849975ddfda7029d16be717ddffcc4c4bc7 10.0.0.51:6380@16380 slave 2a55b4454e33b3c5a953264c9d69a58a56ab1a85 0 1587000834939 20 connected
5ff2b711ff5b377bf06ce5ef878b3a7aaf881a98 10.0.0.52:6380@16380 slave 7d1328883b4a162d2728f8719fffc53d5fb3d801 0 1587000838082 22 connected
de167d131d45eedcb9b56ef0021ae110d6e55d46 10.0.0.53:6380@16380 slave aef2cbf60bc3109ba76253d52d691e2dba7bd3e5 0 1587000837000 21 connected
aef2cbf60bc3109ba76253d52d691e2dba7bd3e5 10.0.0.51:6381@16381 myself,master - 0 1587000837000 21 connected 10923-16383
2a55b4454e33b3c5a953264c9d69a58a56ab1a85 10.0.0.52:6381@16381 master - 0 1587000837000 20 connected 0-5460
7d1328883b4a162d2728f8719fffc53d5fb3d801 10.0.0.53:6381@16381 master - 0 1587000837070 22 connected 5461-10922
2.主动发起故障转移
redis-cli -c -h 10.0.0.51 -p 6380 CLUSTER FAILOVER
redis-cli -c -h 10.0.0.52 -p 6380 CLUSTER FAILOVER
redis-cli -c -h 10.0.0.53 -p 6380 CLUSTER FAILOVER
十四、 迁移过程意外中断如何修复
1.模拟场景:迁移时人为中断,导致槽的状态不对
[5754->-f765d849975ddfda7029d16be717ddffcc4c4bc7]
2.手动修复
redis-cli -c -h 10.0.0.52 -p 6380 CLUSTER SETSLOT 5754 STABLE
3.使用工具修复-生产建议使用工具修复
redis-cli --cluster fix 10.0.0.51:6380
十五 RedisCluster常用命令整理
1.集群(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 将节点的配置文件保存到硬盘里面。
2.槽(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)。
3.键 (key)
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。
十六、 ansible自动化部署
1.ansible部署redis集群5.x
目录结构
redis_cluster/
├── files
│ ├── redis_6380
│ │ ├── conf
│ │ ├── logs
│ │ └── pid
│ ├── redis_6381
│ │ ├── conf
│ │ ├── logs
│ │ └── pid
│ └── redis_cmd
│ ├── redis-benchmark
│ ├── redis-check-aof
│ ├── redis-check-rdb
│ ├── redis-cli
│ └── redis-server
├── handlers
│ └── main.yaml
├── tasks
│ └── main.yaml
└── templates
├── redis_6380.conf.j2
├── redis_6381.conf.j2
├── redis-master.service.j2
└── redis-slave.service.j2
调用文件
cat >/etc/ansible/redis_cluster.yaml <<EOF
- hosts: redis_cluster
roles:
- redis_cluster
EOF
tasks内容:
cat >>/etc/ansible/roles/redis_cluster/tasks/main.yaml <<EOF
#01.创建用户组
- name: 01_create_group
group:
name: redis
gid: 777
#02.创建用户
- name: 02_create_user
user:
name: redis
uid: 777
group: redis
shell: /sbin/nologin
create_home: no
#03.拷贝执行文件
- name: 03_copy_cmd
copy:
src: redis_cmd/
dest: /usr/local/bin/
mode: '0755'
#04.拷贝运行目录
- name: 04_mkdir_conf
copy:
src: "{{ item }}"
dest: /opt/
owner: redis
group: redis
loop:
- redis_6380
- redis_6381
#05.创建数据目录
- name: 05_mkdir_data
file:
dest: "/data/{{ item }}"
state: directory
owner: redis
group: redis
loop:
- redis_6380
- redis_6381
#06.拷贝配置文件模版
- name: 06_copy_conf
template:
src: "{{ item.src}}"
dest: "{{ item.dest }}"
backup: yes
loop:
- { src: 'redis_6380.conf.j2', dest: '/opt/redis_6380/conf/redis_6380.conf' }
- { src: 'redis_6381.conf.j2', dest: '/opt/redis_6381/conf/redis_6381.conf' }
- { src: 'redis-master.service.j2', dest: '/usr/lib/systemd/system/redis-master.service' }
- { src: 'redis-slave.service.j2', dest: '/usr/lib/systemd/system/redis-slave.service' }
notify:
- restart redis-master
- restart redis-slave
#07.启动服务
- name: 07_start_redis
systemd:
name: "{{ item }}"
state: started
daemon_reload: yes
loop:
- redis-master
- redis-slave
EOF
handlers
[root@m01 ~]# cat /etc/ansible/roles/redis_cluster/handlers/main.yaml
- name: restart redis-master
service:
name: redis-master
state: restarted
- name: restart redis-slave
service:
name: redis-slave
state: restarted
templates
cat >/etc/ansible/roles/redis_cluster/templates/redis_6380.conf.j2 <<EOF
bind {{ ansible_facts.eth0.ipv4.address }}
port 6380
daemonize yes
pidfile "/opt/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_6380/"
appendonly yes
appendfilename "redis.aof"
appendfsync everysec
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
EOF
cat >/etc/ansible/roles/redis_cluster/templates/redis-master.service.j2 <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/redis-server /opt/redis_6380/conf/redis_6380.conf --supervised systemd
ExecStop=/usr/local/bin/redis-cli -h {{ ansible_facts.eth0.ipv4.address }} -p 6380 shutdown
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
2.免交互初始化集群
echo "yes"|redis-cli --cluster create 10.0.0.51:6380 10.0.0.52:6380 10.0.0.53:6380 10.0.0.51:6381 10.0.0.52:6381 10.0.0.53:6381 --cluster-replicas 1
3.免交互扩容
添加主节点
redis-cli --cluster add-node 10.0.0.51:6390 10.0.0.51:6380
添加从节点
redis-cli --cluster add-node 10.0.0.51:6391 10.0.0.51:6380 --cluster-slave --cluster-master-id $(redis-cli -c -h 10.0.0.51 -p 6380 cluster nodes|awk '/51:6390/{print $1}')
重新分配槽
redis-cli --cluster reshard 10.0.0.51:6380 --cluster-from all --cluster-to $(redis-cli -c -h 10.0.0.51 -p 6380 cluster nodes|awk '/51:6390/{print $1}') --cluster-slots 4096 --cluster-yes
4.免交互收缩
迁移槽
redis-cli --cluster rebalance 10.0.0.51:6380 --cluster-weight $(redis-cli -c -h 10.0.0.51 -p 6390 cluster nodes|awk '/51:6390/{print $1}')=0
下线节点
redis-cli --cluster del-node 10.0.0.51:6391 $(redis-cli -c -h 10.0.0.51 -p 6380 cluster nodes|awk '/51:6391/{print $1}')
redis-cli --cluster del-node 10.0.0.51:6390 $(redis-cli -c -h 10.0.0.51 -p 6380 cluster nodes|awk '/51:6390/{print $1}')