Redis做持久化之RDB

    技术2022-07-10  121

    Redis如何做持久化? redis是内存形数据库,一旦服务器进程退出数据库数据就会丢失,为了解决这个问题,redis主要提供了三种持久化方案,将内存中的数据保存到磁盘中,避免数据丢失。 RDB(快照)持久化:在特定的间隔保存该时间点的全量数据的快照

    在redis.cof文件中可以查看RDB持久化的策略: save 900 1 在900秒内如果有一条写入指令,就触发产生一次快照 save 300 10 在300秒内有10条写入,进行一次备份 save 60 10000 在60秒内有一万条写入,进行一次备份

    stop-writes-on-bgsave-error yes 当备份进程出错时,主进程停止接受新的写入操作,保护持久化数据一致

    rdbcompression yes RDB文件压缩 可设置save “” 将RDB的配置禁用

    src文件夹下有dump.rdb,redis系统会定时将全量数据保存生成dump.rdb文件(二进制文件)

    RDB的创建与载入: SAVE:阻塞Redis的服务器进程,直到RDB文件被创建完毕 save很少被使用,因为save操作是在主线程中保存快照的,由于redis是用一个主线程处理所有的请求,这种方式会阻塞所有client的请求。 BGSAVE:Fork出一个子进程来创建RDB文件,不阻塞服务器进程 BGSAVE会派生出及Fork出一个子进程来创建新的RDB文件,记录接受BGSAVE当时的数据库状态,父进程继续处理接收到的命令,子进程完成文件的创建后会发送信号给父进程也就是我们redis主进程。父进程处理命令的同时通过轮询接收子进程的信号,BGSAVE指令是用后台的方式保存RDB文件,调用此命令后,会立刻返回OK返回码,redis会产生一个子进程进行处理并立刻恢复对客户端的服务,在客户端我们可以使用lastsave指令查看操作是否成功。lastsave记录了上一次成功执行save或BGSAVE命令的时间。

    手工触发RDB持久化: 自动化触发RDB持久化: 根据redis.conf配置里的SAVE m n 定时出发(用的是BGSAVE) 主从复制时,主节点自动出发 执行Debug Reload 执行Shutdown且没有开启AOF持久化

    BGSAVE原理: 在执行BGSAVE指令之后,首先会去检查当前主进程有没有正在执行的IOF或者RDB子进程,有则返回错误。这样做是为了防止子进程之间的竞争,也就意味着在执行BGSAVE期间客户端发送的SAVE,BGSAVE命令会被服务器拒绝执行; 如果没有发现相关子进程,则会触发持久化。这时候会调用redis源码里面rdbsavebackground()方法,执行fork系统调用。 fork指令是用来创建进程的,而linux下fork系统调用实现了cope-on-write写时复制。传统方式下fork函数在创建子进程时,直接把所有资源复制给子进程,这种实现方式简单但是效率低下,而且复制的资源可能对子进程毫无用处。linux为了降低创建子线程的成本,改进fork实现方式,当父进程创建子进程时,内核只为子进程创建虚拟空间,父子两个进程使用的是相同的物理空间,只有父子进程发生更改时才会为子进程分配独立的物理空间。 此种改进方式我们称为“写时复制”(cope-on-write),简称COW。它是一种计算机程序设计里面的优化策略,其核心思想是,如果有多个调用者同时请求相同资源,例如内存或磁盘上的数据存储,他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本给该调用者,而其他调用者所见到的最初资源仍然保持不变,这个过程对其他的调用者是透明的。此做法的主要优点是如果调用者没有修改该资源就不会有副本被创建,因此多个调用者支持读取操作时可以共享同一份资源。

    COW的处理过程中需要维持一个为读请求使用的指针,并在新数据写入完成后更新这个指针以提升读写并发能力,因此COW也间接提供了数据更新过程中的原子性。在保证数据的完整性的同时还保证了一定的读写效率,当redis需要做持久化时,redis会fork一个子进程,子进程将数据写到磁盘上一个临时的RDB文件中,当子进程完成写临时文件之后,将原来的RDB替换掉,这样的好处就是可以实现cope-on-write,子进程继续接受其他请求,确保了redis的性能。

    当redis需要做持久化的时候,redis会调用fork创建出子线程,父进程继续处理client的请求,子进程负责将内存内容写入到临时文件中,由于OS的copy-on-write机制,父子进程会共享相同的物理页面,当父进程处理写请求时,OS会为父进程要修改的页面创建副本而不是写共享的页面,所以子进程的地址空间内的数据是fork时刻的整个数据库的一个快照。当子进程完成了临时文件的写入之后,用临时文件替换掉原来的快照文件,然后子进程退出进而完成一次备份操作。

    RDB文件的载入一般情况下是自动的,redis服务器再启动的时候如果检测到RDB文件的存在那么redis会自动占用这个文件。

    需要注意的是:每次快照持久化都是将内存数据完整地写入到磁盘一次,并不是增量的只同步脏数据,如果数据量大的话,并且写操作比较多的时候,必然会引起大量的磁盘IO操作,可能会严重影响性能。另外由于快照方式是在一定间隔时间做一次的,快照后的所有修改,如果应用要求不能丢失任何修改的话,可以采用另外一种持久化方式AOF。

    Processed: 0.010, SQL: 9