重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
今天就跟大家聊聊有关redis中持久化RDB和AOF的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
为德州等地区用户提供了全套网页设计制作服务,及德州网站建设行业解决方案。主营业务为成都网站设计、成都网站建设、德州网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
RDB基础知识
RDB文件存在是以一个压缩后的二进制文件,这个RDB文件一般是保存在Redis安装目录下,通过启动Redis服务器执行rdbLoad函数加载RDB文件,执行rdbSave函数保存RDB文件。
RDB保存
rdbSave函数负责将内存中的数据库数据以RDB格式保存到磁盘中,如果RDB文件已存在,那么新的RDB文件将替换已有的RDB文件,SAVE和BGSAVE两个命令都会调用rdbSave函数。
SAVE直接调用rdbSave,阻塞Redis主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。
BGSAVE则开启一个子进程,子进程负责调用rdbSave,Redis服务器在BGSAVE执行期间仍然可以继续处理客户端的请求,并在保存完成之后向主进程发送信号,通知保存已完成。
注意:执行保存命令时Redis不会再次执行save、bgsave、bgrewriteaof等命令,因为如果执行这些命令会存在资源抢占使备份出现意想不到的bug。
自动隔离保存
此时我们的小伙伴意识到,我们不能每次都执行命令手动保存或者执行定时器执行命令,这样会导致可用性降低,那么Redis提供自动保存的配置
####100秒内对Redis进行10次以上的修改save 100 10####一小时内对Redis进行至少1000次的修改save 3600 1000###只要满足上面任何一个要求则执行bgsave命令
那么Redis源代码中保存这个配置的是在redisServer中的一个saveparam的结构,代码如下:
struct saveparam { teme_t seconds; //秒 int changes; //修改数}
save我们这里就不分析了,因为它直接阻塞主线程把Redis数据直接写入磁盘文件,所以我们这对bgsave进行讲解,前面说了bgsave是开启一个子进程进行文件的操作,那么此时的Redis主进程还在响应客户端的命令,那么我们的Redis如何保证数据完整性和性能呢?
Redis在持久化的时候会fork产生一个子进程,持久化过程完全交给子进程,而父进程则响应客户端的命令,子进程创建时不会立即保存文件因为这会与父进程产生资源抢占,它的指针指向父进程的内存空间与父进程共享内存,这样为了更加节约资源。
此时父进程是会读写内存中的数据,子进程只是读取资源并不会写,此时Redis使用操作系统的多进程COW(Copy On Write)机制进行数据段页面的分离,每页数据不会超过4K,我们把这个数据称之为冷数据,父进程进行修改的时候我们只需要把共享的页数据复制出来对其进行修改,而不在原数据上进行修改,冷数据没有任何的变化。子进程现在可以安心的对冷数据进行持久化,此时我们持久化的内容就像是被拍了照一样固定下来,这就是快照的整个过程。
这里值得注意的是随着时间的推移,父进程修改的页也会越来越多,理论上这个复制出来的内存能达到之前数据内存,所以我们在设计缓存的时候尽可能的少改数据。
Redis还有一个持久化操作那就是AOF(Append Only File),AOF是将客户端的修改指令保存下来追加到服务器状态的aof_buf缓冲区尾部,最后保存到AOF日志文件。举个例子。
首先,前面我们讲过Redis的通讯协议RESP,我们这里把客户端的指令转换成这种协议
>set name mango####保存到aof_buf缓冲区*3\r\n$3\r\nset\r\n$4\r\name\r\n$5\r\mango\r\n
然后我们将协议文本追加到aof_buf末尾
最后我们把这些指令信息保存至AOF日志文件中
AOF保存模式
每当服务器常规任务函数被执行、或者事件处理器被执行时,aof.c/flushAppendOnlyFile函数都会被调用,这个函数执行以下两个工作:
WRITE:根据条件,将aof_buf中的缓存写入到AOF文件。
SAVE:根据条件,调用fsync或fdatasync函数,将AOF文件保存到磁盘中。
Redis目前支持三种AOF保存模式:
1. AOF_FSYNC_NO:不保存,操作系统来决定什么时候保存保存。
2. AOF_FSYNC_EVERYSEC:每一秒钟保存一次。
3. AOF_FSYNC_ALWAYS:总是保存,每执行一个命令保存一次。
这三种模式从上到下执行速度越来越慢,安全性越来越高,如果使用no模式,那么恢复数据会恢复到上次备份,如果是everysec最多会丢失一秒,而always只会丢失一个指令。所以我们考虑使用哪种AOF模式取决于我们的业务需求综合考虑。
关于fsync
AOF日志是以文件的形式存在的,当我们的AOF从缓冲区写入AOF文件中时服务器突然宕机,此时我们的文件还没有完全写入磁盘,这时我们该如何处理呢?
fsync函数可以将指定文件的内容强制从内核缓存刷到磁盘。只要Redis进程实时调用fsync函数就可以保证AOF日志不失。但是fsync是一个磁盘IO操作,so它很慢。如果Redis执行一条指令就要fsync一次,那么可想而知Redis的性能就会拉下一大截 。
所以在生产环境的服务器中,Redis通常是每隔1s左右执行一次fsync操作,这个1s的周期是可以配置的。这是在数据安全性和性能之间做的一个折中,在保持高性能的同时,尽可能使数据少丢失。
Redis同样也提供了另外两种策略,一个是永不调用fsync让操作系统来决定何时同步碰盘,这样做很不安全,另一个是来一个指令就调用fsync一次——结果导致非常慢。这两种策略在生产环境中基本不会使用。
AOF重写
我们的AOF一直累加进行持久化,随着时间的推移备份文件会越来越大,甚至影响我们对Redis的恢复和操作,Redis也提供重写机制,下面我们来看看
>set name zhangsan>set name mango>set name lisi...>set name mango####优化后>set name mango
我们可以看到经常会对一个key进行多次修改,那么我们可以把这个key的最后一次操作保存起来这样我们就轻易的给AOF"瘦身"。当然我们还有一种方式,就是遍历整个Redis,set每个key和它的值,也跟RDB全备一样我们需要一个子进程读取当前的Redis库。
这里会出现一个问题,我们如果是遍历整个Redis需要考虑此时的客户端必定会有指令更改里面的值,此时我们怎么保证AOF重写后不丢下重写后的指令呢?
操作步骤:
AOF创建一个子进程进行AOF重写,其指定内存跟主进程一致
客户端执行写命令,主线程处理指令,指令追加到AOF缓冲区,并且追加到AOF重写缓冲区
AOF重写完成后替换现有的AOF文件
那么为什么会把这个指令同时追加到AOF缓冲区和AOF重写区呢?原因是如果我们在重写的时候突然服务器挂了,那么我们AOF文件中会保存这个指令。追加到AOF缓冲区是为了保证操作指令能及时同步到AOF重写区。AOF重写操作也就是之前提到过的bgrewriteaof。
Redis4.0为了解决这个问题,带来了一个新的持久化选项一一混合持久化。将RDB文件的内容和增量的AOF日志文件存在一起。这里的AOF日志不再是全量的曰志,而是自持久化开始到持久化结束的这段时间发生的增量AOF日志,通常这部分AOF日志很小。
在Redis重启的时候,可以先加载RDB,然后再重放增量AOF日志,就可以完全替代之前的AOF全量文件重放,重启效率因此得到大幅提升。
总结一下:
Redis持续化操作包括RDB和AOF
RDB保存的是一个压缩二进制文件,AOF保存的是操作指令文件
Redis优先恢复AOF,因为它比较全,Redis4.0采用混合模式来恢复
RDB执行bgsave时和AOF重写一样,开启一个子进程,他们的内存与父进程共享
AOF有三种保存模式,no不主动保存依赖操作系统调度;everysec一秒执行一次;always每次执行一个指令保存一次。
AOF保存模式主要是fsync函数,保证AOF日志不会丢失
看完上述内容,你们对Redis中持久化RDB和AOF的原理是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注创新互联行业资讯频道,感谢大家的支持。