Redis 高可用 持久化、主从复制、哨兵、cluster集群

336 阅读16分钟

一、高可用

在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。

但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务( 如主从分离、快速容灾技术),还需要考虑数据容量的扩展、数据安全不会丢失等。

Redis的高可用技术

在Redis中,实现高可用的技术主要包括持久化、主从复制、哨兵和cluster集群,下面分别说明它们的作用,以及解决了什么样的问题。

  • 持久化: 持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。

  • 主从复制: 主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份(和同步),以及对于读操作的负载均衡和简单的故障恢复。

    • 缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
  • 哨兵: 在主从复制的基础上,哨兵实现了自动化的故障恢复。(主挂了,找一个从成为新的主,哨兵节点进行监控)

    • 缺陷:写操作无法负载均衡;存储能力受到单机的限制。
  • Cluster集群: 通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。(6台起步,成双成对,3主3从)

二、持久化

1、持久化的功能

持久化的功能: Redis是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致Redis进程异常退出后数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

灾难备份:一般做异地备份,发生灾难后切换节点。例如本来使用上海的数据库,现在使用切换到重庆的。

2、Redis提供两种方式进行持久化:

  • RDB持久化:原理是将Reids在内存中的数据库记录定时保存到磁盘上。(定时对内存中的数据生成快照,以文件形式保存在硬盘中)
  • AOF持久化(append only file):原理是将Reids 的操作日志以追加的方式写入文件,类似于MySQL的binlog。(类似于Mysql的二进制日志)(以追加的方式将写和删的操作命令记录到AOF文件中)

RDB持久化的优缺点

优点:

RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比, RDB最重要的优点之一是对性能的影响相对较小。

(体积小,恢复速度更快,对性能影响较小。)

缺点:

  • RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。
  • 此外,RDB文 件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。
  • 对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力。

AOF持久化的优缺点

  • 与RDB持久化相对应,AOF的优点在于支持秒级持久化、实时性好、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。
  • 对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO 压力更大,甚至可能造成AOF追加阻塞问题。
  • AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的 IO 压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对Redis主进程性能的影响会更大。

3、RDB持久化

RDB持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据

RDB持久化的触发分为手动触发和自动触发两种。

手动触发

save命令和bgsave命令都可以生成RDB文件。

  • save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求。
  • 而bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即Redis主进程)则继续处理请求。
  • bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用。

自动触发

在自动触发RDB持久化时,Redis 也会选择bgsave而不是save来进行持久化。

自动触发最常见的情况是在配置文件中通过 save m n 指定当m秒内发生n次变化时,会触发bgsave。

 vim /etc/redis/6379.conf      #编辑配置文件
 
219行
 save 900 1      #当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
 save 300 10     #当时间到300秒时,如果redis数据发生了至少10次变化,则执行bgsave
 save 60 10000   #当时间到60秒时,如果redis数据发生了至少10000次变化, 则执行bgsave
##以下三个save条件满足任意一一个时,都会引起bgsave的调用
​
242行   rdbcompression yes     ##是否开启RDB文件压缩
 
 
254行  dbfilename dump.rdb      ##指定RDB文件名
​
264行  dir /var/lib/redis/6379     ##指定RDB文件和AOF文件所在目录

bgsave执行流程

(1)Redis父进程首先判断:当前是否在执行save,或 bgsave/ bgrewriteaof 的子进程,如果在执行则bgsave命令直接返回。

  • bgsave/bgrewriteaof 的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题。

(2)父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令。

(3)父进程fork后,bgsave 命令返回"Background saving started" 信息并不再阻塞父进程,并可以响应其他命令。

(4)子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换。(原子替换:文件整体替换,要么都发生,要么都不发生)

(5)子进程发送信号给父进程表示完成,父进程更新统计信息。

4、AOF持久化

RDB持久化是将进程数据写入文件,而AOF持久化,则是将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录。

当Redis重启时再次执行AOF文件中的命令来恢复数据。(重放命令进行恢复)

与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。

开启AOF

Redis服务器默认开启RDB,关闭AOF的, 要开启AOF,需要在/etc/redis/6379.conf配置文件中配置。

 vim /etc/redis/6379.conf
700行   appendonly yes      ##修改,开启AOF
704行   appendfilename "appendonly.aof"     ##指定AOF文件名称
796行   aof-load-truncated yes    ##是否忽略最后一条可能存在问题的指令
​
 /etc/init.d/redis_6379 restart    #重启redis
 ls /var/lib/redis/6379/      #查看是否生成了aof文件

三、Redis主从复制

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。

主从复制的流程

(1)若启动一个slave机器进程,则它会向Master机器发送一个sync command命令,请求同步连接。

(2)无论是第一次连接还是重新连接,Master机器都会启动一个后台进程,将数据快照保存到数据文件中(执行rdb操作),同时Master还会记录修改数据的所有命令并缓存在数据文件中.

