
Redis持久化RDB与AOF实战文章目录Redis持久化RDB与AOF实战RAIDS持久化RDBAOFRAIDS持久化什么是 Redis 持久化?Redis 作为一个键值对内存数据库(NoSQL)数据都存储在内存当中在处理客户端请求时所有操作都在内存当中进行如下所示这样做有什么问题呢其实只要稍微有点计算机基础知识的人都知道存储在内存当中的数据只要服务器关机(各种原因引起的)内存中的数据就会消失了。不仅服务器关机会造成数据消失Redis 服务器守护进程退出内存中的数据也一样会消失。对于只把 Redis 当缓存来用的项目来说数据消失或许问题不大重新从数据源把数据加载进来就可以了。但如果直接把用户提交的业务数据存储在 Redis 当中把 Redis 作为数据库来使用在其放存储重要业务数据那么 Redis 的内存数据丢失所造成的影响也许是毁灭性。为了避免内存中数据丢失Redis 提供了对持久化的支持我们可以选择不同的方式将数据从内存中保存到硬盘当中使数据可以持久化保存。Redis 提供了 RDB 和 AOF 两种不同的数据持久化方式RDBRedis DataBaseAOFAppen-only FileRDBRDB 是一种快照存储持久化方式具体就是将 Redis 某一时刻的内存数据保存到硬盘的文件当中默认保存的文件名为dump.rdb而在 Redis 服务器启动时会重新加载dump.rdb文件的数据到内存当中恢复数据。开启 RDB 持久化方式开启 RDB 持久化方式很简单客户端可以通过向 Redis 服务器发送save或bgsave命令让服务器生成RDB 文件或者通过服务器配置文件指定触发 RDB 条件。save 命令是一个同步操作# 同步数据到磁盘上127.0.0.1:6379save OK当客户端向服务器发送 Save 命令请求进行持久化时服务器会阻塞 Save 命令之后的其他客户端的请求直到数据同步完成。如果数据量太大同步数据会执行很久而这期间 Redis 服务器也无法接收其他请求所以最好不要在生产环境使用 Save 命令。范例save执行过程会使用主进程进行快照# 查看默认进程[rootlocalhost ~]# pstree -p | grep redis-server ; ll -h /var/lib/redis|-redis-server(2104)--{redis-server}(2105)||-{redis-server}(2106)|-{redis-server}(2107)total4.0K -rw-r--r--1 redis redis92Feb2117:58 dump.rdb# 执行save[rootlocalhost ~]# redis-cli127.0.0.1:6379debug populate5000000#这是 Redis 的一个调试命令debugcommand用于快速生成大量测试数据这个命令不会触发持久化AOF / RDB 不会记录它因为它属于 调试命令。 OK(5.99s)127.0.0.1:6379save OK(5.07s)# 再开个窗口[rootlocalhost ~]# pstree -p | grep redis-server ; ll -h /var/lib/redis|-redis-server(2104)--{redis-server}(2105)||-{redis-server}(2106)|-{redis-server}(2107)total 64M -rw-r--r--1 redis redis92Feb2117:59 dump.rdb -rw-r--r--1 redis redis 51M Feb2117:59 temp-2104.rdb#主进程号2104Bgsave与 Save 命令不同Bgsave 命令是一个异步操作。# 异步保存数据到磁盘上127.0.0.1:6379bgsave Background saving started当客户端发服务发出 bgsave 命令时Redis 服务器主进程会 Forks 一个子进程来数据同步问题在将数据保存到 RDB 文件之后子进程会退出。所以与 save 命令相比Redis 服务器在处理 Bgsave 采用子线程进行 IO 写入。而主进程仍然可以接收其他请求但 Forks 子进程是同步的所以 Forks 子进程时一样不能接收其他请求。这意味着如果 Forks 一个子进程花费的时间太久一般是很快的Bgsave 命令仍然有阻塞其他客户的请求的情况发生。**服务器配置自动触发**除了通过客户端发送命令外还有一种方式就是在 Redis 配置文件中的 Save 指定到达触发 RDB 持久化的条件比如【多少秒内至少达到多少写操作】就开启 RDB 数据同步。例如我们可以在配置文件 redis.conf 指定如下的选项# 以下是默认值[rootlocalhost ~]# vim /etc/redis.conf218save9001# 900秒内修改了1个KEY即触发保存RDB219save30010# 300秒内修改了10个KEY即触发保存RDB220save6010000# 60秒内修改了10000个KEY即触发保存RDB这种通过服务器配置文件触发 RDB 的方式与 Bgsave 命令类似达到触发条件时会 Forks 一个子进程进行数据同步。范例手动执行备份RDB[rootlocalhost ~]# redis-cli127.0.0.1:6379flushall OK127.0.0.1:6379debug populate5000000OK(8.99s)127.0.0.1:6379get key:0value:0127.0.0.1:6379get key:1value:1127.0.0.1:6379get key:2value:2127.0.0.1:6379get key:499999value:499999127.0.0.1:6379get key:5000000(nil)127.0.0.1:6379bgsave Background saving started#再开个窗口[rootlocalhost ~]# pstree -p | grep redis-server ; ll -h /var/lib/redis|-redis-server(2104)--redis-server(2266)||-{redis-server}(2105)||-{redis-server}(2106)|-{redis-server}(2107)total 191M -rw-r--r--1 redis redis 127M Feb2117:54 dump.rdb -rw-r--r--1 redis redis 62M Feb2117:55 temp-2266.rdb#新开了个子进程2266RDB 文件前面介绍了三种让服务器生成 RDB 文件的方式无论是由主进程生成还是子进程来生成其过程如下生成临时 RDB 文件并写入数据。完成数据写入用临时文代替代正式 RDB 文件。删除原来的 DB 文件。RDB 默认生成的文件名为 dump.rdb当然我可以通过配置文件进行更加详细配置。241rdbcompressionyes# 是否压缩rbd文件253dbfilename dump.rdb# rdb文件的名称263dir/var/lib/redis# rdb文件保存目录RDB的几个优点与 AOF 方式相比通过 RDB 文件恢复数据比较快。RDB 文件非常紧凑适合于数据备份。通过 RDB 进行数据备份由于使用子进程生成所以对 Redis 服务器性能影响较小。RDB 的几个缺点如果服务器宕机的话采用 RDB 的方式会造成某个时段内数据的丢失比如我们设置 10 分钟同步一次或 5 分钟达到 1000 次写入就同步一次那么如果还没达到触发条件服务器就死机了那么这个时间段的数据会丢失。使用 Save 命令会造成服务器阻塞直接数据同步完成才能接收后续请求。使用 Bgsave 命令在 Forks 子进程时如果数据量太大Forks 的过程也会发生阻塞另外Forks子进程会耗费内存。AOF聊完了 RDB来聊聊 Redis 的另外一个持久化方式AOFAppend-only file。与 RDB 存储某个时刻的快照不同AOF 持久化方式会记录客户端对服务器的每一次写操作命令并将这些写操作以 Redis 协议追加保存到以后缀为 AOF 文件末尾。在 Redis 服务器重启时会加载并运行 AOF 文件的命令以达到恢复数据的目的。①开启 AOF 持久化方式Redis 默认不开启 AOF 持久化方式我们可以在配置文件中开启并进行更加详细的配置如下面的redis.conf 文件# aof机制默认关闭699appendonly no# aof文件名703appendfilenameappendonly.aof# 写入策略,always表示每个写操作都保存到aof文件中,也可以是everysec或no729appendfsync everysec# 默认不重写aof文件751no-appendfsync-on-rewrite no# 保存目录dir/var/lib/redis错误开启AOF功能会导致数据丢失注意AOF模式默认是关闭的第一次开启AOF后并重启服务生效后会因为AOF的优先级高于RDB而AOF默认没有数据文件存在从而导致所有数据丢失[rootlocalhost ~]# redis-cli127.0.0.1:6379dbsize(integer)5000000[rootlocalhost ~]# vim /etc/redis.conf699appendonlyyes#修改此行[rootlocalhost ~]# systemctl restart redis[rootlocalhost ~]# redis-cli127.0.0.1:6379dbsize(integer)0# 还原步骤[rootlocalhost ~]# rm -f /var/lib/redis/appendonly.aof[rootlocalhost ~]# vim /etc/redis.conf699appendonly no#修改此行[rootlocalhost ~]# systemctl restart redis[rootlocalhost ~]# redis-cli127.0.0.1:6379FLUSHALL OK127.0.0.1:6379DEBUG POPULATE5000000OK(4.86s)127.0.0.1:6379DBSIZE(integer)5000000正确启用AOF功能防止数据丢失[rootlocalhost ~]# ll /var/lib/redis/total4-rw-r--r--1 redis redis 127M Feb2117:27 dump.rdb[rootlocalhost ~]# redis-cli127.0.0.1:6379config get appendonly1)appendonly2)no127.0.0.1:6379configsetappendonlyyes#自动触发AOF重写会自动备份所有数据到AOF文件 OK127.0.0.1:6379config get appendonly1)appendonly2)yes[rootlocalhost ~]# ll /var/lib/redis/total8-rw-r--r--1 redis redis 127M Feb2117:29 appendonly.aof -rw-r--r--1 redis redis 127M Feb2117:29 dump.rdb[rootlocalhost ~]# vim /etc/redis.conf699appendonlyyes#修改此行# 验证[rootlocalhost ~]# systemctl restart redis[rootlocalhost ~]# redis-cli127.0.0.1:6379DBSIZE(integer)5000000②三种写入策略在上面的配置文件中我们可以通过 appendfsync 选项指定写入策略有三个选项appendfsync always# appendfsync everysec# appendfsync no**always**客户端的每一个写操作都保存到 AOF 文件当中这种策略很安全但是每个写操作都有 IO 操作所以也很慢。**everysec**appendfsync 的默认写入策略每秒写入一次 AOF 文件因此最多可能会丢失 1s 的数据。**no**Redis 服务器不负责写入 AOF而是交由操作系统来处理什么时候写入 AOF 文件。更快但也是最不安全的选择不推荐使用。③AOF 文件重写AOF重写是通过读取服务器当前的数据库状态来实现的。我举个例子大家就明白了假设我对 Redis 执行了下面六条命令rpush listArpush listBrpush listCrpush listDrpush listErpush listF那么服务器为了保存当前 list键的状态会在AOF文件中写入上述六条命令。而我现在要对 AOF 进行重写的话其实最高效最简单的方式不是挨个读取和分析现有AOF文件中的这六条命令。而是直接从数据库中读取键 list 的值然后用一条命令rpush list “A” “B” “C” “D” “E” “F” 可以直接代替原 AOF 文件中的六条命令。命令由六条减少为一条重写的目的就达到了。**两种重写方式**通过在 redis.conf 配置文件中的选项 no-appendfsync-on-rewrite 可以设置是否开启重写。这种方式会在每次 Fsync 时都重写影响服务器性能因此默认值为 no不推荐使用。# 默认不重写aof文件no-appendfsync-on-rewrite no客户端向服务器发送 bgrewriteaof 命令也可以让服务器进行 AOF 重写。# 让服务器异步重写追加aof文件命令127.0.0.1:6379bgrewriteaof Background append onlyfilerewriting started[rootlocalhost ~]# pstree -p | grep redis-server ; ll -h /var/lib/redis/|-redis-server(1924)--redis-server(1940)||-{redis-server}(1925)||-{redis-server}(1926)|-{redis-server}(1927)total 318M -rw-r--r--1 redis redis 127M Feb2414:29 appendonly.aof -rw-r--r--1 redis redis 127M Feb2414:27 dump.rdb -rw-r--r--1 redis redis 43M Feb2414:32 temp-rewriteaof-1940.aofAOF 重写方式也是异步操作即如果要写入 AOF 文件则 Redis 主进程会 Forks 一个子进程来处理如下所示重写 AOF 文件的好处压缩 AOF 文件减少磁盘占用量。将 AOF 的命令压缩为最小命令集加快了数据恢复的速度。③AOF 文件损坏在写入 AOF 日志文件时如果 Redis 服务器宕机则 AOF 日志文件文件会出格式错误。在重启 Redis 服务器时Redis 服务器会拒绝载入这个 AOF 文件可以通过以下步骤修复 AOF 并恢复数据备份现在 AOF 文件以防万一。使用 redis-check-aof 命令修复 AOF 文件该命令格式如下# 修复aof日志文件[rootlocalhost ~]# redis-check-aof --fix /var/lib/redis/appendonly.aofThe AOF appears to start with an RDB preamble. Checking the RDB preamble to start:[offset0]Checking RDBfile--fix[offset26]AUX FIELD redis-ver5.0.3[offset40]AUX FIELD redis-bits64[offset52]AUX FIELD ctime1771664520[offset67]AUX FIELD used-mem858552[offset83]AUX FIELD aof-preamble1[offset85]Selecting DB ID0[offset1202]Selecting DB ID1[offset1245]Checksum OK[offset1245]\o/ RDB looks OK!\o/[info]110keysread[info]0expires[info]0already expired RDB preamble is OK, proceeding with AOF tail... AOF analyzed:size1245,ok_up_to1245,diff0AOF is valid重启 Redis 服务器加载已经修复的 AOF 文件恢复数据。AOF 的优点AOF 只是追加日志文件因此对服务器性能影响较小速度比 RDB 要快消耗的内存较少。AOF 的缺点AOF 方式生成的日志文件太大即使通过 AFO 重写文件体积仍然很大。恢复数据的速度比 RDB 慢。选择 RDB 还是 AOF 呢通过上面的介绍我们了解了 RDB 与 AOF 各自的优点与缺点到底要如何选择呢通过下面的表示我们可以从几个方面对比一下 RDB 与 AOF在应用时要根据自己的实际需求选择RDB 或者 AOF。其实如果想要数据足够安全可以两种方式都开启。当 RDB 与 AOF 两种方式都开启时Redis 会优先使用 AOF 日志来恢复数据因为 AOF 保存的文件比RDB 文件更完整。小结上面讲了一大堆 Redis 的持久化机制的知识其实如果你只是单纯把 Redis 作为缓存服务器那么可以完全不用考虑持久化。但是在如今的大多数服务器架构中Redis 不单单只是扮演一个缓存服务器的角色还可以作为数据库保存我们的业务数据此时我们则需要好好了解有关 Redis 持久化策略的区别与选择。