redis持久化方案
Posted zsk-1996
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis持久化方案相关的知识,希望对你有一定的参考价值。
说到redis的持久化,可以先说redis的高可用,而保证其高可用的手段有------持久化、复制、哨兵、集群。
持久化:数据的备份,将数据存入硬盘保证数据不会因进程退出而丢失。
复制:是哨兵和集群的基础。复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。
redis的持久化又可分为RDB持久化和AOF持久化:前者将当前数据保存到硬盘,后者则是将每次执行的写命令保存到硬盘(类似于mysql的binlog);由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式。
- RDB持久化(也称快照持久化)
- 触发条件:有手动触发和自动触发两种。
- 手动触发:save和bgsave命令都可以生成RDB文件。前者因为会阻塞redis服务器进程,已基本被弃用;后者是通过fork子进程来负责RDB文件的创建,因此只会在fork的时候阻塞。
- 自动触发:最常见的是在redis.conf中配置 save m n ,意思为 指定当m秒内发生n次变化时,会触发bgsave。而 save m n 的实现原理是通过 serverCron函数、dirty计数器、和lastsave时间戳来实现的。
- serverCron是周期性操作函数,默认每隔100ms执行一次,会对服务器状态进行维护,其中一项就是检查 save m n 配置条件是否满足,满足则执行 bgsave。
- dirty计数器则是负责记录上一次bgsave/save命令后服务器状态进行的修改次数(增删改);执行bgsave/save命令后将置0。
- lastsave时间戳记录的是上一次成功执行bgsave/save命令的时间。
- save m n的原理即是:通过serverCron函数的周期性执行检查save m n的配置条件是否满足,满足则执行命令。而只有当 dirty >= n && lastsave > m 时才算满足条件。
- 其他自动触发机制:在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点;执行shutdown命令时,自动执行rdb持久化。
- 执行流程:见下图即可
- 触发条件:有手动触发和自动触发两种。
-
- RDB文件
- 存储路径:可以在启动前配置,也可以通过命令动态设定。
- 配置:dir配置指定目录,dbfilename指定文件名。默认是Redis根目录下的dump.rdb文件。
- 动态设定:在磁盘损害或空间不足时非常有用;执行命令为config set dir {newdir}和config set dbfilename {newFileName}。
- RDB文件格式(见下图)
- 存储路径:可以在启动前配置,也可以通过命令动态设定。
- RDB文件
-
-
-
- REDIS:常量,保存着”REDIS”5个字符。
- db_version:RDB文件的版本号,注意不是Redis的版本号。
- SELECTDB 0 pairs:表示一个完整的数据库(0号数据库),SELECTDB 3 pairs 同理。只有当数据库中有键值对时,RDB文件中才会有该数据库的信息(上图所示的Redis中只有0号和3号数据库有键值对);如果Redis中所有的数据库都没有键值对,则这一部分直接省略。其中:SELECTDB是一个常量,代表后面跟着的是数据库号码;0和3是数据库号码;pairs则存储了具体的键值对信息,包括key、value值,及其数据类型、内部编码、过期时间、压缩信息等等。
- EOF:常量,标志RDB文件正文内容结束。
- check_sum:前面所有内容的校验和;Redis在载入RBD文件时,会计算前面的校验和并与check_sum值比较,判断文件是否损坏。
- 压缩(默认采用LZF进行压缩,默认为开启,可以通过命令 config set rdbcompression no 进行关闭)。需要注意的是,RDB文件的压缩并不是针对整个文件进行的,而是对数据库中的字符串进行的,且只有在字符串达到一定长度(20字节)时才会进行。
-
- 启动时加载:RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AOF的优先级更高,因此当AOF开启时,Redis会优先载入AOF文件来恢复数据。
- RDB常用配置总结
- save m n:bgsave自动触发的条件;如果没有save m n配置,相当于自动的RDB持久化关闭,不过此时仍可以通过其他方式触发
- stop-writes-on-bgsave-error yes:当bgsave出现错误时,Redis是否停止执行写命令;设置为yes,则当硬盘出现问题时,可以及时发现,避免数据的大量丢失。当对Redis服务器的系统(尤其是硬盘)使用了监控时,该选项考虑设置为no
- rdbcompression yes:是否开启RDB文件压缩
- rdbchecksum yes:是否开启RDB文件的校验,在写入文件和读取文件时都起作用
- dbfilename dump.rdb:RDB文件名
- dir ./:RDB文件和AOF文件所在目录
-
- AOF持久化(与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案)
- 开启AOF:需要在配置文件中配置:appendonly yes
- 执行流程:包括 命令追加、文件写入和文件同步以及文件重写。
- 命令追加:将Redis的写命令追加到缓冲区aof_buf。不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。
- 文件写入和文件同步:根据不同的同步策略将aof_buf中的内容同步到硬盘。AOF缓存区的同步文件策略由参数appendfsync控制,各个值的含义如下:
- always:命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈。
- no:命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
- everysec:命令写入aof_buf后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。
- 文件重写:随着时间的流逝,AOF文件会越来越大,会影响到服务器的正常运行,也会导致数据恢复需要的时间变长。文件重写指定期重写AOF文件,减小AOF文件的体积。AOF重写是同步到新的AOF文件,不会对旧文件进行任何读取、写入操作。
- 文件重写之所以能压缩文件,在于过期的数据不再写入文件;无效的命令不再写入文件(如有些数据被重复设值,有些数据被删除了);多条命令可以合并为一个。
- 文件重写的触发:分为手动和自动
- 手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。
- 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数,以及aof_current_size和aof_base_size状态确定触发时机。
- auto-aof-rewrite-min-size:执行AOF重写时,文件的最小体积,默认值为64MB。
- auto-aof-rewrite-percentage:执行AOF重写时,当前AOF大小(即aof_current_size)和上一次重写时AOF大小(aof_base_size)的比值。(参数可以通过config get {参数名}命令查看,状态可以通过info persistence查看)
- 只有当auto-aof-rewrite-min-size和auto-aof-rewrite-percentage两个参数同时满足时,才会自动触发AOF重写,即bgrewriteaof操作。
- 文件重写的流程:见下图
-
-
-
-
- Redis父进程首先判断当前是否存在正在执行 bgsave/bgrewriteaof的子进程,如果存在则bgrewriteaof命令直接返回,如果存在bgsave命令则等bgsave执行完成后再执行。
- 父进程执行fork操作创建子进程,这个过程中父进程是阻塞的
- 父进程fork后,bgrewriteaof命令返回”Background append only file rewrite started”信息并不再阻塞父进程,并可以响应其他命令。Redis的所有写命令依然写入AOF缓冲区,并根据appendfsync策略同步到硬盘,保证原有AOF机制的正确。
- 由于fork操作使用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然在响应命令,因此Redis使用AOF重写缓冲区(图中的aof_rewrite_buf)保存这部分数据,防止新AOF文件生成期间丢失这部分数据。也就是说,bgrewriteaof执行期间,Redis的写命令同时追加到aof_buf和aof_rewirte_buf两个缓冲区。
- 子进程根据内存快照,按照命令合并规则写入到新的AOF文件。
- 子进程写完新的AOF文件后,向父进程发信号,父进程更新统计信息,具体可以通过info persistence查看。
- 父进程把AOF重写缓冲区的数据写入到新的AOF文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致。
- 使用新的AOF文件替换老文件,完成AOF重写。、
-
-
- AOF常见配置总结
- appendonly no:是否开启AOF
- appendfilename “appendonly.aof”:AOF文件名
- dir ./:RDB文件和AOF文件所在目录
- appendfsync everysec:fsync持久化策略
- no-appendfsync-on-rewrite no:AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据;需要在负载和安全性之间进行平衡
- auto-aof-rewrite-percentage 100:文件重写触发条件之一
- auto-aof-rewrite-min-size 64mb:文件重写触发提交之一
- aof-load-truncated yes:如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件
-
- 方案选择
- RDB优缺点
- 优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小
- 缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化。此外,RDB文件需要满足特定格式,兼容性差。
- AOF优缺点
- 优点:在于支持秒级持久化、兼容性好
- 缺点:文件大、恢复速度慢、对性能影响大
- 持久化策略选择(按上述的优缺点即可大概知道)
- fork阻塞:CPU的阻塞
- 在Redis的实践中,众多因素限制了Redis单机的内存不能过大,例如:
- 当面对请求的暴增,需要从库扩容时,Redis内存过大会导致扩容时间太长
- 当主机宕机时,切换主机后需要挂载从库,Redis内存过大导致挂载速度过慢 以及持久化过程中的fork操作,下面说明:
- 父进程通过fork操作可以创建子进程;子进程创建后,父子进程共享代码段,不共享进程的数据空间,但是子进程会获得父进程的数据空间的副本。如果Redis内存过大,会导致fork操作时复制内存页表耗时过多;而Redis主进程在进行fork时,是完全阻塞的,也就意味着无法响应客户端的请求,会造成请求延迟过大。
- 在Redis的实践中,众多因素限制了Redis单机的内存不能过大,例如:
- AOF追加阻塞:硬盘的阻塞
- 在AOF中,如果AOF缓冲区的文件同步策略为everysec;如果硬盘负载过高,那么fsync操作可能会超过1s;如果Redis主线程持续高速向aof_buf写入命令,硬盘的负载可能会越来越大,IO资源消耗更快;如果此时Redis进程异常退出,丢失的数据也会越来越多,可能远超过1s。为此,Redis的处理策略是这样的:主线程每次进行AOF会对比上次fsync成功的时间;如果距上次不到2s,主线程直接返回;如果超过2s,则主线程阻塞直到fsync同步完成。因此,如果系统硬盘负载过大导致fsync速度太慢,会导致Redis主线程的阻塞;此外,使用everysec配置,AOF最多可能丢失2s的数据,而不是1s。
- info命令与持久化
- info Persistence和info stats
- RDB优缺点
- 总结
- 持久化在Redis高可用中的作用:数据备份,与主从复制相比强调的是由内存到硬盘的备份。
以上是关于redis持久化方案的主要内容,如果未能解决你的问题,请参考以下文章