Redis RDB及AOF持久化

1、Question1:什么叫持久化?(What)

持久化是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存)。

2、Question2:Redis不就是数据库吗,为什么要持久化?(Why)

Redis确实是一个数据库,但它是基于内存的数据库。
类似于你用代码写了个变量String a = 123 这个a在程序运行时存入内存中,等程序停止,你还能找到a吗?显然是不行的。
所以Redis需要有一个持久化的功能,将它存储的数据记到硬盘上。

3、Question3:Redis如何进行持久化?(How)

Redis为了能把数据写到硬盘中,它提供了两种持久化功能,分别是RDB (redis database)、AOF (append only file)。下面是对两种方法的说明。

3.1、RDB持久化是什么?

RDB持久化是将Redis数据库中的数据快照进行备份,将内存中的数据库状态保存至磁盘,避免数据丢失。


image.png

RDB

3.2、RDB持久化怎么做?

RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行。

1、手动执行

手动执行有两个命令可以选择,save bgsave
save 命令会阻塞Redis服务器进程,直到RDB文件创建完毕。阻塞期间,服务器不能处理任何命令。这个命令估计没人敢用。

save命令

bgsave 命令是非阻塞的,它会创建一个子进程,由子进程负责创建RDB文件,服务器进程继续处理命令请求,这个命令看着比较靠谱。

bgsave

很明显,bgsave命令执行后,客户端会收到"Background saving started",并且可以执行命令。bgsave命令执行期间,客户端发送的savebgsave命令会被服务器拒绝。
用伪代码表示:

def SAVE():
      # 创建RDB文件
       rdbSave()

def BGSAVE():
      # 创建子进程
     pid = fork() ;
     if pid ==  0 :
         # 子进程负责创建RDB文件
         rdbSave()
         # 完成后向父进程发送信号
         signal_parent()
     elif pid > 0:
         # 父进程继续处理命令请求,并通过轮询等待子进程的信号
         handle_request_and_wait_signal() 
     else:
         # 处理出错情况
          handle_fork_error()
2、服务器配置

Redis允许用户通过设置服务器配置的save选项(这个不是指save命令),让服务器每隔一段时间自动执行一次bgsave命令。 save选项可以被配置多个,只要有一个条件满足,就会执行bgsave命令。配置文件为redis.conf。在文件中可以找到以下配置:

save 900 1
save 300 10
save 60 10000

该配置表示只要满足以下三个条件中的任意一个,bgsave命令就会被执行:

  • 服务器在900秒之内,对数据库进行了至少1次修改。
  • 服务器在300秒之内,对数据库进行了至少10次修改。
  • 服务器在60秒之内,对数据库进行了至少10000次修改。
    将save选项改为save 60 1,往数据库写入一条数据,可以看到日志会输出以下信息:
    log
3、RDB文件如何载入?

将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可,redis在启动时就会自动加载文件数据至内存了。Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。查看启动日志。


log
4、RDB持久化的优势与劣势

优势:

  • RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。
  • 生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
  • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

劣势:

  • RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁执行成本过高(影响性能)
  • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题(版本不兼容)
  • 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)
5、RDB持久化的原理

Redis有个服务器状态结构:

struct redisService{
     //1、记录保存save条件的数组
     struct saveparam *saveparams;
     //2、修改计数器
     long long dirty;
     //3、上一次执行保存的时间
     time_t lastsave;
}
struct saveparam{
     //秒数
     time_t seconds;
     //修改数
     int changes;
};

saveparams属性是一个数组,数组中的每个元素都是一个saveparam结构,当设置save选项为以下条件时:

save 900 1
save 300 10
save 60 10000

saveparams数组是如下结构:

saveparams

dirty计数器记录距离上次执行save命令或者bgsave命令后,服务器进行了多少次修改(写入、删除、更新等)
lastsave属性是一个UNIX时间戳,记录上一次成功执行save或者bgsave 命令的时间。
通过这两个属性,服务器没执行一次修改,就将dirty计数器加一。成功执行save或者bgsave命令后,将执行时间记录到lastsave属性中。
服务器有个周期性函数serverCron默认每隔100毫秒就会执行一次。它有一项工作就是检查save选项所保存的条件是否满足,满足的话,就执行一次bgsave命令。
伪代码表示:

