Redis: RDB与AOF的选择和容灾备份以及Redis数据持久化的优化方案

如何选择RDB和AOF

1 )同时开启

  • 在我们 Redis 的服务器上,把RDB和AOF同时打开, 这样可以通过RDB快速的恢复数据,因为它是一个紧凑的缩缩的二进制文件, 但是有时 Redis 的不小心故障了,丢失了十几分钟的数据

  • 可以通过AOF来做数据的恢复, 因为它所有写命令都会记录,Redis先加载AOF文件来恢复原始数据,因为AOF数据比RDB更完整,有时候我们会把一些错误的命令也记录在文件中, 会有一些潜在的bug,可以通过 redis-check-aof 来做修复,如果AOF文件实在是用不了,恢复不了,可以把RDB作为一种后备数据来使用,这就是最常用的一种方式

  • 为了考虑性能,可以只在Slave上开启RDB,并且15min备份一次,因为在主从模式下让从节点去实现持久化,其实也是可以达到避免数据丢失的这样的一个效果,如果为了避免 AOF rewite的IO以及阻塞,可以在Redis集群中不开启AOF, 靠集群的备份机制来保证可用性,在启动时选取较新的RDB文件,如果集群全部崩溃,会丢失15min前的数据

2 )混合模式

  • Redis4.0开始支持该模式
  • 解决的问题:Redis在重启时通常是加载AOF文件,但加载速度慢
  • 因为 RDB 数据不完整,所以加载 AOF
  • 开启方式:aof-use-rdb-preamble true
  • 开启后,AOF在重写时会直接读取RDB中的内容
  • 运行过程:通过 bgrwriteaof 完成,不同的是当开启混合持久化后
    • 子进程会把内存中的数据以RDB的方式写入aof中
    • 把重写缓冲区中的增量命令以AOF方式写入到文件
    • 将含有RDB个数和AOF格数的AOF数据覆盖旧的AOF文件
  • 新的AOF文件中,一部分数据来自RDB文件,一部分来自Redis运行过程时的增量数据

3 ) 数据恢复

  • 当我们开启了混合持久化时,启动Redis依然优先加载aof文件,aof文件加载可能有两种情况如下:
    • aof文件开头是rdb的格式,先加载 rdb内容再加载剩余的 aof
    • aof文件开头不是rdb的格式,直接以aof格式加载整个文件
  • 优点:既能快速备份又能避免大量数据丢失
  • 缺点:RDB是压缩格式,AOF在读取它时可读性较差

二者动态切换

  • 在Redis 2.2或以上版本,可以在不重启的情况下,从RDB切换到AOF:

    • 为最新的dump.rdb文件创建一个备份
    • 将备份放到一个安全的地方 cp dump.rdb dump.rdb.bak
  • 执行以下两条命令:

    sh 复制代码
    # 开启 aof
    redis-cli config set appendonly yes
    # 关闭 rdb
    redis-cli config set save ""
  • 确保写命令会被正确地追加到AOF文件的末尾

  • 执行的第一条命令开启了AOF功能:

    • Redis会阻塞直到初始AOF文件创建完成为止,所以不要在高峰期做这个事情
    • 之后Redis会继续处理命令请求,并开始将写入命令追加到AOF文件末尾

Redis容灾备份

1 ) 开启RDB持久化

conf 复制代码
save 900 1
save 300 10
save 60 10000

2 ) 开启AOF配置

conf 复制代码
# 开启 aof
appendonly yes
appendfilename "appendony. aof"

# rewrite
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# appendfsync always
appendfsync everysec
# appendfsync no

3 ) RDB日志备份,编写脚本定时备份

  • vim bin/redis-rdb-copy-per-hour.sh

    conf 复制代码
    #!bin/bash
    cur_date=$(date "+%Y%m%d%H%M%S")
    rm -rf /usr/local/redis/snapshotting/$cur_date
    mkdir -p /usr/local/redis/snapshotting/$cur_date
    cp /usr/local/redis/data/dump.rdb /usr/local/redis/snapshotting/$cur_date
    
    del_date=$(date -d -48hour "+%Y%m%d%H%M")
    rm -rf /usr/local/redis/snapshotting/$del_date
    • 备份与删除48小时之前的
  • 使用 crontab 定时器执行备份脚本

    • 确保机器上有定时任务服务 $ systemctl status crond 可看到定时服务是运行的状态

    • 默认linux都会集成 crond 服务,没有启动,进行 start 即可

    • 现在编写定时任务 :$ crontab -e

    • 下面写入 (以下为每分钟执行一次,生产环境可调整为每小时执行一次)

      conf 复制代码
      */1 * * * * sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
      */1 * * * * sleep 10; sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
      */1 * * * * sleep 20; sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
      */1 * * * * sleep 30; sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
      */1 * * * * sleep 40; sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
      */1 * * * * sleep 50; sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
      • 这里虽然每分钟执行一次,但是加上了 sleep 用来演示阻塞的效果,仅仅是演示
      • */1 表示"每 1 分钟",而其余的星号分别代表小时、日期、月份和星期几,这里用星号表示任意值
      • 生产环境配置如:0 * * * * sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh 每小时执行一次
    • 查看定时任务列表 $ crontab -l

    • 到时间后,检查是否生成相应的备份

  • 这样就实现了通过脚本来实现了容灾备份

  • 考虑到恢复,则考虑到 redis 进程挂掉了

    • 基于 aof 和 rdb 文件恢复即可
    • 如果 aof 文件损坏了,可以通过机器上最新时间段的rdb副本来恢复

