Redis—高可用及持久化

  • Post author:
  • Post category:其他





一、Redis 高可用

  • 在 web 服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。
  • 但是在 Redis 语境中,高可用除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展,数据安全不会丢失等。
  • 在 Redis 中,实现高可用的技术主要包括持久化、主从复制、哨兵和集群



1. 持久化

主要作用是数据备份,即把数据保存在一个位置或者磁盘中



2. 主从复制

  • 主从复制是高可用 Redis 的基础,主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复
  • 缺陷:故障恢复无法自动化,写操作无法负载均衡,单机的原因限制了存储能力



3. 哨兵

  • 需要在主从复制的基础上实现自动化的故障恢复
  • 缺陷:写操作无法实现负载均衡,单机的原因限制了存储能力



4. 集群(cluster)

  • 通过集群,Redis 解决了写操作无法负载均衡,以及存储能力受到单机限制的问题
  • 实现了较为完善的高可用方案



二、Redis 持久化方式



1. 持久化的功能

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



2. 持久化的方式

  • RDB 持久化

    原理是将 Reids 在内存中的数据库记录定时保存到磁盘上 (类似于快照)
  • AOF 持久化 (append only file)

    目前主流的持久化方式

    原理是将 Reids 的操作日志以追加的方式写入文件,类似于 MySQL 的 binlog。 (基于日志持久化方式)



三、RDB 持久化

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



1. 触发条件


  • 手动触发(生成RDB文件:save命令、bgsave命令)

① save命令会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止,在 Redis 服务器阻塞期间,服务器不能处理任何命令请求

② bgsave 命令——>派生子进程——>子进程来创建 RDB 文件并阻塞服务器——>父进程(主进程)则继续处理请求


  • 自动触发

① 在自动触发 RDB 持久化时,Redis 会选择 bgsave 来进行持久化

② save m n →自动触发通常是在配置文件中此命令触发 bgsave

m:多少 s 内; n:发生多少次

vim /etc/redis/6379.conf
#下面三个 save 条件满足任意一个,都会引起 bgsave 的调用

219 save 900 1 	 					#当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
220 save 300 10  					#当时间到300秒时, 如果redis数据发生了至少10次变化, 则执行bgsave
221 save 60 10000  					#当时间到60秒时,如果redis数据发生了至少10000次变化, 则执行bgsave

242 rdbcompression yes		 		#是否开启RDB文件压缩
254 dbfilename dump.rdb		 		#指定RDB文件名
264 dir /var/lib/redis/6379			#指定RDB文件和AOF文件所在目录

  • 其他自动触发机制

① 在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点

② 执行shutdown命令时,自动执行rdb持久化



2. 执行流程

  • Redis 父进程首先判断:当前是否在执行 save,或 bgsave/bgrewriteaof 的子进程,如果在执行则 bgsave 命令直接返回 bgsave/bgrewriteaof
  • 父进程执行 fork 操作创建子进程,这个过程中父进程是阻塞的,Redis 不能执行来自客户端的任何命令
  • 父进程 fork后,bgsave 命令返回 ”Background saving started” 信息并不再阻塞父进程,并可以响应其他命令
  • 子进程创建 RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
  • 子进程发送信号给父进程表示完成,父进程更新统计信息



3. 启动时加载

  • RDB 文件的载入工作是在服务器启动时自动执行的,并没有专门的命令
  • 优先级:AOF>RDB,因此当 AOF 开启时,默认先载入 AOF 文件,仅当 AOF 关闭,才会载入 RDB 文件
  • Redis 载入 RDB 文件时(即启动过程中),会对RDB 文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败



四、AOF 持久化

是将 Redis 执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录

当 Redis 重启时优先执行 AOF 文件中的命令来恢复数据。



1.开启 AOF

  • Redis 服务器默认开启 RDB,关闭 AOF,要开启AOF,需要在配置文件中配置
vim /etc/redis/6379.conf
700 appendonly yes								#修改成yes,开启AOF
704 appendfilename "appendonly.aof"		    	#指定A0F文件名称
796 aof-load-truncated yes		           	 	#是否忽略最后一条可能存在问题的指令

/etc/ init.d/redis_ 6379 restart		   	 	#重启redis



2. 执行流程

由于需要记录 Redis 的每条写命令,因此 A0F 不需要触发,AOF 的执行流程如下


  • ① 命令追加(append)


    将Redis的写命令追加到缓冲区aof_buf; (为了尽量不因为持久化而影响redis性能)


  • ② 文件写入(write)和文件同步(sync)


    根据不同的同步策略将 aof_buf 中的内容同步到硬盘,所以 Redis 系统同时提供了 fsync、fdatasync 等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。

AOF 缓存区的同步文件策略存在三种同步方式,如下

vim /etc/redis/6379.conf

729 appendfsync always		
#命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。
这种情况下,每次有写命令都要同步到A0F文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;
即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命。

729 appendfsync no
#命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。
这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。

729 appendfsync everysec(默认配置)
#命令写入aof_buf后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。
everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。

  • ③ 文件重写(rewrite)


    定期重写AOF文件,达到压缩的目的



3. 文件重写的触发分类