def serverCron():
      #....
      #遍历所有保存条件
      for saveparam in server.saveparams:
            #计算距离上次保存操作有多少秒
            save_interval = unixtime_now() - server.lastsave ;
            # 如果数据库状态的修改次数超过条件所设置的次数
            # 并且距离上次保存的时间超过条件所设置的时间
            # 那么执行操作
            if server.ditry >= serverparam.changes and 
                save_interval > server.seconds:
                BGSAVE()
#....

3.3、AOF持久化是什么?

AOF(Append only file) 持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。


aof

3.4、AOF持久化怎么做

将redis.conf配置项appendonly no改为appendonly yes,重启redis即可。

image.png

3.5、AOF原理

AOF持久化分为三个步骤 命令追加(append)、文件写入、文件同步(sync)
这里有很多人会迷惑,文件写入跟文件同步的区别两个难道不是一个操作吗?

对用户而言,是一个操作,就是将内容写入文件。但是操作系统为了提高效率,会将写入数据暂时保存在一个内存缓存中,等到缓存区被填满或者到了一定时间时,才将数据写入到磁盘中。所以,如果只是将数据写入文件而不同步,还是存在丢失数据的风险。

当AOF持久化功能打开后,服务器在执行完一个写命令后,会以协议格式将命令保存至redisServer的aof_buf缓冲区中。

struct redisServer{
   //aof缓冲区
    sds aof_buf ;
}

AOF有个配置参数appendfsync是决定什么时候将aof_buf缓冲区的数据写入和保存到AOF文件里面。有三个参数可选:


image.png
参数 描述
always 将aof_buf缓冲区的所有内容写入并同步到AOF文件中。每个事件循环都执行效率最慢,安全性最高。宕机时丢失数据会最少,会丢一个事件循环的数据。
everysec 默认选项。将aof_buf缓冲区的所有内容写入到AOF文件中,如果距离上次同步AOF文件超过一秒钟,再次同步。宕机时,有可能会丢失一秒钟数据。
no 这个配置项不是说不保存数据,而是每个事件循环都将aof_buf缓冲区的所有内容写入到AOF文件,是否同步取决于操作系统。速度最快,宕机时丢的数据最多。

3.5、AOF存在的问题

1. AOF存在的问题

AOF不同于RDB持久化,RDB保存的都是有效数据,而AOF保存的是执行命令,随着服务器运行,AOF文件会越来越大,这是它的一个弊端。
例如,RPUSH list "a" "b" RPUSH list "c" "d"
RDB只会保存数据list a b c d一条记录,AOF会保存两条命令。

2. AOF重写,解决AOF文件过大问题

redis提供一种方式可以解决上面的问题:AOF重写
就是每隔一段时间重新生成新的AOF文件代替现有的AOF文件。新的AOF文件不需要去对现有的AOF文件进行任何操作,它是通过读取数据库状态实现的。有两个参数会触发AOF重写,当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。一般都设置为3G,64M太小了。

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

AOF重新会从数据库中读取键现有的值,然后用一条命令去记录键值对。
例如,RPUSH list "a" "b" RPUSH list "c" "d"
现有的AOF是保存了两条命令,AOF重写文件会用一条命令代替上面的两条命令,所以新的AOF文件会比现有的AOF文件占用空间小。

3. AOF重写问题

redis将AOF重新程序放到子进程里进行,不至于影响主线程,但随之而来会存在一个问题,子进程在AOF重新期间,新的命令无法进入子线程被写入AOF文件中。

4. AOF重写缓存区,解决AOF重写过程中无法保存新命令问题

redis为了解决重写的这个问题,设置了一个AOF重写缓冲区,它会记录AOF重写期间的命令,在子进程完成重写后,将AOF重写缓冲区的命令写入新的AOF文件中,并替换现有的AOF文件。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 一、Redis高可用概述 在介绍Redis高可用之前,先说明一下在Redis的语境中高可用的含义。 我们知道,在w...
    空语阅读 1,593评论 0 2
  • 本文档翻译自http://redis.io/topics/persistence。 这篇文章提供了 Redis 持...
    daos阅读 690评论 0 10
  • Redis 持久化: 常用的两种持久化 提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF. RDB 持...
    边学边记阅读 1,125评论 0 1
  • 邸鸣一直漫无目地的走着,一包烟抽完了,天也黑了,肚子也开始叫了,今夜真的无法想象。 邸鸣在公园里...
    无为0阅读 733评论 0 1