首页 > 数据库 >[Redis]持久化

[Redis]持久化

时间:2024-07-06 23:30:14浏览次数:13  
标签:AOF 持久 Redis 内存 进程 快照 日志

持久化

Redis的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证Redis的数据不会因为故障而丢失,这种机制就是Redis的持久化机制。

Redis的持久化机制有两种,第一种是快照,第二种是AOF日志

快照是一次全量备份,AOF日志是连续的增量备份。
快照是内存数据的二进制序列化形式,在存储上非常紧凑,而AOF日志记录的是内存数据修改的指令记录文本。

RDB持久化通过创建内存中所有数据的快照并将其保存到磁盘上来实现。具体工作原理如下:

触发条件:
RDB持久化可以通过配置来自动触发,比如在一定时间内有一定数量的写操作时。
也可以手动触发,如通过执行 SAVE 或 BGSAVE 命令。

创建快照:
当触发RDB持久化时,Redis会生成一个数据快照文件。
如果是执行 SAVE 命令,Redis会阻塞当前所有客户端连接,直到快照生成完毕。这种方式通常不推荐在生产环境中使用,因为它会导致服务中断。
如果是执行 BGSAVE 命令,Redis会创建一个子进程,由子进程负责生成快照文件,这样可以避免阻塞主进程,保证服务的持续运行。

存储到磁盘:
子进程将数据快照写入到一个临时文件中。只有当快照完成并且数据完全写入后,临时文件才会替换旧的快照文件。
这种方式确保了快照文件的一致性,即使生成快照时发生崩溃,也不会损坏已有的快照文件。

快照原理

我们知道Redis是单线程程序,这个线程要同时负责多个客户端套接字的并发读写操作和内存数据结构的逻辑读写。
在服务线上请求的同时,Redis还需要进行内存快照,内存快照要求Redis必须进行文件IO操作,可文件IO操作不能使用多路复用API这意昧着单线程在服务线上请求的同时,还要进行文件IO操作,而文件IO作会严重拖累服务器的性能。还有个重要的问题,为了不阻塞线上的业务,Redis就需要一边持久化,一边响应客户端的请求。持久化的同时,内存数据结构还在改变,比如一个大型的hash典正在持久化,结果一个请求过来把它给删掉了,可是还没持久化完呢,这该怎么
办呢?Redis使用操作系统的多进程COW(CopyOnWrite)机制来实现快照持久化,这个机制很有意思,也很少人知道。多进程cow也是鉴定程序员知识广度的一个重要指标。

fork(多进程)

Redis在持久化时会调用glibc的函数fork产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这时你可以把父子进程想象成一个连体婴儿,它们在共享身体。这是Linux操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的瞬间,内存的增长几乎没有明显变化。
fork函数会在父子进程同时返回,在父进程里返回子进程的pid,在子进程里返回零。如果操作系统的内存资源不足pid就会是负数,表示fork失败。
子进程做数据持久化,不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到碰盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改。
image

这个时候就会使用操作系统的cow机制来进行数据段页面的分离。数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。
随着父进程修改操作的持续进行,越来越多的共享页面被分离出来,内存就会持续增长,但是也不会超过原有数据内存的2倍大小。另外,Redis实例里冷数据占的比例往往是比较高的,所以很少会出现所有的页面都被分离的情况,被分离的往往只有其中一部分页面。每个页面的大小只有4KB,一个Redis实例里面一般都会有成千上万个页面子进程因为数据没有变化,它能看到的内存里的数据在进程产生的瞬间就凝固了,再也不会改变,这也是为什Redis的持久化叫"快照"的原因。接下来子进程就可以非常安心地遍历数据,进行序列化写磁盘了。

AOF原理

AOF日志存储的是Redis服务器的顺序指令序列,AOF日志只记录对内存进行修改的指令记录。
假设AOF日志记录了自Redis实例创建以来所有的修改性指令序列,那可以通过对一个空的Redis实例顺序执行所有的指令一一也就是重放,来恢复
Redis当前实例的内存数据结构的状态。Redis会在收到客户端修改指令后,进行参数校验、逻辑处理,如果没问题,就将该指令文本存储到AOF日志中,也就是说,先执指令才将日志存盘,这点不同于leveldb,hbase等存储引擎,它们都是先存储日志做逻辑处理。

Redis在长期运行的过程中,AOF的日志会越来越长,如果实例宕机重启,重放整个AOF日志会非常耗时,导致Redis长时间无法对外提供服务,所以需要对AOF日志瘦身。

AOF重写

Redis提供了bgrewriteaof指令用于对AOF日志进行瘦身,其原理就是开辟一个子进程对内存进行遍历,转换成一系列Redis的操作指令,序列化到一个新的AOF日志文件中。序列化完毕后再将操作期间发生的增量AOF日志追加到这个新的AOF日志文件中,追加完毕后就立即替代旧的AOF日志文件了,瘦身工作就完成了。

fsync

AOF日志是以文件的形式存在的,当程序对AOF日志文件进行写操作时,实际上是将内容写到了内核为文件描述符分配的一个内存缓存中,然后内核会异步将脏数据刷回到磁盘的。

这就意昧着如果机器突然宕机,AOF日志内容可能还没有来得及完全刷到磁盘中,这个时候就会出现日志丢失。那该怎么办?
Linuxglibc提供了fsync(intfd)函数可以将指定文件的内容强制从内核缓存刷到磁盘。只要Redis进程实时调用fsync函数就可以保证AOF日志不丢失。但是fsync是一个磁盘IO操作,它很慢!如果Redis执行一条指令就要fsync一次,那么Redis高性能的地位就不保了,所以在生产环境的服务器中,Redis通常是每隔ls左右执行一次fsync操作,这ls的周期是可以配置的。这是在数据安全性和性能之间做的一个折中,在保持高性能的同时,尽可能使数据少丢失。

