zoukankan      html  css  js  c++  java
  • Redis 持久化

    Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,例如:

    (1) 将Redis作为数据库使用(存储历史数据)。

    (2) 将Redis作为缓存服务器使用,如果缓存被穿透后会对性能造成很大影响,所有缓存同时失效会导致缓存雪崩,从而使服务器无法响应。

    这时,我们希望Redis能将数据从内存中以某种方式同步到硬盘中,当服务器重启后可以根据硬盘中的记录恢复数据,这一过程就是持久化。

    写操作的流程

    首先我们来看一下数据库在进行写操作时到底做了哪些事,主要有下面五个过程。

    1.客户端向服务端发送写操作(数据在客户端的内存中)

    2.数据库服务端接收到写请求的数据(数据在服务端的内存中)

    3.服务端调用write(2) 这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)

    4.操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)

    5.磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)

    写操作大致有上面5个流程,下面我们结合上面的5个流程看一下各种级别的故障。

    •当数据库系统故障时,这时候系统内核还是OK的,那么此时只要我们执行完了第3步,那么数据就是安全的,因为后续操作系统会来完成后面几步,保证数据最终会落到磁盘上。

    •当系统断电,这时候上面5项中提到的所有缓存都会失效,并且数据库和操作系统都会停止工作。所以只有当数据在完成第5步后,机器断电才能保证数据不丢失,在上述四步中的数据都会丢失。

    通过上面5步的了解,可能我们会希望搞清下面一些问题:

    •数据库多长时间调用一次write(2),将数据写到内核缓冲区

    •内核多长时间会将系统缓冲区中的数据写到磁盘控制器

    •磁盘控制器又在什么时候把缓存中的数据写到物理介质上

    对于第一个问题,通常数据库层面会进行全面控制。而对第二个问题,操作系统有其默认的策略,但是我们也可以通过POSIX API提供的fsync系列命令强制操作系统将数据从内核区写到磁盘控制器上。对于第三个问题,好像数据库已经无法触及,但实际上,大多数情况下磁盘缓存是被设置关闭的。或者是只开启为读缓存,也就是写操作不会进行缓存,直接写到磁盘。建议的做法是仅仅当你的磁盘设备有备用电池时才开启写缓存。

    所谓数据损坏,就是数据无法恢复,上面我们讲的都是如何保证数据是确实写到磁盘上去,但是写到磁盘上可能并不意味着数据不会损坏。比如我们可能一次写请求会进行两次不同的写操作,当意外发生时,可能会导致一次写操作安全完成,但是另一次还没有进行。如果数据库的数据文件结构组织不合理,可能就会导致数据完全不能恢复的状况出现。

    这里通常也有三种策略来组织数据,以防止数据文件损坏到无法恢复的情况:

    1.第一种是最粗糙的处理,就是不通过数据的组织形式保证数据的可恢复性。而是通过配置数据同步备份的方式,在数据文件损坏后通过数据备份来进行恢复。

    2.另一种是在上面基础上添加一个操作日志,每次操作时记一下操作的行为,这样我们可以通过操作日志来进行数据恢复。因为操作日志是顺序追加的方式写的,所以不会出现操作日志也无法恢复的情况。

    3.更保险的做法是数据库不进行老数据的修改,只是以追加方式去完成写操作,这样数据本身就是一份日志,这样就永远不会出现数据无法恢复的情况了。

    针对上述数据库写操作流程及数据库文件组织策略,我们来认识Redis的持久化

    Redis支持两种方式的持久化

    一种是RDB(快照)方式,一种是AOF(追加文件)方式。可以单独使用其中一种或将二者结合使用。

    RDB

    RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程即为“快照”。Redis会在一下几种情况下对数据进行快照:

    1. 根据配置规则进行自动快照。
    2. 用户执行save或者bgsave命令。
    3. 执行flushall命令。
    4. 执行复制时。

    根据配置规则进行自动快照

    你可以配置保存点,使Redis如果在每N秒后数据发生了M次改变就保存快照文件。例如下面这个保存点配置表示每60秒,如果数据发生了1000次以上的变动,Redis就会自动保存快照文件:

    save 60 1000

    保存点可以设置多个,Redis的配置文件就默认设置了3个保存点:

    # 格式为:save <seconds> <changes>

    # 可以设置多个。

    save 900 1 #900秒后至少1个key有变动

    save 300 10 #300秒后至少10个key有变动

    save 60 10000 #60秒后至少10000个key有变动

    如果想禁用快照保存的功能,可以通过注释掉所有"save"配置达到,或者在最后一条"save"配置后添加如下的配置:

    save ""

    文件路径和名称

    默认Redis会把快照文件存储为当前目录下一个名为dump.rdb的文件。要修改文件的存储路径和名称,可以通过修改配置文件redis.conf实现:

    # RDB文件名,默认为dump.rdb。

    dbfilename dump.rdb

    # 文件存放的目录,AOF文件同样存放在此目录下。默认为当前工作目录。

    dir ./

    用户执行save或者bgsave命令

    除了让Redis进行自动快照外,当进行服务器重启,手动迁移以及备份的时候我们也需要手动执行快照操作,redis提供了两命令:

    save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。

    一般来说,在生产环境很少执行 SAVE 操作,因为它会阻塞所有客户端,保存数据库的任务通常由 BGSAVE 命令异步地执行。

    bgsave 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。

    客户端可以通过 LASTSAVE 命令查看最近一次成功执行快照的时间,返回一个unix时间戳。

    Flushall命令

    flushall清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。注意:无论清空数据库的过程是否触发了自动快照条件,只要自动快照条件不为空,redis就会执行一次快照。例如:当定义快照条件为1秒内修改10000个键时进行快照,而是据库只有一个健,执行flushall也会触发快照,即使这一过程只有一个健被修改。当没有定义自动快照条件时,执行fluahall命令不进行快照。

    执行复制

    当设置了主从模式时,redis会在复制初始化时进行自动快照,即使没有自定义自动快照条件,并且没有手动执行过快照操作,也会生成RDB快照文件。

    快照原理

    1.redis 使用 fork 命令复制一份当前进程(父进程)的副本(子进程)

    2.父进程继续接受并处理客户端发来的命令,而子进程开始将内存的数据存储写入硬盘的临时文件

    3.当子进程写入完所有数据后调用将临时文件替换旧的 RDB 文件,到这里一次快照结束。

    RBD 明显的不足就是一旦数据库出现崩溃之类的,RDB 里保存的数据可能不是最新的,从上次 RDB 到 redis 停机这段时间的数据可能会丢失。

    AOF

    Redis 将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件, 以此达到记录数据库状态的目的为了方便起见, 我们称呼这种记录过程为同步。

    开启AOF方式持久化:

    appendonly  yes

    AOF文件的保存位置和RDB文件位置相同,默认appendonly.aof,可通过appendfilename参数修改:

    Appendfilename  appendonly.aof

    同步硬盘数据

    根据“写的操作流程”可知,虽然每次执行更改数据库内存操作时,AOF都会将命令记录在AOF文件中,但是根据操作系统缓存机制,数据并没有真正地写入硬盘。一般来讲启用AOF的应用无法容忍这样的损失,这就需要Redis在写入AOF文件后主动将系统缓存同步到硬盘中。

    Redis 可以通过appendfsync 参数设同步的时机:

    #appendfsync   always   #每次执行都同步

    appendfsync   everysec  #每秒执行一次同步,默认

    #appendfsync   no      # 不主动同步操作,由操作系统决定(30秒一次)

    Redis 允许同时开启AOF和RDB,重启时会使用AOF文件恢复数据,因为AOF方式可能丢失的数据更少。

    从上面看出,RDB和AOF操作都是顺序IO操作,性能都很高。而同时在通过RDB文件或者AOF日志进行数据库恢复的时候,也是顺序的读取数据加载到内存中。所以也不会造成磁盘的随机读。

    到底选择什么呢?下面是来自官方的建议:
    通常,如果你要想提供很高的数据保障性,那么建议你同时使用两种持久化方式。如果你可以接受灾难带来的几分钟的数据丢失,那么你可以仅使用RDB。
    很多用户仅使用了AOF,但是我们建议,既然RDB可以时不时的给数据做个完整的快照,并且提供更快的重启,所以最好还是也使用RDB。
    在数据恢复方面:
    RDB的启动时间会更短,原因有两个:
    一是RDB文件中每一条数据只有一条记录,不会像AOF日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。
    另一个原因是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不需要再进行数据编码工作,所以在CPU消耗上要远小于AOF日志的加载

  • 相关阅读:
    分布式系统笔记
    Paxos算法细节详解(一)
    Java G1学习笔记
    Spring Boot 的 10 个核心模块
    k8s 重点
    毕玄:阿里十年,从分布式到云时代的架构演进之路
    netty原理解析
    JVM调优总结(一):基本概念
    《快学 Go 语言》第 16 课 —— 包管理 GOPATH 和 Vendor
    Oracle 检查表空间使用情况
  • 原文地址:https://www.cnblogs.com/zhangzhi19861216/p/4721846.html
Copyright © 2011-2022 走看看