Redis的主要优势在于快速的读写速度。但是,内存数据的易失性使得在断电或系统故障时可能丢失数据。为了保证数据的持久性,就需要让Redis把数据存储到硬盘上。Redis 提供了两种持久化策略:
RDB 是一种将 Redis 数据定期保存到磁盘上的快照方式。它会在指定的时间间隔内生成数据库的快照,并保存到磁盘上。后续Redis一旦重启,内存数据就没了,但是可以根据定期生成的快照把内存中的数据给恢复回来。
通过Redis客户端,执行特定命令save
和bgsave
来触发快照生成。
save
:执行save
的时候,Redis就会全力以赴的进行“快照生成”操作,此时就会阻塞Redis的其他命令。这可能会导致类似:keys *
的后果。
bgsave
:bgsave
命令是非阻塞的。它会 fork 一个子进程,由子进程来生成快照,而父进程(主进程)仍然可以继续处理客户端请求。
(1)判断当前是否已经存在其他正在工作的子进程,比如现在已经有一个子线程正在执行bgsave,那么就直接把当前的bgsave返回。
(2)如果没有其他的工作子进程,通过fork系统调用创建一个子线程。fork创建子线程,直接是把当前的父进程复制一份,作为子线程。一旦完成复制,子父线程就完全独立了,各自执行各自的任务了。
(3)子进程负责写文件、生成快照的过程;父进程继续接受客户端的请求,继续正常提供服务。
(4)子进程完成整体持久化过程之后,就会通知父进程已经工作完毕,父进程就会更新一些统计信息,随后销毁子进程。
cd /etc/redis
进入redis目录,vim redis.conf
打开配置文件。
可以看见redis的工作目录在/var/lib/redis
,这样对于生成的镜像文件也在这里。
Redis内存中的数据,以压缩(消耗CPU资源,但是节省空间)的方式保存到了这个二进制文件中。当执行生成rdb镜像的时候,此时就会要把生成的快照数据先存放到一个临时文件中,当这个快照生成完毕之后,再放到.rdb
文件中,随后删除临时文件。
AOF 是通过将每个写操作追加到日志文件(appendonly.aof)中的方式来实现持久化。这个有点类似于MySQL的binlog,会把用户的每个操作,都记录到文件中。Redis 可以在服务器重启时重新执行这些操作,从而恢复数据。当开启AOF的时候,RDB就不生效了。
cd /etc/redis
进入redis目录,vim redis.conf
打开配置文件,找到如图配置,将no改为yes开启AOF。
AOF工作机制并非直接让工作线程把数据写入硬盘,而是先写入一个内存中的缓存区,积累到一定内容后再统一写入硬盘。
当数据被写入到缓存区时,数据实际上还在内存中。如果在写入缓存区后但未写入硬盘前,进程挂掉或主机断电,那么缓存区中的数据就会丢失。
Redis提供了appendfsync 配置项,让我们根据实际情况决定如何平衡数据可靠性和系统性能。
appendfsync
有三个主要选项,每个选项对应不同的性能和数据可靠性权衡:
fsync()
,将数据立即写入磁盘。fsync()
,将数据写入磁盘。Redis 的 AOF重写机制是为了优化 AOF 文件的大小和性能而设计的。但是,随着时间的推移,AOF 文件会不断增长,如果不加以控制,文件可能会变得非常大,影响服务器的启动时间和性能。AOF 重写机制可以将现有的数据集写入一个新的 AOF 文件,从而压缩文件大小。
举例:我当前已经进行了如下操作:
1 | lpush key 111 |
但是,其实上面三条指令其实等价于:lpush key 111 222 333
原始 AOF 文件每次 LPUSH
操作都被单独记录,导致文件内容冗余。重写后的 AOF 文件将多次 LPUSH
操作合并为一次操作,极大地减少了文件大小。
手动触发 AOF 重写:bgrewiteaof
自动触发:可以设置AOF 文件在达到一定大小或比例后自动进行重写,可以在 Redis 配置文件 redis.conf
中设置以下参数:
1 | auto-aof-rewrite-percentage 100 # 当 AOF 文件大小超过上次重写后的 100% 时触发重写 |