Redis同样也提供了另外两种策略,一个是永不调用fsync一一让操作系统来决定何时同步碰盘,这样做很不安全,
另一个是来一个指令就调用fsync一次一一结果导致非常慢。这两种策略在生产环境中基本不会使用,了解一下即可。

运维

快照是通过开启子进程的方式进行的,它是一个比较耗资源的操作。
1.遍历整个内存,大块写磁盘会加重系统负载。
2.AOFfsync是一个耗时的IO操作,它会降低Redis性能,同时也会增加系IO负担。

所以通常Redis的主节点不会进行持久化操作,持久化操作主要在从节点进行。从节点是备份节点,没有来自客户端请求的压力,它的操作系统资源往往比较充沛。但是如果出现网络分区,从节点长期连不上主节点,就会出现数据不一致的问题,特别是在网络分区出现的情况下,主节点一旦不小心看机了,那么数据就会丢失,所以在生产环境下要做好实时监控工作,保证网络畅通或者能快速修复。另外还应该再增加一个从节点以降低网络分区的概率,只要有一个从节点数据同步正常,数据也就不会轻易丢失。

Redis4.0混合持久化|

重启Redis时,我们很少使用rdb来恢复内存状态,因为会丢失大量数据。我们通常使用AOF日志重放,但是重放AOF日志相对于使用rdb来说要慢很多,这样在Redis实例很大的时候,启动需要花费很长的时间。
Redis4.0为了解决这个问题,带来了一个新的持久化选项一一混合持久化。如所示,将rdb文件的内容和增量的AOF日志文件存在一起。这里的AOF日志不再是全量的曰志,而是自持久化开始到持久化结束的这段时间发生的增量AOF志,通常这部分AOF日志很小。
image

标签:AOF,持久,Redis,内存,进程,快照,日志
From: https://www.cnblogs.com/DCFV/p/18288075

相关文章

  • [Redis]扩容
    原因扩容原因:当hashtable存储的元素过多,可能由于碰撞也过多,导致其中某链表很长,最后致使查找和插入时间复杂度很大。因此当元素超多一定的时候就需要扩容。缩容原因:当元素数量比较少的时候就需要缩容以节约不必要的内存。为了让哈希表的负载因子(loadfactor)维持在一个合理的范围......
  • [Redis]ZSet
    通过value查score在Redis的有序集合(zset)中,通过成员(member)获取其对应的分数(score)的复杂度是O(logN),其中N是有序集合中的元素数量。这是因为Redis使用跳跃表(skiplist)和哈希表(hashtable)的组合来实现有序集合。跳跃表用于按顺序存储元素,以便高效地按分数排序和查找范围,而哈......
  • Redis 高阶应用
    生成全局唯一ID全局唯一ID需要满足以下要求:唯一性:在分布式环境中,要全局唯一高可用:在高并发情况下保证可用性高性能:在高并发情况下生成ID的速度必须要快,不能花费太长时间递增性:要确保整体递增的,以便于数据库创建索引安全性:ID的规律性不能太明显,以免信息泄......
  • Redis主从复制实验
    实验环境系统:Linuxmaster(主库):192.168.1.2slave(从库):192.168.1.6两台服务器均安装好Redis数据库,安装步骤点这里开始搭建主从复制环境之前,确认防火墙是否开启,firewall-cmd--list-all实验步骤在slave下的配置进行配置,进入到/usr/local/bin下,viredis.conf配置redis.conf......
  • Redis的zset的zrem命令可以做到O(1)吗?
    事情是这样的,当我用zrem命令去移除value的时候,我知道他之前会做的几个步骤1、查找这个value对应的score(通过zset中的dict)2、根据这个score查找到跳表中的节点3、删除这个节点我就想了一下为什么dict为什么要保存score呢?如果保存的是跳表中的节点,那么不就可以做到删除O(1)......
  • 数据持久化-关系型数据库
    基于SQLite组件提供的本地数据库,用于管理应用中的结构化数据用户首选项只能在轻量级数据中进行数据持久化,复杂的数据就需要用到关系型数据库三步使用:1.初始化数据库2.增删改数据3.查询数据1.初始化数据库1)导入关系型数据库模块importrelationalStorefrom'@ohos.data.re......
  • Redis的数据类型
    1、五种常见的数据类型       String            String类型的三种格式                字符串                int              ......
  • 深入刨析Redis存储技术设计艺术(一)
    一、RedisObject1.1、Redis数据存储1.2、RedisObject的数据结构redis的value都封装在redisObject中redisObject的底层实现:redisObject的数据结构如下:server.htypedefstructredisObject{ unsignedtype:4; unsignedencoding:4; unsignedlru......
  • Pinia 实用教程【Vue3 状态管理】状态持久化 pinia-plugin-persistedstate,异步Action,s
    什么是状态管理?全局状态Store(如Pinia)是一个保存状态和业务逻辑的实体,与组件树没有绑定,有点像一个永远存在的组件,每个组件都可以读取和写入它。三大核心概念state属性——相当于组件中的datagetter计算属性——相当于组件中的computedaction操作属性的......
  • Redis 清理日志文件的策略
    目录Redis清理日志文件的策略1.Redis日志文件2.日志清理策略定期归档压缩归档文件设置日志文件大小限制注意事项结论Redis清理日志文件的策略在使用Redis时,日志文件可能会不断增长,占用磁盘空间。为了保持良好的系统性能和合理利用磁盘空间,我们需要实施一定的......