前文如上:
39.【面试宝典】面试宝典-redis过期k值回收策略,缓存淘汰策略
合集参考:面试宝典
redis持久化
1.概述
由于 redis 是一个内存数据库,所谓内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的数据将会全部丢失. redis持久化是指在指定的时间间隔内将内存中的数据集快照(snapshotting)写入磁盘,恢复时是将快照文件读入内存。redis提供了两种持久化方式:
- RDB(Redis DataBase)
- AOF(Append of File)
2.rdb:
2.1 概念:
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里,在默认配置中,Redis将内存数据库快照保存在名字为dump.rdb的二进制文件中。
2.2 原理:
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。如图所示:
注: fork函数的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
2.3 优点:
- 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。
- 节省磁盘空间
- 恢复速度快
2.4 缺点:
- Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
- 虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。
- 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
适合场景: 适合大规模的数据恢复,适合对数据完整性和一致性要求不高更适合使用。
2.5 触发方式
- 自动触发
可以通过配置文件配置持久化策略:save N M,表示m秒内数据集存在n次修改时,自动触发bgsave 例如redis的默认策略有:
save 900 1 -- 900秒内至少有一个改动 save 300 10 -- 300秒内至少有10个改动 save 60 10000 -- 60秒内至少有10000个改动
当然如果你只是用Redis的缓存功能,不需要持久化,那么你可以注释掉所有的 save 行来停用保存功能。 也可以直接一个空字符串来实现停用:
save ""
或者连接客户端手动停止RDB:
redis-cli config set save "" #save后给空值,表示禁用保存策略
- 手动触发 手动触发Redis进行RDB持久化的命令有两种:
- save: 该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。显然该命令对于内存比较大的实例会造成长时间阻塞,这是致命的缺陷,为了解决此问题,Redis提供了第二种方式。
- bgsave: 执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体操作是Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。
注意:执行执行 flushall 命令,也会产生dump.rdb文件,但里面是空的.shutdown
也会触发Redis
的RDB
持久化机制,我们在客户端执行shutdown
即可
- 其他参数配置
- stop-writes-on-bgsave-error:默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了。
- rdbcompression :默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。
- rdbchecksum :默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
- dbfilename :设置快照的文件名,默认是 dump.rdb
- dir:设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。
也就是说通过在配置文件中配置的 save 方式,当实际操作满足该配置形式时就会进行 RDB 持久化,将当前的内存快照保存在 dir 配置的目录中,文件名由配置的 dbfilename 决定。
3. aof
3.1 概念
为解决RDB方式丢失数据的问题,从1.1版本开始,redis增加了一种更加可靠的方式:AOF持久化方式。
AOF(Append Only File)是把所有对内存进行修改的指令(写操作)以独立日志文件的方式进行记录,只许追加文件但不可以改写文件(类似于wal日志)。AOF
能够解决数据持久化实时性问题,是现在Redis
持久化机制中主流的持久化方案。redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
3.2 流程
- 客户端所有请求的写命令都会被追加到AOF缓冲区中;
- AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
- AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
- (AOF重写:当
AOF
的文件达到重写策略配置的阈值时,Redis
会对AOF
日志文件进行重写,给AOF
日志文件瘦身) - Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
3.3 优势
- 备份机制更稳健,丢失数据概率更低。
- 可读的日志文本,通过操作AOF稳健,可以处理误操作。
3.4 劣势
- 客户端所有请求的写命令都会存储,比起RDB占用更多的磁盘空间。
- 恢复备份速度要慢。
- 每次读写都同步的话,有一定的性能压力。
- 存在个别Bug,造成不能恢复。
3.5 配置
1 打开 redis.conf 文件,找到 APPEND ONLY MODE 对应内容 redis 默认关闭,开启需要手动把no改为yes
appendonly yes
2 指定本地数据库文件名,默认值为 appendonly.aof
appendfilename "appendonly.aof"
3 指定更新日志条件
# appendfsync always appendfsync everysec # appendfsync no
AOF同步频率设置
- appendfsync always 始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好
- appendfsync everysec 每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
- appendfsync no redis不主动进行同步,把同步时机交给操作系统。
3.6 总结
- 官方推荐两个都启用。
- 如果对数据不敏感,可以选单独用RDB。
- 不建议单独用 AOF,因为可能会出现Bug。
- 如果只是做纯内存缓存,可以都不用。
3.7 AOF重写
前面提到,AOF持久化客户端所有请求的写命令都会存储,比起RDB占用更多的磁盘空间,文件的冗余内容会越来越多。比如同一个key
被写了10000
次,最后却被删除了,这种情况不仅占内存,也会导致恢复的时候非常缓慢,因此Redis
提供重写机制来解决这个问题。
1.AOF重写原理
Redis 会fork出一条新进程,读取内存中的数据,并重新写到一个临时文件中。并没有读取旧文件。最后替换旧的aof文件。Redis
的AOF
持久化机制执行重写后,保存的只是恢复数据的最小指令集,我们如果想手动触发可以使用如下指令:
bgrewriteaof 复制代码
2.AOF重写流程
AOF重写不会阻塞主线程,其重写过程是由后台子进程 bgrewriteaof 来完成的,从而避免了性能下降。具体流程如下:
- 把主线程的内存拷贝一份给fork出来的 bgrewriteaof 子进程,这里面包含了Redis中最新的数据。
- 子进程将其中的数据进行重写。
- 主线程维护一个AOF缓冲区(实际上无论重不重写都有这个缓冲区,因为AOF日志写入是 → AOF缓冲区 → AOF文件),如果此时有写操作,则会写入到AOF缓冲区以及AOF日志中,保证数据完整。
- 主线程在重写时维护一个AOF重写缓冲区,将重写过程中的写操作记入其中,保证重写后的AOF日志也能记录在重写过程中产生的新数据。
- 用新AOF替换老AOF日志。
文档参考:Redis持久化
由于重写AOF
文件时,会对Redis
的性能带来一定的影响,因此也不能随便的进行自动重写,Redis
提供两个配置用于自动进行AOF
重写的指标,只有这两个指标同时满足的时候才会发生重写:
3.AOF重写触发机制
当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。这里的“一倍”和“64M” 可以通过配置文件修改
- auto-aof-rewrite-percentage 100:指的是当文件的内存达到原先内存的两倍
- auto-aof-rewrite-min-size 64mb:指的是文件重写的最小内存大小
4.思考:为什么AOF重写不采用覆盖的方式
父子进程写同一个文件必然会产生竞争,如果控制竞争就意味着会影响父进程的性能。 如果AOF重写失败,那么原本的AOF文件相当于被污染了,就直接废了。而采用覆盖的方式则不会有这种负面影响(重写失败就直接删了,一点影响没有)。
4. 拓展
4.1 如何选择合适的持久化方式
- 一般来说,如果想达到足以媲美
PostgreSQL
的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当Redis
重启的时候会优先载入AOF
文件来恢复原始的数据,因为在通常情况下AOF
文件保存的数据集要比RDB
文件保存的数据集要完整。 - 如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失,那么你可以只使用
RDB
持久化。 - 有很多用户都只使用
AOF
持久化,但并不推荐这种方式,因为定时生成RDB
快照(snapshot
)非常便于进行数据库备份,并且RDB
恢复数据集的速度也要比AOF
恢复的速度要快,除此之外,使用RDB
还可以避免AOF
程序的bug
。 - 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
4.2 Redis持久化数据和缓存怎么做扩容?
- 如果
Redis
被当做缓存使用,使用一致性哈希实现动态扩容缩容。 - 如果
Redis
被当做一个持久化存储使用,必须使用固定的keys-to-nodes
映射关系,节点的数量一旦确定不能变化。否则的话(即Redis
节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis
集群可以做到这样。
公众号,感谢关注