(3)后台进程完成缓存操作之后,Master机器就会向slave机器发送数据文件,slave端机器将数据文件保存到硬盘上,然后将其加载到内存中,接着Master机器就会将修改数据的所有操作一并发送给slave端机器。若slave出现故障导致宕机,则恢复正常后会自动重新连接。

(4)Master机器收到slave端机器的连接后,将其完整的数据文件发送给slave端机器,如果Mater同时收到多个slave发来的同步请求,则Master会在后台启动一个进程以保存数据文件,然后将其发送给所有的slave端机器,确保所有的slave端机器都正常。

主从复制实验

master 192.168.37.101

slave1 192.168.37.133

slave2 192.168.37.135

1、修改Redis配置文件

>>>>>>   master 节点:
​
vim /etc/ redis/ 6379. conf
70 bind 0.0.0.0     ##修改监听地址为0.0.0.0
137 daemonize yes       ##开启守护进程
172 logfile /var/log/redis_6379.log     ##指定日志文件目录
264 dir /var/lib/redis/6379     ##指定工作目录
700 appendonly yes      ##开启AOF持久化功能
/etc/init.d/redis_6379 restart  ##重启服务使配置生效
-------------------->Slave节点<-----------------------------
vim /etc/redis/6379.conf
70 bind 0.0.0.0         ##修改监听地址为0.0.0.0
137 daemonize yes       ##开启守护进程
172 logfile/var/log/redis_6379.log
264 dir /var/lib/redis/6379     ##指定工作目录
288 replicaof 192.168.35.40 6379        ##添加一条指定要同步的Master节点IP和端口
700 appendonly yes      ##开启AOF持久化功能
/etc/init.d/redis_6379 restart  ##重启服务使使配置生效

2、验证主从效果

#主节点查看日志
tail /var/log/redis_6379.log 
#主节点插入一条数据
[root@ziyu utils]# redis-cli
127.0.0.1:6379> set name 1122
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name
"1122"#从节点查看是否同步成功
[root@momo utils]# redis-cli     #slave1查看数据同步成功  
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name
"1122"
•
[root@mina utils]# redis-cli     #slave2查看数据同步成功  
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name
"1122"

四、Redis哨兵模式

主从切换技术的方法是:当服务器宕机后,需要手动一台从机切换为主机,这需要人工干预,不仅费时费力而且还会造成一段时间内服务不可用。为了解决主从复制的缺点,就有了哨兵机制。

作用

  • 监控: 哨兵会不断地检查主节点和从节点是否运作正常。
  • 自动故障转移: 当主节点不能正常工作时,哨兵会开始自动故障转移操,它会将失效主节点的其中一个从节点升级为新的主节点,并让其它从节点改为复制新的主节点。
  • 通知(提醒): 哨兵可以将故障转移的结果发送给客户端。

故障转移机制

1、由哨兵节点定期监控发现主节点是否出现了故障

每个哨兵节点每隔1秒会问主节点、从节点及其它哨兵节点发送一次ping命令做一次心检测。如果主节点在一定时间范围内不回复或者是回复一个错误消息,那么这个哨兵就会认为这个主节点主观下线了(单方面的)。当超过半数哨兵节点认为该主节点主观下线了,这样就客观下线了。

2、当主节点出现故障,此时哨兵节点会通过Raft算法(选举算法)实现选举机制共同选举出一个哨兵节点为leader,来负责处理主节点的故障转移和通知。所以整个运行哨兵的集群的数量不得少于3个节点。

3、由leader哨兵节点执行故障转移,过程如下:

  • 将某一个从节点升级为新的主节点,让其它从节点指向新的主节点;
  • 若原主节点恢复也变成从节点,并指向新的主节点;
  • 通知客户端主节点已经更换。

主节点的选举

1.过滤掉不健康的(己下线的),没有回复哨兵ping响应的从节点。

2.选择配置文件中从节点优先级配置最高的。(replica-priority,默认值为100)

3.选择复制偏移量最大,也就是复制最完整的从节点。

配置实验

1、修改哨兵配置文件(三台都要)

vim /opt/redis-5.0.7/sentinel.conf
17 protected-mode no        ##关闭保护模式
21 port 26379       ##Redis哨兵默认的监听端口
26 daemonize yes        ##开启守护进程
36 logfile "/var/log/sentinel.log"      ##指定日志存放路径
65 dir /var/lib/redis/6379      ##指定数据库存放路径
84 sentinel monitor mymaster 192.168.35.40 6379 2   ##指定哨兵节点;2:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移
113 sentinel down-after-milliseconds mymaster 3000      ##判定服务器down掉的时间周期,默认30000毫秒 (30秒)
146 sentinel failover- timeout mymaster 180000      ##故障节点的最大超时时间为180000 (180秒)

2、启动哨兵模式(先主后从)

cd /opt/redis-5.0.7/
redis-sentinel sentinel.conf &      ##使用redis-sentinel启动,再使用sentinel.conf,&:放在在后台启动

