Redis 高可用之持久化

Redis服务实例宕机后,其中的数据还能恢复吗?

是的,与其他内存数据库不同(如memcache没有持久化),redis还提供了数据持久化功能,并提供两种持久化方式:

  • AOF(append only file):逻辑文件,记录的是一条一条的更改命令。在进行数据恢复时,需要一条一条的重放日志,恢复速度较慢
  • RDB(read database):物理文件,把某一时刻内存中的数据写入到磁盘,类似于一个快照。在进行数据恢复时,直接将快照文件加载到内存中,恢复速度快

redis默认使用RDB的方式,异步的将数据写入到磁盘中。

AOF

AOF默认为关闭状态(appendonly no),需要手动开启(appendonly yes)。

# 开启aof
appendonly yes
# aof文件名
appendfilename "appendonly.aof"
# 持久化文件目录,aof+rdb
dir ./
# 进行数据恢复时,在 AOF 文件的开头追加 RDB 文件内容,加快数据恢复速度,减少AOF重放
aof-use-rdb-preamble yes

写入方式

在MySQL中,写日志的方式往往是写前日志(Write Ahead Log, WAL),即先写日志,再更新内存中的数据。Redis中不同的是,采用的写入方式为写后日志,即先更新内存中的数据,再写日志。

这是为什么呢?首先,在速度上,写后日志的速度快于写前日志,但写前日志可支持事务回滚、恢复等事务特性。而redis作为NoSQL更关注于速度,不支持事务回滚、恢复等,所以采用写后日志提供处理速度。

写入策略

我们知道AOF是在命令执行完后再写入日志,那么写入日志是同步写入还是异步写入呢?同步写入可以保证数据一致性,但是影响处理性能,有阻塞主线程的风险;异步写入速度最快,但是有数据不一致的风险(宕机,日志没写入磁盘)。其中的优劣需要根据实际应用去把握,为此,redis提供了三种写入策略:

  • always:立即同步写回,每个写命令执行完后,同步地将日志写回磁盘,速度慢、但能保证一致性
  • everysec:每秒同步写回,每个写命令执行完后,先把日志写到 AOF 文件的内存缓冲区,主线程每隔一秒把缓冲区中的内容写入磁盘,速度中等、宕机损失一秒内数据更改信息
  • no:异步写回,由操作系统控制,每个写命令执行完后,先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘,速度最快、宕机损失的数据也最多

Redis的默认策略是everysec

# appendfsync always
appendfsync everysec
# appendfsync no

AOF日志重写

随着执行的命令数量增加、写入的日志大小也同步增加。为了减小日志的大小,使用一个异步线程对AOF日志进行重写。重写原理是,合并多条更新命令为一条。例如对一个key进行了六次更新,保存了六条日志,重写后只保存最新的一条即可。相关配置如下

# 设置 AOF 重写的触发条件,指定 AOF 文件大小增长的百分比,例如从32mb增加到64mb
auto-aof-rewrite-percentage 100
# 设置 AOF 重写的触发条件,指定最小 AOF 文件大小
auto-aof-rewrite-min-size 64mb

RDB

RDB是将数据库某一时刻的数据当作一个快照文件写入到磁盘中,这就引出了一个问题,什么时候执行RDB?

执行策略

redis中相关的配置格式为save ,其中seconds表示时间范围,changes表示key的更改数量。save 300 100的意思是如果300s内,有至少100个key的更改,就执行一次RDB操作。

可以配置多个save,符合任一条配置都可以立即执行RDB,例如,默认的save配置有三个:

  • save 3600 1
  • save 300 100
  • save 60 10000
# 执行策略
save 300 100

# 快照文件名
dbfilename dump.rdb

# 持久化文件目录,aof+rdb
dir ./

# 校验rdb文件,默认yes
rdbchecksum yes

# 压缩rdb文件,默认yes
rdbcompression yes

# 子线程执行RDB失败后,则拒绝接受写请求,用以提醒用户RDB无法正常工作
# 默认为yes,在有监控运维时可设置为no
stop-writes-on-bgsave-error no

写入策略

假设当前redis中有2GB的数据,以什么方式将2GB的数据保存到磁盘上呢?

为了不阻塞主线程,自然只能使用子线程进行异步保存了。具体操作是主线程fork一个子线程,这个子线程共享主线程的内存,可以访问其中的数据。

异步保存?那岂不是可以加快RDB的执行频率了。

这也是不可取的,

  • 一是:磁盘的写入速率较慢,会增加磁盘压力
  • 二是:虽然保存快照是异步的,但是主线程fork子线程这个操作是同步的,并且内存数据越大,fork时间越长

异步保存快照文件时,内存中的数据还能进行更改吗?变了还能叫做快照吗?

能更改,但是快照还是那个快照,这一切通过写时复制(Copy-On-Write, COW)技术完成。

写时复制

子线程在保存快照文件时,从客户端传来了请求

  • 如果是读取请求,没有影响,主线程从内存中读取后返回
  • 如果是写请求,主线程在进行更改前,需要将值拷贝一个副本出来,供子线程使用

通过写时复制,可以保证在子线程异步保存快照文件时,不影响主线程处理客户端请求。

如何选择持久化方式?

redis中可以单独使用AOF和RDB,也可以一起使用,具体的配置需要根据实际应用进行选择。

在主从架构中,主库不进行持久化,在从库中进行持久化操作。

不需要持久化

可以在redis.conf中配置save "",表明不使用持久化

需要持久化,但可以忍受几分钟的数据丢失

使用默认的RDB配置即可

不能忍受长时间的数据丢失

使用AOF,并配置appendfsync everysec(要求高可配置为always),配合RDB一起使用,可以在确保数据一致性的基础上加快数据恢复速度。

posted @   cd_along  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示