江小南

V1

2022/08/21阅读:24主题:默认主题

【中间件】redis持久化方式

这个专栏,为大家介绍一些常用的中间件。今天介绍在实际开发过程中使用频率较高的redis。主要介绍持久化机制。

持久化机制

redis是一个支持持久化的内存数据库。支持两种持久化方式:一种是Snapshotting(快照),也是默认方式;另一种是Append-only file(AOF)的方式。

快照方式

快照方式是redis默认的持久化方式,就是将内存中的数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb,可以通过配置来设置自动做快照持久化的方式:

save 900 1    # 900秒内如果超过1个key被修改,则发起快照保存
save 300 10   # 300秒内如果超过10个key被修改,则发起快照保存
save 60 10000 # 60秒内如果超过1万个key被修改,则发起快照保存

快照的保存过程

  1. redis使用fork函数复制一份当前进程的副本;
  2. 父进程继续接受并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件。
  3. 当子进程写入完所有的数据后会用该临时文件替换旧的RDB文件,然后子进程退出。至此一次快照操作完成。

客户端也可以使用save或bgsave命令通知redis做一次快照持久化。save操作是在主线程中保存的,由于redis是用主线程来处理所有client发送的命令的,所以这种方式会堵塞client请求,另外需要注意的是,每次快照持久化都是将内存数据完整地写入到磁盘,并不是增量的只同步变更数据,所以如果数据量大的话,必然会引起大量的磁盘io操作,影响性能。

两种方式对比如下:

命令 save bgsave
IO类型 同步 异步
是否阻塞redis其他命令 否(生成子进程是调用fork函数会有短暂阻塞)
优点 不会消耗额外内存 不阻塞客户端命令
缺点 阻塞客户端命令 fork函数子进程,消耗内存

说明:配置了自动生成RDB文件后使用的是bgsave方式。

快照持久化方式有它的不足,如果一旦redis出现问题,RDB文件中保存的数据并不是全新的,从上次RDB文件生成到redis宕机这段时间的数据全部丢失掉了,在某些业务下这是可以忍受的(也推荐这些业务使用快照的方式持久化,因为开启RDB的代价并不高)。但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,快照方式就无能为力了,所以redis引入了另一个重要的持久化机制:AOF(Append-only file)。

AOF方式

AOF的全称是append only file,从名字上我们就可以看出,它是一个追加写入的文件,AOF文件是可识别的纯文本,它的内容就是一个个的redis标准命令。当然,并不是发送到redis的所有命令都要记录到AOF日志里面,只有那些会导致数据量发生变化的命令才会追加到AOF文件。

默认情况下redis没有开启AOF方式的持久化,可以通过修改配置来开启:

appendonly yes

AOF文件保存的位置和RDB文件位置相同,都是通过dir参数设置的,默认的文件名称是appendonly.aof,可以通过appendfilename参数修改:

appendfilename "appendonly.aof"

因为AOF的运行方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加,AOF文件的体积也会变得越来越大。举个例子,如果你对一个计数器调用了10次INCR,那么仅仅是为了保存这个计数的当前值,AOF文件可能就需要使用100条记录。但实际上,只使用一条set命令就已经足以保存计数器的当前值了,其余99条记录实际上都是多余的。为了处理这种情况,redis支持一种功能:可以在不打断服务客户端的情况下,对AOF文件进行重建,执行bgrewriteaof命令,redis将生成一个新的AOF文件,这个文件包含重建当前数据集所需的最少命令。redis可以自动优化AOF文件,可以在配置文件中做如下配置:

auto-aof-rewrite-percentage 100  # 当目前的AOF文件大小超过上一次重写AOF文件大小的百分之多少时才会再次进行重写,如果之前没有重写过则以启动时AOF文件的大小为依据
auto-aof-rewrite-min-size 64mb   # 允许重写的最小AOF文件大小,通常情况下该文件很小,即使有些冗余命令,我们也不太关心。

AOF方式比快照方式有更好的持久化性,是由于redis会将每一个收到的命令都追加到文件中(默认是appendonly.aof),当redis重启时通过执行文件中的写命令重建整个内存数据库内容。但需要注意的是,由于操作系统的缓存机制,数据并没有真正的写入磁盘,而是进入了硬盘缓存。在默认情况下系统每30秒会执行一次同步操作,在这30秒的过程中,如果系统异常退出则会导致数据丢失。一般选择AOF持久化的应用不能容忍这样的数据丢失,可以通过在配置文件中的配置来修改持久化策略:

appendfsync everysec
appendfsync always
appendfsync no

默认情况下redis采用everysec规则,即每秒执行一次;always表示每次写入都会执行同步,这是最安全也是最慢的方式;no表示不主动进行同步操作,而是完全交给系统来做,这也是最快但最不安全的方式。一般情况下everysec就足够了,既兼顾了性能又保证了数据的安全。

Redis 4.0 混合持久化

重启Redis时,我们很少使用RDB来恢复内存状态,因为会丢失大量数据。我们通常使用AOF日志重放,但是重放AOF日志性能相对RDB来说要慢很多,这样在Redis实例很大的情况下,启动需要花费很长的时间。Redis4.0为了解决这个问题,带来了一个新的持久化选项--混合持久化。 通过如下配置可以开启混合持久化(必须先开启aof)

aof-use-rdb-preamble yes

如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。于是在Redis重启的时候,可以先加载RDB的内容,然后再重放增量AOF日志就可以完全替代之前的AOF全量文件重放,因此重启效率大幅得到提升。

Redis数据备份策略:

  1. 写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,一般保留最近48小时的备份
  2. 每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份
  3. 每次copy备份的时候,都把太旧的备份给删了,每次备份将当前机器上的备份复制一份到其他机器上,以防机器损坏

redis适用场景

  1. 一次写入,多次读取的情况。
  2. 取最新N个数据的操作。
  3. 排行榜应用,取TOP-N操作。
  4. 计数器应用。
  5. 构建队列系统。
  6. 缓存系统。

redis使用建议

  1. key的长度最好不用太长。
  2. hash更适合存储对象。
  3. sort的集合非常大的话排序就会消耗很长时间,由于redis单线程的,所以长时间的排序操作会阻塞其他client的请求。解决办法是通过主从复制将数据复制到多个client上,然后我们只在slave上做排序操作。
  4. 如果你的redis集群需要主从复制,那么最好事先配置好所有的从库,避免中途再去增加从库(一方面slave恢复时间会非常慢,另一方面也会给主库带来压力)。
  5. 尽量避免在压力较大的主库上增加从库。
  6. 如果服务器数据压力过大,可以添加多台服务器节点。
  7. master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。如果数据比较关键,某个slave开启AOF备份数据,策略为每秒同步一次。
  8. 为了主从复制的速度和连接的稳定性,slave和master最好在同一个局域网内。

分类:

后端

标签:

后端

作者介绍

江小南
V1