暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis 持久化

老码农空杯修行记 2020-09-02
208
快照
原理

快照,就是给当前redis在内存中的数据进行拍照片,一般有条件触发拍照,比如执行save、bigsave 或某段时间内满足了写条件都会触发,当服务器重启时,根据照片将内容恢复到内存,这就是快照。

快照流程

  1. 触发快照功能,比如执行了BGSAVE命令
  2. 判断是否有子进程在进行RDB持久化
  3. 有子进程在持久化则返回,到此结束本次持久化
  4. 无子进程持久化,则fork一个子进程
  5. 子进程开始从共享内存读取数据写入临时文件
  6. 临时文件写完之后调用rename系统函数重命名临时文件为dump.rdb, rename会删除原来的dump.rdb

  7. 子进程处理快照的同时父进程继续为客户端提供服务
再次理解快照
快照如拍照片,是拍照此刻的画面,此刻之后画面的变动不在照片内,redis主进程在fork子进程时,父进程和子进程会共享物理内存,只不过子进程得到的是到这块物理内存的虚拟映射,此时此刻这块内存画面就定格了,子进程就操作定格的这部分内存,之后的变动不会影响子进程,这由linux的写时复制机制保障。

写时复制

  • 父进程原来映射的物理空间 page-1, page-2, page-3

  • fork子进程并执行exec,此时相当于对内存拍了照片,父子进程映射同一块内存空间,内存页引用计数加1

  • 父进程执行写操作,写的内容假设在page-2,此时发生写时复制,page-2的数据会被拷贝到page-4,然后写page-4,同时父进程断开到page-2的映射,page-2引用计数减1

  • 父子进程共享page-1,3,其它各自管理

  • 假设子进程结束,对应子进程的内存会根据引用计数回收

到此就容易理解了,redis子进程在快照持久化时,父进程为啥还能继续接收请求而不影响子进程

触发快照的方式

  • 客户端向Redis发送BGSAVE命令:开辟子进程,只有在开辟子进程时短暂拒绝客户端请求,一旦子进程启动,正常处理客户请求

  • redis 配置触发

    save 10 1 # 10s 内发生一次写操作,触发BGSAVE


    # 快照允许且一旦发生快照持久化失败时,若此选项开启
    # redis将不再处理客户端写请求,一旦失败恢复,依然
    # 会恢复接收写请求,若不再乎数据持久化失败丢失的问题
    # 可以设置该选项为 no,从而即便持久化失败也正常提供
    # 服务
    stop-writes-on-bgsave-error yes


    # 是否开启LZF算法压缩字符串,若开启将会有更多cpu占用率
    # 设置为no,节省cpu,但持久化的文件更大,cpu和空间的一个
    # 折中,根据实际业务场景选择
    rdbcompression yes


    # 是否开启 CRC64 校验,开启后,持久化存储时
    # 会计算 CRC64, 并将校验码写入到快照文件件的
    # 末尾,加载时也会再次校验持久化文件,一旦校验
    # 失败,不会加载文件。开启时在持久化和加载时有
    # 10% 性能损耗
    rdbchecksum yes


    # 持久化文件的名称,默认 dump.rdb
    dbfilename dump.rdb


    # 持久化文件默认路径
    dir var/lib/redis
    复制
    • 客户端向Redis发送SAVE命令:SAVE命令与BGSAVE不同之处是,SAVE不开辟子进程,而是主进程直接执行持久化,此时不接收客户端请求,一般BGSAVE内存不足是用SAVE方法
    • redis-server 接收到SHUTDOWN命令或是TERM信号是,开启SAVE命令,进行持久化,此时会短暂阻止进程结束,直到持久化完毕
    • 节点被设置为从,并发送同步进行数据同步时,主节点会触发

    问题

    快照是某一个时刻的内存全貌,一旦服务器挂了,那就丢失了上一次快照结束后到最近的数据,因此要权衡业务是否接受数据的丢失,比如业务接受最近10分钟数据的丢失,可以配置

      save 600 1
      复制
      AOF
      原理

      AOF是将写操作命令追加到一个文件,重启或恢复时,只要执行一遍文件中的命令就可以恢复数据。

      AOF配置

        # 是否开启 AOF
        appendonly yes


        # AOF 文件名称
        appendfilename "appendonly.aof"


        # 操作系统如何何时将缓冲区数据刷到磁盘
        # no 操作系统决定何时刷新到磁盘,此时redis性能最好
        # always 每条写后都刷新,最安全,性能最弱
        # everysec 每秒刷新一次
        # appendfsync always
        appendfsync everysec
        # appendfsync no


        # 其它进程执行BGSAVE,BGREWRITEAOF 时是否停止
        # 执行刷新命令 fsync()
        no-appendfsync-on-rewrite no


        # 当AOF文件的体积比上一次重写之后的体积大了至少
        # 一倍且AOF文件体积大于64mb时执行 BGREWRITEAOF
        auto-aof-rewrite-percentage 100
        auto-aof-rewrite-min-size 64mb
        复制

        append写

        写分为三个步骤,调用write写,然后写入缓冲区,最后当缓冲区满、close或者调用flush触发flush操作,将缓冲区的数据刷到磁盘上

        怎么刷盘,redis中由 appendfsync 配置决定,其各配置都有优缺点,根据实际业务折中:
        • always每条写操作都刷盘,安全性高,数据丢失最少,但是性能最低,对于ssd磁盘很致命

        • no操作系统自己决定,性能特别好,但是一旦服务挂掉,导致不定条数的数据丢失,可能丢失少,也可能一个缓冲区的数据全丢了

        • everysec每秒刷一次盘,性能和安全的一个折中

        AOF 文件重写

        不停的append有一个问题,看下面的命令

          lacr_r1:6379> set a 1
          OK
          lacr_r1:6379> set a 2
          OK
          lacr_r1:6379> set a 1
          OK
          lacr_r1:6379> set a 3
          OK
          复制
          在看持久化文件
            root@lacr_r1:/var/lib/redis# cat appendonly.aof


            # 第一条命令
            set      # 命令
            $1       # 键长度
            a        # 键
            $1       # 值长度
            1        # 值
            *3
            $3
            ----------------------------
            set
            $1
            a
            $1
            2
            *3
            $3
            ------------------------------
            set
            $1
            a
            $1
            1
            *3
            $3
            ------------------------------
            set
            $1
            a
            $1
            3


            复制

            结果四条命令全部append文件中持久化文件中了,导致持久化文件越来越大,浪费磁盘空间,因此应该尽可能的压缩,此时可以向redis发送 BGREWRITEAOF 命令:

              lacr_r1:6379> BGREWRITEAOF
              Background append only file rewriting started


              root@lacr_r1:/var/lib/redis# cat appendonly.aof
              SET
              $1
              a
              $1
              3
              *2
              $6
              复制
              执行 BGREWRITEAOF 之后会对数据进行压缩,压缩之后4条命令变成一条,减小了文件大小。
              BGREWRITEAOF原理
              • 触发 BGREWRITEAOF
              • 判断有无AOF的子进程,有则退出,无则继续
              • 判断有无RDB的子进程,有则退出,无则继续
              • FORK子进程,将内存中的数据合并压缩刷新到临时AOF文件temp-rewriteaof-bg-进程id.aof

              • 父进程继续接收客户端请求
              • 子进程结束,父进程判断退出状态,若子进程正常退出,父进程将自己写入的数据刷新到temp-rewriteaof-bg-进程id.aof

              • 父进程调用rename将临时文件重命名为appendonly.aof,并删除临时aof文件
              文章转载自老码农空杯修行记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论