
这个专栏,为大家介绍一些常用的中间件。今天介绍在实际开发过程中使用频率较高的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被修改,则发起快照保存
快照的保存过程:
客户端也可以使用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的全称是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时,我们很少使用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全量文件重放,因此重启效率大幅得到提升。
本文由mdnice多平台发布