[redis]持久化

目录

前言

猜想

快照

快照的痛苦的点

redis怎么做快照

快照cow

Copy On Write 机制

Linux中CopyOnWrite实现原理

CopyOnWrite的好处

Redis中的CopyOnWrite

redis的快照的疑问

RDB的几个优点

rdb的缺点

redis的内存页大小

AOF

概念

bgrewriteaof

异常宕机

定期的aof重写

一般只会在从节点进行同步备份

怎么进行aof瘦身?

总结


前言

redis的持久化可能要配合mysql的redolog 一起看理解,还有binlog。

都差不多的玩意~

回头补一下es的实现~

做事情要学会类比,学习工具里面的思想,看看能不能用到业务中去~

做一个高逼格的人 嘿嘿

猜想

如果看到过别的持久化,不管是mysql也好,还是什么mq也好,持久化目的是什么?

我觉得是

1.防止宕机之后数据丢失,保证数据的准确性;

2.宕机可以恢复;

3.类似kafka的话,宕机之后可以从offset恢复,而且有多partition机制

   类似mysql,有redolog和binlog双重保证~宕机可以恢复binlog点位,然后进行回放~

4. 有一种思想就是,我们先写log,后写数据,两阶段提交类似mysql,这样的话就不会有log写了,但是内存或者数据查不到的问题~(但是redis其实是先执行指令,再进行日志存盘的,跟别的存储引擎不太一样~)

以上是最近在复习这方面知识的一个感受~

因为以前都看过redis持久化,知道aof和rdb,所以下面就直接开始记录~

快照

RDB是一种快照存储持久化方式,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb,而在Redis服务器启动时,会重新加载dump.rdb文件的数据到内存当中恢复数据。

开启RDB持久化方式很简单,客户端可以通过向Redis服务器发送save或bgsave命令让服务器生成rdb文件,或者通过服务器配置文件指定触发RDB条件。(save是同步操作,会阻塞线上不要用哇)

注意:

快照是全量备份,AOF是增量备份;

快照是二进制序列化形式,存储紧凑,而aof日志记录是内存数据修改的指令记录文本;

(aof简直就是redolog的一毛一样的感觉)

需要定期进行aof重写,给aof日志进行瘦身;

快照的痛苦的点

1.redis单线程,线程需要同时负责多个客户端套接字的并发读写操作,和内存数据结构的逻辑读写;

2.服务器的请求同时,redis还要进行内存快照;内存快照要求redis 必须进行io操作,但是文件io操作不能用多路复用api;

3.单线程还要进行io,会严重影响性能,所以需要一遍持久化买一遍响应客户端

redis怎么做快照

使用操作系统的多进程cow (copy on write)

(所以说知识真是互通的)

cow简单描述:写的时候复制,直接映射原始盘的内容;

                         当原始盘旧数据有修改,将修改前的旧数据存入前端盘

                          对前端盘修改不会写到原始盘

一头雾水是不是,往下看

快照cow

Copy On Write 机制

核心思路:fork一个子进程,只有在父进程发生写操作修改内存数据时,才会真正去分配内存空间,并复制内存数据,而且也只是复制被修改的内存页中的数据,并不是全部内存数据;

  • Redis中执行BGSAVE命令生成RDB文件时,本质就是调用Linux中的fork()命令,Linux下的fork()系统调用实现了copy-on-write写时复制;
  • fork()是类Unix操作系统上创建线程的主要方法,fork用于创建子进程(等同于当前进程的副本);
  • 传统的普通进程复制,会直接将父进程的数据拷贝到子进程中,拷贝完成后,父进程和子进程之间的数据段和堆栈是相互独立的;
  • copy-on-write技术,在fork出子进程后,与父进程共享内存空间,两者只是虚拟空间不同,但是其对应的物理空间是同一个;

                (这个cow机制 跟kafka的零拷贝好像啊!!其实也不太像,就是都是节省拷贝的过程节省资源)

总结:copy-on-write技术,在fork出子进程后,与父进程共享内存空间,两者只是虚拟空间不同,但是其对应的物理空间是同一个,那我们就不用多冗余一份数据了

Linux中CopyOnWrite实现原理

fork()之后,kernel把父进程中所有的内存页的权限都设为read-only然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。

当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷入kernel的一个中断例程。中断例程中,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份。

(!!!所以这才是为啥叫做写时复制的原因,也就是我们如果是只读的话,我们就不复制,默认readonly,但是一旦有了更改(指的是主线程),那我们就把更改的内容复制一部分,修改的内容单独分离一个页面, 因为父子线程是readonly的, 发生了异常中断, 主线程去处理要更改的内容就好了,子线程看到的就是快照!

这样也能保证redis的子进程复制的正确~)

CopyOnWrite的好处

1、减少分配和复制资源时带来的瞬时延迟;
2、减少不必要的资源分配;
CopyOnWrite的缺点:
如果父子进程都需要进行大量的写操作,会产生大量的分页错误(页异常中断page-fault);

Redis中的CopyOnWrite

Redis在持久化时,如果是采用BGSAVE命令或者BGREWRITEAOF的方式,那Redis会fork出一个子进程来读取数据,从而写到磁盘中。
总体来看,Redis还是读操作比较多。如果子进程存在期间,发生了大量的写操作,那可能就会出现很多的分页错误(页异常中断page-fault),这样就得耗费不少性能在复制上。
而在rehash阶段上,写操作是无法避免的。所以Redis在fork出子进程之后,将负载因子阈值提高,尽量减少写操作,避免不必要的内存写入操作,最大限度地节约内存。