Redis 持久化的优化方案

1 )独立部署

  • 因为Redis 的RDB和AOF文件生成的这个过程,除了会对内存和硬硬盘造成压力之外
  • 它其实都是属于一个CPU密集型的操作,所以最好是把 Redis 单独部署在一台服务器上
  • 不要和其他的存储服务, 例如关系数据库或者说消息队列服务部署在一起
  • 消息队列和关系数据库本来就会有大量的磁盘IO
  • 再加上 Redis 的话,可能磁盘和CPU就会受不了
  • 选择独立部署,其实就是为了解决子进程的频繁开销的问题

2 ) 硬盘优化

  • 可以根据写入量来决定,比如当前这个 Redis 的服务器,它有大量的写入请求的话
  • 可以决定是否使用性能更高的SSD的磁盘

3 ) 缓存禁用持久化

  • 如果我们业务的Redis 它的定位就是做缓存
  • 缓存的数据肯定是在别的地方都已经有的,即使它丢失了也不要紧
  • 这个缓存备份,就是AB两套缓存:比如,A缓存失效了,马上B缓存顶上去
  • 只需要把这种方案做好就行, 持久缓存的数据丢失了,是不需要考虑的
  • 因为这个缓存的数据肯定是在关系数据库里边都有的,丢失了也不要紧
  • 所以说这种场景下,就可以把 Redis 这个节点的持久化功能,直接给它禁用掉
  • 这样它从关系数据库加载提供缓存的服务就可以了

4 ) 主从模式从持久化

  • 从模式主从模式从节点的数据是从主节点复制的
  • 因为从节点我们一般是不会开启写模式的,也就是它是只读的
  • 它是写不进去数据的,它的数据都是通过主节点复制过去的
  • 但是它每次从主节点复制数据的时候,首先会主节点进行一次BGSAVE的操作
  • 然后跟磁盘交互一下,生成RDB的快照,然后再把快照发给从节点,这就是一次复制的过程
  • 如果从节点频繁的跟主节点进行复制,那么主节点这边肯定会压力比较大
  • 因为它频繁的在fork 进程去做RDB快照生成这件事情
  • 这样可以考虑,把主节点的持久化给它关闭掉, 从节点来做持久化
  • 比如说,从节点,15分钟备份一次,只需要在从节点上添加一个 save 900 1 就可以了
  • 甚至可以把AOF也给它禁用掉,因为 master/slave 主从已经高可用了,数据是不可能丢失的
  • 因为15分钟内,假如说某一节点的数据丢失了,但还有其他的节点还在工作着
  • 所以说不可能像之前单节点十几分钟的一个很长的窗口期,当掉了,数据全丢了
  • 也可以考虑AOF的禁用,那就又节省掉了一大笔的IO的行为
  • 因为AOF它在 rewrite 的时候肯定会带来一个系统的波动,因为AOF的同步策略默认情况下是每秒
  • 每一次的同步实际上都是它要去把这些数据从缓冲区写到一个AOF文件里边
  • 最后会覆盖掉原来的那个AOF文件,它是这样去做的
  • 新浪微博的架构就是
    • 主从模式, 从节点备份
    • 然后关闭主节点AOF提高性能

5 ) 优化 fork 处理

  • 这个优化就是降低 AOF 的重写频率
  • RDB它虽然是子进程 fork 在做这件事情,但是RDB毕竟是一个很长的时间窗口期才会去做这件事儿
  • 所以,降低重写频率,说的无非就是我们开启了AOF的情况
  • 比如说,现在已经超过64m了,它就会rewrite,在rewrite的这个过程中,它肯定是会影响到性能的
  • 那我们把 rewrite的执行的这个时间给它拉长,即把重写上限调高,比如从 64m 到 5g
  • 这样就可以降低rewrite的一个触发的频率
  • 这样,也会提高我们的性能,降低 fork 子进程的一个创建
  • 还有一个AOF的配置优化,在重写的时候,要不要去执行正常的追加操作
    • 如果说在它重写的这个期间段内,本来就已经带来阻塞了
    • 然后我还让它去正常进入我们正常的一些命令
    • 这个时候它又要去folk进程去做这件事,开销销比较大的
    • 我们可以把这个 no-appendfsync-on-rewrite 选项改为 yes ,(默认是 no)
    • 改为yes之后,AOF 重写段内不去执行接收正常命令追加的这个行为
    • 这样的话,它就会专心去做 rewrite,rewrite做完才会继续接受命令
    • 这个方案不好的地方就是重写期间的数据可能会丢失,需要根据具体生产环境
    • 包括你的服务器CPU硬盘各方面因素来决定的,如果你的硬盘是能扛得住的
    • 你的服务器性能是比较好的,就可以忽略,这个选项不要去禁用
    • 让它在重写期间仍然可以执行正常的追加就可以了
相关推荐
ketil272 小时前
Ubuntu 安装 redis
redis
王佑辉3 小时前
【redis】redis缓存和数据库保证一致性的方案
redis·面试
Karoku0664 小时前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
gorgor在码农4 小时前
Redis 热key总结
java·redis·热key
想进大厂的小王4 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
Java 第一深情4 小时前
高性能分布式缓存Redis-数据管理与性能提升之道
redis·分布式·缓存
minihuabei9 小时前
linux centos 安装redis
linux·redis·centos
monkey_meng11 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
hlsd#12 小时前
go 集成go-redis 缓存操作
redis·缓存·golang
奶糖趣多多14 小时前
Redis知识点
数据库·redis·缓存