redis所有的数据都在内存中,持久化就是将数据异步的保存到磁盘中
持久化的两种方式:
- 快照,将当前节点的数据保存一份(例如:Mysql Dump,Redis RDB)
- 写日志(例如:Mysql Binlog,Hbase Hlog,Redis AOF)
RDB
将数据以快照的方式存储到磁盘中。redis将文件压缩成二进制文件。
保存到磁盘的3种方式:
save命令(同步)
- 生成一个临时的文件,然后替换老的RDB文件
bgsave(异步)
- 使用Linux的fork()函数,生成一个redis的子进程,用于保存数据,阻塞发生在fork阶段,fork的过程很快,并且有内存的消耗
- Linux的fork()函数会把原来的进程的所有值都复制到新的进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。redis并没有完全拷贝所有内存,而是采用了copy-on-write的策略
自动
- 满足,60秒内有10000次操作,或300秒内有10次操作,或900内有一次操作,满足任一条件,就调用bgsave
- 缺点是过于频繁,会生成太多RDB文件
最佳配置:
1 | # save 900 1 # 不开启自动保存 |
缺点:
- 耗时,耗内存,cpu,IO
- 不可控,数据丢失
AOF
数据以日志的形式存储数据,先将每一条操作放入到缓存区中,再采用一定的策略将缓冲区的内容同步到磁盘中。
AOF的三种策略:
- always,将每一条命令先放入缓冲区,再立即同步到磁盘中,优点是不丢失数据,缺点是IO开销
- everysec,每秒钟同步一次,将缓冲区的数据写入到磁盘(redis默认值),优点没有IO开销,缺点是会丢失一秒钟的数据
- no,由操作系统决定什么时候同步
重写:
随着时间的推移,AOF文件的体积变得越来越大,恢复和写入速度变慢,redis提供了日志重写,将无用的日志去除,减小磁盘占用,加快恢复速度。
例如:对hello进行多次赋值,重写后只保留最后一条赋值的操作;数字多次增加,只保留最后数字的值;过期数据直接忽略;多次rpush合并为一次rpush操作…
两种实现方式:
- bgrewriteaof命令,fork出子进程用于重写,并不是去分析旧的日志,而是直接将内存中的数据写入AOF文件
- 自动配置
auto-aof-rewrite-min-size
,指定AOF文件占用多大空间时进行重写auto-aof-rewrite-percentage
,增长率,例如设置增长率为100%,目前重写完是100M,那么增长到200M时,再进行一次重写aof_current_size
,AOF当前尺寸(单位字节),内置的统计变量,不需要配置aof_base_size
,AOF上次启动和重写的尺寸(单位字节),内置的统计变量,不需要配置
最佳配置:
1 | appenfonly yes # 支持动态变化`config set appendonly yes` |
对比
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 根据策略决定 |
轻重 | 重 | 轻 |
最佳策略
- 小分片,redis因为单线程,实际生产中都是单机多实例,通过
max-memory
给每个实例设置一个较小的内存,例如4G,这样每次持久化的时候,消耗较小,不集中。 - 预留40%的空余内存用于持久化,内存不足会引发数据丢失和一系列奇怪问题。