(因为redis是读操作比较多~rehash 写操作是必须的因为迁移了一个新的hash结构~ )

redis的快照的疑问

RDB过程中会fork一个子进程,子进程做数据备份操作,主进程继续对外提供服务,所有Redis服务不会阻塞;
Copy On Write 机制,备份的是开始那个时刻内存中的数据;准确的将,是bgsave命令执行的时候的快照,那一个时刻的。

从那一个时刻起,父子线程看到的内存内容就是一样的,从上面分析来看就是readonly的,如果主线程有请求进来要改数据了,我们就让主线程单独分离一个页面出来就好,等rdb操作完成(也许弄回去,这个我没有注意也没有看,再和回去,或者都是内存的地址也许就这样放着了~)
Copy On Write 机制不需要把整个内存的数据都复制一份,因为是写时复制

RDB的几个优点

  • 与AOF方式相比,通过rdb文件恢复数据比较快。

  • rdb文件非常紧凑,适合于数据备份。

  • 通过RDB进行数据备,由于使用子进程生成,所以对Redis服务器性能影响较小。

  • copyonwrite只是一个寻址的过程,纳秒级别的。而aof每次都是写盘操作,毫米级别。

rdb的缺点

  • 使用bgsave命令在forks子进程时,如果数据量太大,forks的过程也会发生阻塞,另外,forks子进程会耗费内存。(耗费内存,也不是一定不会发生阻塞的)

  • save同步肯定不能用

  • 需要配合aof一起用,因为rdb每次全量,太多了,容易丢失很多数据。

redis的内存页大小

一般每个页面的大小只有4kb,redis实例有成千上万个页面~

rbd因为redis读多写少,所以cow时候的复制操作并不会很多、

复制过程,越来越多的共享页面被分离出来,内存会持续增长,但是也不会超过现有数据内存的2倍大小。

AOF

AOF是增量备份;aof日志记录是内存数据修改的指令记录文本;

概念

aof是redis的顺序指令序列,aof日志只记录对内存进行修改的指令记录,

redis是先讲内存中的东西改了,执行指令之后,才进行日志存盘。这个不同于别的数据结构 比如mysql hbase

bgrewriteaof

这个指令可以进行瘦身,开辟一个子进程,然后对内存进行遍历,然后转换成一系列的redis 的操作指令,序列化到一个新的aof日志文件中。

异常宕机

因为aof日志是稳健性存在,但是程序对aof日志文件进行写操作,其实是写到 (内存缓存中),然后内核会一步的将脏数据刷会磁盘中。

如果突然宕机,aof可能没有来得及刷到磁盘,这时候日志丢失怎么办?

linux 的glibc提供的fsync 函数可以将指定的文件内容强制从内核缓存刷到磁盘。

只要redis进程实时调用这个函数就可以保证aof日志不丢失,但是fsync是一个磁盘io操作,很慢的;

所以生产服务器,redis通常是每隔一秒左右执行一次刷回磁盘,做一个折中。

(总结,aof先写道内存缓存中,之后才弄到磁盘上,防止数据丢失,应该合理的配置这个刷回的时间~)

定期的aof重写

需要定期进行aof重写,给aof日志进行瘦身;

(因为可能会有很多重复指令,需要进行瘦身的)

执行一个 AOF文件重写操作,重写会创建一个当前 AOF 文件的体积优化版本。
即使 BGREWRITEAOF 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 BGREWRITEAOF 成功之前不会被修改。
从 Redis 2.4 开始,AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。但网上有网友说已经3.2.5版本了,貌似redis还是没有自动触发BGREWRITEAOF

一般只会在从节点进行同步备份

因为主节点,遍历全部内存,会很加大系统的负担,aof的fsync是个耗时的io操作,降低性能的。

怎么进行aof瘦身?

使用rewirte机制,rewrite机制现在达到一定的条件redis会自动触发
其具体的流程就是:
1,redis主进程fork一个子进程
2,子进程根据当前内存的数据,构建一个新的日志,写入一个新的AOF文件中  (有点类似于,我把内存中有的数据,写到aof中~)
3,这段时间内,redis接收到的client的修改操作,都会在内存中新起一个日志文件去进入,并同步到旧的AOF文件中 (两个都接受者)
4,当子进程完成了任务,redis就会把新的日志文件追加到新的AOF文件中
5,使用新的AOF文件替换旧的AOF文件

总结

快照是父进程fork时的快照,触发bgsave父进程还会进行一次判断的,如果当前存在正在执行的RDB和AOF会直接返回的,如果不存在,那么父进程会阻塞,fork出子进程,因为fork的COW机制,这个子进程会有父进程fork时的内存快照。

redis是先将内存中的东西改了,执行指令之后,才进行日志存盘。这个不同于别的数据结构 比如mysql hbase

aof先写道内存缓存中,之后才弄到磁盘上,防止数据丢失,应该合理的配置这个刷回的时间~

通常线上服务是混合持久化,这样的话,把aof和rdb放到一起,不会丢失很多数据,而且重启的效率也会很高

参考:

https://www.cnblogs.com/kgdxpr/p/7155718.html

https://blog.csdn.net/lh87270202/article/details/106430154

《redis深度历险》-钱文忠

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值