zoukankan      html  css  js  c++  java
  • redis的数据持久化策略

    redis提供了两种不同的持久化方法来将数据存储到硬盘里面。一种方法叫快照,它可以将存在于某一时刻的所有数据都写入硬盘里面。另一种方法叫只追加文件(AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面。这两种持久化方法既可以同时使用,又可以单独使用,在某些情况下甚至可以两种方法都不用,具体选择哪种持久化方法,需要根据用户的数据及应用来决定。

    快照持久化

    redis可以通过创建快照来获得在内存里面的数据在某个时间点上的副本。在创建快照之后,用户可以对快照进行备份,可以将快照复制到其他的服务器从而创建具有相同数据的服务器副本,还可以将快照留在原地以便重启服务器使用。

    触发RDB持久化可以分为:手动触发和自动触发两种模式!

    触发机制:

      手动触发分别对应save命令和bgsave命令

    • save命令:阻塞当前redis服务器,知道RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,显示环境不建议使用。
    • bgsave命令: redis进程执行fork操作创建子进程,rdb持久化由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。很明显bgsave命令是针对阻塞问题做的优化。因此redis内部所有涉及RDB的操作都采用bgsave的方式,而save命令已经废弃。

    除手动触发外,redis可以使用save命令配置redis内部的自动触发机制,如下:

    快照的配置如下:

    save 60  1000
    stop-srites-on-bgsave-error no
    rdbcompression on
    dbfilename  dump.rdb

    创建快照的几种方法:【虽然是save命令,但是触发的是bgsave操作】

    1. 客户端可以通过向redis发送bgsave命令来创建一个快照。对于支持bgsave命令的平台来说(除windows外),redis会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,二父进程继续处理命令请求。
    2. 客户端还可以通过redis发送save命令来创建一个快照,接到save命令的redis服务器在快照创建完毕之前将不再响应其他任何命令。save命令并不常用,我们通常只会在没有足够内存去执行bgsave命令的情况下,又或者即使等到持久化操作执行完毕也无所谓的情况下,才会使用这个命令。
    3. 如果用户设置了save配置选项,譬如save 60 10000, 那么从redis最近一次创建快照操作之后开始算起。当“60s内有10000次写入”这个条件被满足时,redis就会自动触发bgsave命令。如果用户设置了多个save配置选项,那么当任意一个save配置选项所设置的条件被满足时,redis就会触发一次bgsave命令。
    4. 当redis通过shutdown命令接收到关闭服务器的请求时,或者接受到标准term信号时,会执行一个save命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在save命令执行完毕之后关闭服务器。
    5. 当一个redis服务器连接另一个redis服务器,并向对方发送sync命令来开始一次复制操作的时候,如果主服务器目前没有在执行bgsave操作,或者主服务器并非刚刚执行完bgsave操作,那么主服务器就会执行bgsave命令。
    6. 执行debug reload命令重新加载redis时,也会自动触发save操作。

    在只使用快照持久化来保存数据时,一定要记住:如果系统真发生崩溃,用户将丢失最近一次生成快照之后的更改的所有数据。因此,快照持久化只适用于那些即使丢失一部分数据也不会造成问题的应用程序。

    bgsave执行流程:

    bgsave是主流的触发rdb持久化方式,执行流程如下:

    1. 执行bgsave命令,redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF进程,如果存在bgsave命令直接返回。
    2. 父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作耗时,单位为微妙。
    3. 父进程fork完成后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。
    4. 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
    5. 进程发送信号给父进程表示完成,父进程更新统计信息。

    运维提示:

      1:rdb文件的位置可以在线动态修改,可以使用config set dir指定rdb文件的位置,使用config set dbfilename执行文件名。

      2:redis默认采用LZF算法对生成的rdb文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以使用config set rdbcompression动态修改。虽然压缩rdb会消耗cpu,但可大幅度降低文件体积,方便保存到硬盘或通过网络发送给从节点,因此线上建议开启。

    RDB的优缺点:

      RDB是一个紧凑压缩的二进制文件,代表redis在某个时间点上的数据快照。非常适用于备份,全量恢复等场景。redis加载rdb恢复数据远远快于AOF方式。

    RDB的缺点:

      RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作常见子进程,属于重量级操作,频繁执行成本过高。RDB文件使用特定的二进制格式保存,redis版本演进过程中有多个格式的RDB版本,存在老版本redis服务无法兼容新版本rdb格式的问题。

    AOF持久化

    简单来说,AOF持久化会将被执行的写命令写到AOF文件的末尾,以此来记录数据发生的变化。因此,redis只要从头到尾重新执行一次AOF文件包含的所有写命令,就可以恢复AOF文件所记录的数据集。AOF持久化可以通过设置如下选项来打开。AOF的主要作用是解决了数据持久化的实时性,目前已经是redis持久化的主流方式。

    appendonly  no                                 #是否开启aof持久化
    appendfsync everysec
    no-appendfsync-on-rewrite no
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size  64mb
    
    dir  ./                                       #这个参数决定来持久化文件保存的位置
    appendfsync参数有三个选项:
    always: 每个redis写命令都要同步写入硬盘,这样会严重降低redis的速度。
    everysec: 每秒执行一次同步,显式地将多个写命令同步到硬盘。
    no : 让操作系统来决定应该何时进行同步。

    aof处理流程如下:

    1. 所有的写入命令追加到aof_buf(缓冲区)中。
    2. aof缓冲区根据对应的策略向硬盘做同步操作。
    3. 随着aof文件越来越大,需要定期对aof文件进行重写,达到压缩的目的。
    4. 当redis服务器重启时,可以加载aof文件进行数据恢复。

    *1:aof命令写入的内容直接是文本协议格式;文本协议有很好的兼容性;开启aof后,所有写入命令都包含追加操作,直接采用协议格式,避免了二次处理开销。文本协议具有可读性,方便直接修改和处理。

    *2:aof为什么吧命令追加到aof_buf中?redis使用单线程相应命令,如果每次写aof文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。先写入aof_buf中,还有另一个好处,redis可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡。

    aof_buf同步到磁盘的策略,可以使用appendfsync参数来控制!

    • 如果使用always选项的话,那么每个redis写命令都会被写入硬盘。从而将发生系统崩溃时出现的数据丢失减少到最少。不过遗憾的是,因为这种同步策略需要对硬盘进行大量写入,所以redis处理命令的速度会受到硬盘性能的影响;机械硬盘在这种同步频率下每秒只能处理大约200个写命令,而固态硬盘每秒大概也只能处理几万个写命令。(使用固态硬盘慎用always选项,因为不断写入少量数据做法可能会引发严重的写入放大问题)。【命令写入aof_buf后调用系统fsync操作同步到aof文件,fsync完成后线程返回】
    • 为来兼顾数据安全和写入性能,可以考虑用everysec选项,让redis以每秒一次的频率对aof文件进行同步。redis每秒同步一次aof文件时的性能和不适用任何持久化特性时的性能相差无几,而通过每秒同步一次aof文件,redis可以保证,即使出现系统崩溃,用户也最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,redis还会优雅地放慢自己的速度以便使用硬盘的最大写入速度。【命令写入aof_buf后调用系统write操作,write操作完成后线程返回。fsync同步文件由专门线程每秒调用一次】【建议使用】
    • 如果使用来no选项,那么redis将不对aof文件执行任何显式的同步操作,而是由操作系统来决定应该在何时对aof文件进行同步。这个选项在一般情况下不会对redis的性能带来影响,但系统崩溃将导致使用这种选项的redis服务器丢失不定数量的数据。另外,如果用户的硬盘处理写入操作的速度不够快,那么当缓冲区被等待写入硬盘的数据被填满时,redis的写入操作将会被阻塞,并导致redis处理命令请求的速度变慢。【命令写入aof_buf后调用系统write操作,不对aof文件做fsync同步,同步硬盘操作由操作系统负责,通常同步周期最长为30s】

    *3:重新机制

    随着命令不断写入AOF,文件会越来越大,为了解决这个问题,redis引入了aof重写机制压缩文件体积。aof文件重写使redis进程内的数据转化为写命令同步到新aof文件的过程。

    重写后aof文件为什么可以表小?

    • 进程内已经超时的数据不再写入文件。
    • 旧aof文件包含无效命令,如del key1, del key2, srem keys, set all 等。重写使用进程内数据直接生成,这样的新的aof文件只保留最终数据的写入命令。
    • 多条写命令可以合并为一个,如:lpush list a,lpush list b可以转换为lpush a b。为了防止单条命令过大造成客户端缓冲区溢出,对于list,set,hash,zset等类操作,以64个元素为界拆分为多条。

    aof重写降低了文件占用空间,除此之外,另一个目的:更小的aof文件可以更快第被redis加载。

    aof重写过程可以手动触发或自动触发:

    • 手动触发:直接调用bgrewriteaof命令
    • 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机。

    aof持久化可以通过设置auto-aof-rewrite-percentage选项和auto-aof-rewrite-min-size选项来自动执行bgrewriteaof。默认的配置如下:

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

    #那么当aof文件的体积大于64MB,并且aof文件的体积比上一次重写之后的体积大至少一倍(100%)的时候,redis将执行bgrewriteaof命令。如果aof重写执行得过于频繁的话,用户可以考虑将auto-aof-rewrite-percentage选项的值设置为100以上,
    #这种做法可以让redis在aof文件的体积变得更大之后才执行重写操作,不过也会让redis在启动时还原数据集所需的时间变得更长。

    自动触发机制:aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size减去aof_base_zise)/aof_base_size>=auto-aof-rewrite-percentag
    其中:aof_current_size和aof_base_size可以在info命令统计信息中查看

    AOF重写流程

      1:执行aof重写请求,如果当前进程正在执行aof重写,请求不执行并且返回如下响应:

    ERR Background append only file rewriting already in progress

      如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再执行,返回如下响应:

    Background append only file rewriting scheduled

      2:父进程执行fork创建子进程,开销等同于bgsave过程。

      3.1: 主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入aof缓冲区并根据appendfsync策略同步到硬盘,保证原有aof机制正确。

      3.2:由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,redis使用‘AOF重写缓冲’保存这部分数据,防止新AOF文件生成期间丢失这部分数据。

          4:子进程根据内存快照,按照命令合并规则写入到新的AOF文件。每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘过多造成硬盘阻塞。

       5:新aof文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。父进程把aof重写缓冲区的数据写入到新的aof文件,使用新aof文件替换老文件,完成aof重写。

    redis重启加载流程:

      1:aof持久化开启并存在aof文件时,优先加载aof文件。

      2:aof关闭或者aof文件不存在时,加载rdb文件。

      3:加载aof/rdb文件成功后,redis启动成功。

      4:aof/redis文件存在错误时,redis启动失败并打印错误信息。

    验证快照文件和aof文件

    无论是快照持久化还是aof持久化,都提供了在遇到系统故障时进行数据恢复的工具。redis提供来两个命令行程序redis-check-aof和redis-check-dump,它们可以在系统故障发生之后,检查aof文件和快照文件的状态,并在有需要的情况下对文件进行修复。

    [root@test2 redis]# redis-check-aof 
    Usage: redis-check-aof [--fix] <file.aof>
    [root@test2 redis]# redis-check-rdb 
    Usage: redis-check-rdb <rdb-file-name>
    [root@test2 redis]# 

    如果用户在运行redis-check-aof程序时给定了--fix参数,那么程序将对aof文件进行修复。程序修复aof文件的方法非常简单:它会扫描给定的aof文件,寻找不正确或者不完整的命令,当发现第一个出错命令的时候,程序会删除出错的命令以及位于出错命令之后的所有命令,只保留那些位于出错命令之前的正确命令。在大多数情况下,被删除的都是aof文件末尾的不完整的写命令。

  • 相关阅读:
    Windows 10 搭建Python3 安装使用 protobuf
    [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)
    [Python爬虫] 在Windows下安装PIP+Phantomjs+Selenium
    [Python爬虫] Selenium自动访问Firefox和Chrome并实现搜索截图
    [Python爬虫] Selenium实现自动登录163邮箱和Locating Elements介绍
    [Python爬虫] Selenium+Phantomjs动态获取CSDN下载资源信息和评论
    [Python爬虫] Selenium获取百度百科旅游景点的InfoBox消息盒
    [Python] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题
    [python爬虫] Selenium定向爬取海量精美图片及搜索引擎杂谈
    [Python爬虫] scrapy爬虫系列 <一>.安装及入门介绍
  • 原文地址:https://www.cnblogs.com/wxzhe/p/10683459.html
Copyright © 2011-2022 走看看