3、查看哨兵信息

redis-cli -p 26379 info Sentinel
# Sentinel
sentinel_masters:1     #一台主节点
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.121.10:6379,slaves=2,sentinels=3

五、Redis 集群模式

集群,即Redis Cluster,是Redis3.0开始引入的分布式存储方案。

集群由多个节点(Node)组成,Redis的数据分布在这些节点中。集群中的节点分为主节点和从节点:只有主节点负责读写请求和集群信息的维护;从节点只进行主节点数据和状态信息的复制。

作用

(1)数据分区: 数据分区(或称数据分片)是集群最核心的功能。

  • 集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。
  • Redis单机内存大小受限问题,在介绍持久化和主从复制时都有提及;例如,如果单机内存太大,bgsave和bgrewriteaof的fork操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出。

(2)高可用: 集群支持主从复制和主节点的自动故障转移(与哨兵类似);当任一节点发生故障时,集群仍然可以对外提供服务。

配置实验

redis的集群一般需要6个节点,3主3从。方便起见,这里所有节点在同一台服务器上模拟

以端口号进行区分: 3个主节点端口号: 6001/6002/6003, 对应的从节点端口号: 6004/ 6005/ 6006

1.创建6个端口的工作目录

cd /opt/redis-5.0.7/utils/
./install_server.sh ##回车,直到出现以下选项,手动修改为"/usr/local/redis/bin/redis-server"
Please select the redis executable path [ ] /usr/local/redis/bin/redis-server
ln -s /usr/local/redis/bin/* /usr/local/bin/
cd /etc/redis/
mkdir -p redis-cluster/redis600{1..6}   ###创建redis 6个端口的工作目录
​
vim /opt/redis.sh
#!/bin/bash
for i in {1..6}
do
cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis600$i 
cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-   cluster/redis600$i
done
​
sh -x /opt/redis.sh

2.修改6个redis的配置文件

cd /etc/redis/redis-cluster/redis6001
vim redis.conf
    69 bind 127.0.0.1       ##注释掉bind项或不修改,默认监听所有网卡
    88 protected -mode no       ##修改,关闭保护模式
    92 port 6001        ##修改,redis监听端口
    136 daemonize yes       ##开启守护进程,以独立进程启动
    832 cluster-enabled yes     ## 取消注释,开启群集功能
    840 cluster-config-file nodes-6001.conf     ##取消注释,群集名称文件设置
    846 cluster-node-timeout 15000      ##取消注释群集超时时间设置
其他五个配置文件除端口号和文件名称外其余改动相同,复制redis6001至redis6002-6006

3.启动服务

-------------->手动启动六次<------------------
cd /etc/redis/redis-cluster/redis6001
redis-server redis.conf     ###启动服务
-------------->写入脚本执行脚本<------------------
vim /opt/redis_start.sh ##根据对应配置文件启动redis
    #!/bin/bash
    for d in {1..6}
    do
    cd /etc/redis/redis-cluster/redis600$d
    redis-server redis.conf
    done
sh -x /opt/redis_start.sh
ps -ef | grep redis

4.加入集群

六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点;下面交互的时候需要输入yes才可以创建;-replicas 1表示每个主节点有一个从节点\

redis-cli --cluster create 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:6004 127.0.0.1:6005 127.0.0.1:6006 --cluster-replicas 1

5.测试群集

redis-cli -p 6001 -c        ##加-c参数,节点之间就可以互相跳转
127.0.0.1:6001> cluster slots       ##查看节点的哈希槽编号范围
1) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 6003
      3) "4d00a92e17456ea977247d17e03a6b694bb62f12"
   4) 1) "127.0.0.1"
      2) (integer) 6006
      3) "96da9ee7f44404cc667eec96fbd63d63fa7ca484"
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 6002
      3) "50874a35e526855d24fcd9574e2fc24a9db27147"
   4) 1) "127.0.0.1"
      2) (integer) 6005
      3) "4fc4fb848de9e8284fec1e451a1f3bc9ba12e4a4"
3) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 6001
      3) "89b5c4caf0bc04943bfa0f1f6c216102d160efd2"
   4) 1) "127.0.0.1"
      2) (integer) 6004
      3) "c2db328985191ad6512b0c17bda0536e1398f915"
127.0.0.1:6001> set name kl     ##新建的键,验证是否会分配到指定哈希槽
-> Redirected to slot [5798] located at 127.0.0.1:6002
OK
127.0.0.1:6002> cluster keyslot kl
(integer) 15098     

六、总结

1、持久化到底用哪个更好呢?

  • 推荐是两者均开启。
  • 如果对数据不敏感,可以选单独用 RDB。
  • 如果只是做纯内存缓存,可以都不用。

2、三种模式需要注意修改不同的配置文件。

主从复制:vim /etc/redis/6379.conf

哨兵模式:vim /opt/redis-5.0.7/sentinel.conf

cluster集群:vim /opt/redis-5.0.7/redis.conf