redis高可用
高可用
在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)
但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展、数据安全不会丢失等
在Redis中,实现高可用的技术主要包括持久化、主从复制、哨兵和集群、集群
持久化
持久化:是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份**,即将数据存储在硬盘,保证数据不会因进程退出而丢失
主从复制
主从复制:主从复制是高可用redis基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。
缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制(吃资源)
哨兵
哨兵:在主从复制的基础上,哨兵实现了自动化的故障恢复。
缺陷:写操作无法负载均衡;存储能力受到单机的限制。
集群
集群:通过集群,redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案
关于持久化
持久化的功能:redis是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致redis进程异常退出后数据的永久丢失,需要定期将redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次redis重启时,利用持久化文件实现数据恢复,除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置
redis 提供两种方式进行持久化
ROB持久化:原理是将redis在内存中的数据库记录定时保存到硬盘上
AOF持久化(append only file):原理是将redis的操作日志以追加的方式写入文件,类似于MySQL的binlog.
由于AOF持久化的实时性更好,即当进程意外退出时,丢失的数据更少,因此AOF是目前的主流持久化方案,,RDB基本也都会开启用于集群。
ROB持久化
ROB持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是rdb;当redis重新启动时,可以读取快照文件复数据。
周期性 1—10秒(会进行一定的限制,周期过于短暂会导致数据冗余)
保存形式为二进制 .rdb
可用于恢复。redis重启后缓存里的数据会清空,此时redis中的数据就是基于.rdb文件回复的。
触发条件
RDB持久化的触发分为手动触发和自动触发两种
手动触发
save命令和bgsave命令都可以生产RDB文件
但是save命令会阻塞redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求
而bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即redis主进程)则继续处理请求
bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用。
自动触发
在自动触发ROB持久化时,redis也会选择bgsave而不是save来进行持久化
自动触发最常见的情况是在配置文件中通过save m n,指定当m秒内发生n次变化时,会触发bgsave。
满足以下任一条件时,都会调用bgsave
其他自定触发机制
除了save m n以外,还有一些其他情况会触发bgsave:
在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点
执行shutdown命令时,自动执行rdb持久化
执行流程
Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof的子进程,如果在执行则bgsave命令直接返回。bgsave/bgrewriteaof的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题
父进程执行fork操作创建 子进程,这个过程中父进程是阻塞的,redis不能执行来自客户端的任何命令
父进程fork后,bgsave命令返回“background saving started” 信息并不再阻塞父进程,并可以响应其他命令
子进程创建ROB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
子进程发送信息给父进程表示完成,父进程更新统计信息。
启动时加载
ROB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AOF的优先级更高,因此当AOF开启时,redis会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会在redis服务器启动时检测RDB文件,并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止
Redis载入RDB文件时,会对RDB文件进行校验,如果文件损坏,则日志中会打印错误,redis启动失败。
AOF 持久化
ROB持久化是将进程数据写入文件,而AOF持久化,则是将redis执行的每次写,删除命令记录到单独的日志文件中,查询操作不会记录;当redis重启时再次执行AOF文件中的命令来恢复数据。与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。
//
[root@localhost ~]# /etc/init.d/redis_6379 restart
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
执行流程
命令追加:将Redis的写命令追加到缓冲区aof_buf
文件写入和文件同步:根据不同的同步策略将aof_buf的内容同步到硬盘
文件重写:定期重写AOF文件,以达到压缩的目的
RDB和AOF的优缺点
RDB持久化
优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多,当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
缺点:数据快照的持久化方式决定了必然做不到实时持久化,而数据越来越重要的今天,数据的流失是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要特定格式,兼容性差。对于RDB持久化,一方面是bgsave在进行fork操作时redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力
AOF持久化
优点:支持秒级持久化、兼容性好,
缺点:文件大、恢复速度慢、对性能影响大
主从复制
//
master 192.168.142.143
slave1 192.168.142.144
slave2 192.168.142.145
三台一安装好redis的服务器
修改配置文件
master
//
[root@master ~]# vim /etc/redis/6379.conf
70 bind 0.0.0.0 /修改bind项,使之监听所有网段
137 daemonize yes /开启守护进程
172 logfile /var/log/redis_6379.log /指定日志文件目录
264 dir /var/lib/redis/6379 /指定工作目录
700 appendonly yes /开启AOF持久化功能
[root@master utils]# /etc/init.d/redis_6379 restart /重启redis
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
slaver
//
[root@slave1 ~]# vim /etc/redis/6379.conf
70 bind 0.0.0.0 /修改bind项,使之监听所有网段
137 daemonize yes /开启守护进程
172 logfile /var/log/redis_6379.log /指定日志文件目录
264 dir /var/lib/redis/6379 /指定工作目录
288 replicaof 192.168.142.143 6379 /指定同步的master节点和端口
700 appendonly yes /开启AOF持久化功能
[root@slave1 utils]# /etc/init.d/redis_6379 restart /修改完成配置文件重启服务
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
验证
验证从节点
哨兵模式
原理
是一个分布式系统,用于对从服务器的监控,当出现故障时用过头机票机制重新选择新的master,并将所有slaver连接到新的master。 所以整个运行了哨兵的集群数量不少于3太.
作用
监控:哨兵会不断检查主节点和从节点是否正常运行
自动故障转移:当主节点不能正常工作时,哨兵会自动移除故障,讲失效的主节点的从节点升级为主节点,并让其他从节点改为复制新的主节点
故障通知:哨兵可以将故障转移的结果发送给客户端
结构
搭建哨兵
所有节点修改配置文件,master为例
//
[root@master ~]# cd /opt/redis-5.0.7
[root@master ~]# vim sentinel.conf
17 protected-mode no //关闭保护模式
21 port 26379 //默认端口
26 daemonize yes //开启守护进程
36 logfile "/var/log/sentinel.log" //指定日志位置
65 dir /var/lib/redis/6379 //指定工作目录
84 sentinel monitor mymaster 192.168.142.143 6379 2 //至少两个哨兵同意才能进行故障转移
113 sentinel down-after-milliseconds mymaster 30000 //判断节点down掉的时间周期,默认30s
146 sentinel failover-timeout mymaster 180000 //最大超时时间,默认180s
启动哨兵模式,先主后从
查看哨兵信息
模拟故障
杀死master上的redis进程
//
[root@master redis-5.0.7]# kill -9 43413
验证
//
[root@master redis-5.0.7]# tail -f /var/log/sentinel.log
Cluster集群
集群由多个node节点组成,redis的数据分布在这些节点中,集群中的节点分为主机点和从节点。只有主节点负责读写请求和集群信息的维护,从节点只进行主节点数据和状态信息的复制。
集群的作用
数据分区:也叫做数据分片。是集群最核心的功能。集群将数据分散多个节点,一方面突出redis单机内存大小的限制,储存容量大大增加。另一方面,每个主节点都可以对外提供读写服务,大大提高集群响应能力。
高可用:集群支持主从和主节点的自动故障转移(与哨兵类似),当任意节点发生故障时,集群人可以对外提供服务。
搭建redis集群
redis的集群一般需要6个节点,3主3从。方便起见,这里所有节点在6台服务器上模拟:
以IP及端口号进行区分:3个主节点端口号:7001、7003、7005,对应的从节点端口号:7002、7004、7006。
//
Master1 CentOS7 192.168.142.143:7001 redis-5.0.7.tar.gz
Slave1 CentOS7 192.168.142.144:7002 redis-5.0.7.tar.gz
Master2 CentOS7 192.168.142.145:7003 redis-5.0.7.tar.gz
Slave2 CentOS7 192.168.142.146:7004 redis-5.0.7.tar.gz
Master3 CentOS7 192.168.142.147:7005 redis-5.0.7.tar.gz
Slave3 CentOS7 192.168.142.148:7006 redis-5.0.7.tar.gz
6台机器都需要安装redis,略过安装步骤。
所有节点创建目录
//
[root@master ~]# cd /etc/redis/
[root@master ~]# mkdir -p redis-cluster/redis6379
[root@master ~]# cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis6379/
[root@master ~]# cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis6379/
修改master1节点配置
//
[root@master redis]# cd /etc/redis/redis-cluster/redis6379
[root@master redis6379]# vim redis.conf
69 bind 192.168.142.142 /修改bind项,监听自己的ip
88 protected-mode no /关闭保护模式
92 port 7001 /修改监听端口为7007,每台都需要不一样
136 daemonize yes /打开以独立进程启动
699 appendonly yes /打开A0F持久化
832 cluster-enabled yes /取消注释,开启集群功能
840 cluster-config-file nodes-6379.conf /取消注释,打开集群名称文件
846 cluster-node-timeout 15000 /取消注释,集群超时时间设置
在master1节点上传并覆盖
//
scp /etc/redis/redis-cluster/redis6379/redis.conf root@192.168.142.143:/etc/redis/redis-cluster/redis6379/redis.conf
scp /etc/redis/redis-cluster/redis6379/redis.conf root@192.168.142.144:/etc/redis/redis-cluster/redis6379/redis.conf
scp /etc/redis/redis-cluster/redis6379/redis.conf root@192.168.142.145:/etc/redis/redis-cluster/redis6379/redis.conf
scp /etc/redis/redis-cluster/redis6379/redis.conf root@192.168.142.146:/etc/redis/redis-cluster/redis6379/redis.conf
scp /etc/redis/redis-cluster/redis6379/redis.conf root@192.168.142.147:/etc/redis/redis-cluster/redis6379/redis.conf
## 在master节点上使用scp上传到其他服务器,并覆盖其它5台服务器的配置文件
其他节点修改配置文件
//
[root@slave1 redis]# vim /etc/redis/redis-cluster/redis6379/redis.conf
69 bind 192.168.142.143 /其他的节点修改监听自己的ip
92 port 7002 /监听端口设置自定义,不需要一样就可以了
启动所有redis
//
[root@master redis6379]# cd /etc/redis/redis-cluster/redis6379 /切换到此目录
[root@master redis6379]# redis-server redis.conf /启动redis节点
15854:C 12 Aug 2021 19:32:21.141 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
15854:C 12 Aug 2021 19:32:21.141 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=15854, just started
15854:C 12 Aug 2021 19:32:21.141 # Configuration loaded
启动集群
//
redis-cli --cluster create 192.168.142.142:7001 192.168.142.144:7003 192.168.142.146:7005 192.168.142.143:7002 192.168.142.145:7004 192.168.142.147:7006 --cluster-replicas 1
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 370c0e26c898d9fa13b4c471b0e6259dfadec731 192.168.142.142:7001
slots:[0-5460] (5461 slots) master
M: dbd8e38b6c8d48f25cc8331624627e7411a43d15 192.168.142.144:7003
slots:[5461-10922] (5462 slots) master
M: 331ee4d7369d949fdef5970be4f0233fa0313efe 192.168.142.146:7005
slots:[10923-16383] (5461 slots) master
S: 2b1a0dd61a2e2a275429b2ec818e95654c29acd8 192.168.142.143:7002
replicates dbd8e38b6c8d48f25cc8331624627e7411a43d15
S: dd86a642078a74f5ebb7f0bb452455e418c5b160 192.168.142.145:7004
replicates 331ee4d7369d949fdef5970be4f0233fa0313efe
S: 822219d31b1248348f223406da72ef69537f4cc4 192.168.142.147:7006
replicates 370c0e26c898d9fa13b4c471b0e6259dfadec731
Can I set the above configuration? (type 'yes' to accept): yes
## 输入yes
进库查看
//
redis-cli -h 192.168.184.10 -p 7001 -c
192.168.142.142:7001> cluster slots //查看节点的哈希槽编号范围
1) 1) (integer) 10923
2) (integer) 16383 //哈希槽编号范围
3) 1) "192.168.142.146"
2) (integer) 7005 //主节点IP和端口号
3) "370c0e26c898d9fa13b4c471b0e6259dfadec731"
4) 1) "192.168.142.147"
2) (integer) 7006 //从节点IP和端口号
3) "822219d31b1248348f223406da72ef69537f4cc4"
2) 1) (integer) 5461
2) (integer) 10922
3) 1) "192.168.142.144"
2) (integer) 7003
3) "dbd8e38b6c8d48f25cc8331624627e7411a43d15"
4) 1) "192.168.142.143"
2) (integer) 7002
3) "2b1a0dd61a2e2a275429b2ec818e95654c29acd8"
3) 1) (integer) 0
2) (integer) 5460
3) 1) "192.168.142.142"
2) (integer) 7001
3) "331ee4d7369d949fdef5970be4f0233fa0313efe"
4) 1) "192.168.142.145"
2) (integer) 7004
3) "dd86a642078a74f5ebb7f0bb452455e418c5b160"
192.168.142.142:7001> set test 123
-> Redirected to slot [14646] located at 192.168.142.146:7005
OK
192.168.142.146:7005> cluster keyslot test //查看test键的槽编号
(integer) 14646
进入该范围值服务器内查看结果
//
[root@slave3 ~]# redis-cli -h 192.168.142.147 -p 7006
192.168.142.147:7006> key *
1) "sky"
192.168.142.147:7006> get test
-> redirected to slot [14646] located at 192.168.142.146:7005
"123"