文件重写的触发,分为手动触发和自动触发

  • ① 手动触发

    直接调用 bgrewriteaof 命令

    通过 fork 子进程进行具体的工作,且只有在 fork 时阻塞。

  • ② 自动触发

    通过设置 auto-aof-rewrite-min-size 选项和 auto-aof-rewrite-percentage 选项来自动执行 BGREWRITEA0F,且两个选项同时满足时,才会自动触发 AOF 重写,即 bgrewriteaof 操作

vim /etc/ redis/ 6379. conf

#AOF同步的策略
729 # appendfsync always
730 appendfsync everysec
731 # appendfsync no
771	auto-aof-rewrite-percentage 100		 #当前AOF文件大小(即aof_current_size)是上次日志重写时AOF文件大小(aof_base_size)两倍时,发生BGREWRITEAOF操作
772 auto-aof-rewrite -min-size 64mb		 #当前A0F文件执行BGREWRITEAOF命令的最小值,避免刚开始启动Reids时由于文件尺寸较小导致频繁的BGREWRITEA0F



4. 启动时加载

  • 当 AOF 开启时,Redis 启动时会优先载入 AOF 文件来恢复数据;只有当 AOF 关闭时,才会载入 RDB 文件恢复数据。
  • 当 AOF 开启,但 AOF 文件不存在时,即使 RDB 文件存在也不会加载。
  • Redis 载入 AOF 文件时,会对 AOF 文件进行校验,如果文件损坏,则日志中会打印错误,Redis 启动失败。但如果是 AOF 文件结尾不完整 (机器突然宕机等容易导致文件尾部不完整),且 aof-load-truncated 参数开启,则日志中会输出警告,Redis 忽略掉 AOF 文件的尾部,启动成功。
  • aof-load-t runcated 参数默认是开启的



五、RDB 与 AOF 的优缺点



1. RDB 持久化

  • 优点

    ① RDB 文件紧凑,体积小,网络传输快,适合全量复制

    ② 恢复速度比 AOF 快很多

    ③ 与 AOF 相比, RDB 最重要的优点之一是对性能的影响相对较小
  • 缺点

    ① RDB 文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此 AOF 持久化成为主流

    ② 此外,RDB 文件需要满足特定格式,兼容性差(如老版本的 Redis 不兼容新版本的 RDB 文件)

    ③ 对于 RDB 持久化,一方面是 bgsave 在进行 fork 操作时 Redis 主进程会阻塞,另一方面,子进程向硬盘写数据也会带来 IO 压力



2. AOF 持久化

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



六、Redis 性能管理



1. 查看 Redis 内存使用

[root@localhost ~]#redis-cli -h 192.168.8.16 -p 6379
192.168.8.16:6379> info memory
# Memory
used_memory:12270264
used_memory_human:11.70M
used_memory_rss:22257664
used_memory_rss_human:21.23M
used_memory_peak:12270264
used_memory_peak_human:11.70M
used_memory_peak_perc:100.00%
......



2. 内存碎片率

  • 操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存值 used_memory 计算得出内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)
  • 跟踪内存碎片率对理解 Redis 实例的资源性能是非常重要的

① 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低

② 内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150号,其中50号是内存碎片率。需要在redis-cli工具上输入shutdownsave命令,并重启Redis服务器。

③ 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少Redis内存占用



3. 内存使用率

  • redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换
  • 避免内存交换发生的方法如下:

① 针对缓存数据大小选择安装Redis实例(云平台里面使用RDS服务,ECS云主机选择内存、缓存型配置) 尽可能的使用Hash数据结构存储

② 设置key的过期时间



4. 内回收 key

  • 保证合理分配 redis 有限的内存资源
  • 当达到设置的最大阀值时,需选择一种 key 的回收策略,默认情况下回收策略是禁止删除
  • 配置文件中修改 maxmemory- policy 属性值
vim /etc/redis/6379.conf

598 maxmemory-policy noenviction
volatile-lru	 								#使用LRU算法从已设置过期时间的数据集合中淘汰数据
volatile-ttl	  								#从已设置过期时间的数据集合中挑选即将过期的数据淘汰
volatile-random	 								#从已设置过期时间的数据集合中随机挑选数据淘汰
allkeys-lru 	 								#使用LRU算法从所有数据集合中淘汰数据
allkeys-random  								#从数据集合中任意选择数据淘汰



总结

  • RDB和AOF,RDB 是默认开启的,AOF 需要手动开启

  • 持久化方式

    ① RDB→周期性的快照,二进制压缩格式

    ② A0F→接近实时的持久化(以everysec方式)基于日志文件持久化;还有一个文件重写功能,可以帮助AOF减少持久化文件的大小

  • redis 启用的优先级

    AOF>RDB,同时仅当AOF功能关闭的情况下,redis才会在重新启动时使用RDB的方式进行恢复

  • RDB和AOF中持久化模式

    ① RDB:由redis主进程( 周期性) fork 派生出子进程对redis内存中的数据进行持久化(二进制压缩),生成到.rd文件中,自动触发的方式是使用的bgsave持久化

    ② AOF:根据持久化策略(alawys、no、everysec(默认) ),先将redis中的语句保存在缓冲区中,再从缓冲区同步到.aof文件中;bgrewriteaeof



版权声明:本文为weixin_59410846原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。