网站模板提供源码,成都有哪些设计公司,东莞品牌网站制作公司,小游戏制作开发目录
介绍
RDB
RDB生成方式
自动触发
手动触发
AOF#xff08;append-only file#xff09;
Redis 4.0 混合持久化
Redis主从工作原理
总结 介绍 Redis提供了两个持久化数据的能力#xff0c;RDB Snapshot 和 AOF#xff08;Append Only FIle#xff09;…目录
介绍
RDB
RDB生成方式
自动触发
手动触发
AOFappend-only file
Redis 4.0 混合持久化
Redis主从工作原理
总结 介绍 Redis提供了两个持久化数据的能力RDB Snapshot 和 AOFAppend Only FIle日志RDB快照能够在指定的时间间隔内生成数据快照而AOF日志则记录了所有的写操作命令。RDB做镜像全量持久化AOF做增量持久化。
RDB RDB全称Redis Database Backup file (Redis数据备份⽂件也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。 当Redis实例故障重启后从磁盘读取快照⽂件恢复数据。这样一来即使故障宕机快照文件也不会丢失数据的可靠性也就得到了保证。它会在特定的时间点对数据库的全部数据进行快照这个快照⽂件称为 RDB文件(dump.rdb)默认是保存在当前运⾏⽬录。其中RDB就是Redis DataBase的缩写是一个二进制文件。
RDB生成方式 自动触发
1. 配置文件中满足默认备份配置条件实际上执行的是bgsave命令 save 900 1 #900 秒之内对数据库进行了至少 1 次修改save 300 10 #300 秒之内对数据库进行了至少 10 次修改save 60 10000 #60 秒之内对数据库进行了至少 10000 次修改
# The filename where to dump the DBdbfilename dump.rdb #默认的rdb文件名dir ./ #指定rdb目录,这里代表的是当前目录 2. 执行flushall/flushdb命令也会产生dump.rdb文件只不过生成的是空文件无意义 3. 执行shutdown且没有开启 AOF 持久化也会触发 RDB 持久化 4. 主从复制时主节点自动触发。 手动触发 在客户端手动执行 save/bgsave会触发 RDB 持久化。save会阻塞当前Redis服务不推荐使用bgsave会fork出子线程执行 RDB 持久化不会阻塞推荐使用 执行了 save 命令就会在主线程生成 RDB 文件由于和执行操作命令在同一个线程所以如果写入 RDB 文件的时间太长会阻塞主线程导致Redis不能处理其他命令因此线上禁止使用。 命令bgsave执行后会立刻返回OKRedis 会fork一个子进程原来的redis主进程继续执行后续操作新fork的子进程负责将数据保存到磁盘然后退出如下图 bgsave开始时会 fork主进程得到⼦进程⼦进程共享主进程的内存数据。在Linux程序中fork()会产生一个和父进程完全相同的子进程。 完成 fork 后读取内存数据并写⼊ RDB ⽂件。 fork 采⽤的是 copy-on-write 技术当主 进程执⾏读操作时访问共享内存当主进程执⾏写操作时则会拷⻉⼀份数据执⾏写操作。 每次命令执行都会将所有redis内存快照到一个新的rdb文件里并覆盖原有rdb快照文件。 Copy-on-write 写时复制多更改条件下内存被大量复制重写完成后数据如何释放
本质来说这是一个进程的内存资源管理问题
内核提供的写时复制机制避免了大量内存拷贝以及占用过多内存子进程fork操作只是拷贝了父进程的页表数据当fork完成后对于一个父进程引用的内存页其引用值从1变成2. 当父进程进行写操作时会申请一份新的内存页并从原内存页copy所有数据之后父进程就在新的内存页上进行操作。而原内存页就变成了子进程的专属内存页引用值变成了1子进程重写完成并退出后内核会对资源进行回收包括占用的内存资源回收对于页表来说是进程专属直接清理即可而关联的内存页会将其引用值减1如果引用值变成了0该内存页就会被回收也就是复制之前的页原内存页变成了子进程的专属页当子进程结束后就会被回收掉
save与bgsave对比 AOFappend-only file AOF全称为Append Only File追加⽂件。Redis处理的每⼀个写命令都会记录在AOF⽂件(读操作不记录) 可以看做是命令⽇志⽂件。 默认情况下redis是没有开启AOF的。开启AOF功能需要设置配置 appendonly yes 开启 AOF 持久化后每执⾏⼀条会更改 Redis 中的数据的命令Redis 就会将该命令写⼊到 AOF 缓冲区 server.aof_buf 中然后再写⼊到 AOF ⽂件中 此时在内核缓存区最后再根据持久化⽅式 fsync策略的配置来决定 何时将系统内核缓存区的数据同步到硬盘中的。 AOF 持久化功能的实现分为 5 步 命令追加append 所有的写命令会追加到 AOF 缓冲区中。 ⽂件写⼊write 将 AOF 缓冲区的数据写⼊到 AOF ⽂件中。这⼀步 需要调⽤write函数系统调⽤write将数据写⼊到了系统内核缓冲区之 后直接返回了延迟写。注意此时并没有同步到磁盘。 ⽂件同步fsync AOF 缓冲区根据对应的持久化⽅式 fsync 策略 向硬盘做同步操作。这⼀步需要调⽤ fsync 函数系统调⽤ fsync 针 对单个⽂件操作对其进⾏强制硬盘同步fsync 将阻塞直到写⼊磁盘完 成后返回保证了数据持久化。 ⽂件重写rewrite 随着 AOF ⽂件越来越⼤需要定期对 AOF ⽂件 进⾏重写达到压缩的⽬的。 重启加载load Redis 重启时可以加载 AOF ⽂件进⾏数据恢复。 这⾥对上⾯提到的 Linux 系统调⽤再做⼀遍解释 write 写⼊系统内核缓冲区之后直接返回仅仅是写到缓冲区不会⽴即同步到硬盘。虽然提⾼了效率但也带来了数据丢失的⻛险。同步硬盘操作通 常依赖于系统调度机制Linux 内核通常为 30s 同步⼀次具体值取决于写出 的数据量和 I/O 缓冲区的状态。 fsync fsync⽤于强制刷新系统内核缓冲区同步到到磁盘确保写磁盘操作结束才会返回。 在 Redis 的配置⽂件中存在三种不同的 AOF 持久化⽅式 fsync策略它们分别是 appendfsync always主线程调⽤ write 执⾏写操作后后台线程 aof_fsync 线程⽴即会调⽤ fsync 函数同步 AOF ⽂件刷盘fsync 完成后线程返回这样会严重降低 Redis 的性能 appendfsync everysec 主线程调⽤ write 执⾏写操作后⽴即返回由后台线程 aof_fsync 线程每秒钟调⽤ fsync 函数系统调⽤同步⼀次 AOF ⽂件 appendfsync no 主线程调⽤ write 执⾏写操作后⽴即返回让操作系统决定何时进⾏同步Linux 下⼀般为 30 秒⼀次 推荐并且也是默认的措施为每秒 fsync 一次 这种 fsync 策略可以兼顾速度和安全性。
AOF重写
AOF文件里可能有太多没用指令所以AOF会定期根据内存的最新数据生成aof文件
如下两个配置可以控制AOF自动重写频率 auto‐aof‐rewrite‐min‐size 64mb //aof文件至少要达到64M才会自动重写文件太小恢复速度本来就很快重写的意义不大 auto‐aof‐rewrite‐percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写 当然AOF还可以手动重写进入redis客户端执行命令bgrewriteaof重写AOF 由于 AOF 重写会进⾏⼤量的写⼊操作为了避免对 Redis 正常处理命令请求造成影响Redis 将 AOF 重写程序放到⼦进程⾥执⾏。 图 1 展示的是 AOFRW 的实现原理。当 AOFRW 被触发执行时Redis 首先会 fork 一个子进程进行后台重写操作该操作会将执行 fork 那一刻 Redis 的数据快照全部重写到一个名为 temp-rewriteaof-bg-pid.aof 的临时 AOF 文件中。 由于重写操作为子进程后台执行主进程在 AOF 重写期间依然可以正常响应用户命令。因此为了让子进程最终也能获取重写期间主进程产生的增量变化主进程除了会将执行的写命令写入 aof_buf还会写一份到 aof_rewrite_buf 中进行缓存。在子进程重写的后期阶段主进程会将 aof_rewrite_buf 中累积的数据使用 pipe 发送给子进程子进程会将这些数据追加到临时 AOF 文件中详细原理可参考[1]。 当主进程承接了较大的写入流量时aof_rewrite_buf 中可能会堆积非常多的数据导致在重写期间子进程无法将 aof_rewrite_buf 中的数据全部消费完。此时aof_rewrite_buf 剩余的数据将在重写结束时由主进程进行处理。 当子进程完成重写操作并退出后主进程会在 backgroundRewriteDoneHandler中处理后续的事情。首先将重写期间 aof_rewrite_buf 中未消费完的数据追加到临时 AOF 文件中。其次当一切准备就绪时Redis 会使用 rename 操作将临时AOF 文件原子的重命名为 server.aof_filename此时原来的 AOF 文件会被覆盖。至此整个 AOFRW 流程结束。
图1 AOF重写存在的问题
内存开销 由图 1 可以看到在 AOFRW 期间主进程会将 fork 之后的数据变化写进aof_rewrite_buf 中aof_rewrite_buf 和 aof_buf 中的内容绝大部分都是重复的因此这将带来额外的内存冗余开销。
CPU 开销 CPU 的开销主要有三个地方分别解释如下 1) 在 AOFRW 期间主进程需要花费 CPU 时间向 aof_rewrite_buf 写数据并使用 eventloop 事件循环向子进程发送 aof_rewrite_buf 中的数据。 2) 在子进程执行重写操作的后期会循环读取 pipe 中主进程发送来的增量数据 然后追加写入到临时 AOF 文件。 3) 在子进程完成重写操作后主进程会在 backgroundRewriteDoneHandler 中进 行收尾工作。其中一个任务就是将在重写期间 aof_rewrite_buf 中没有消费完 成的数据写入临时 AOF 文件。如果 aof_rewrite_buf 中遗留的数据很多这里 也将消耗 CPU 时间。
磁盘 IO 开销 如前文所述在 AOFRW 期间主进程除了会将执行过的写命令写到 aof_buf 之外 还会写一份到 aof_rewrite_buf 中。aof_buf 中的数据最终会被写入到当前使用的旧 AOF 文件中产生磁盘 IO。同时aof_rewrite_buf 中的数据也会被写入重写生成的新 AOF 文件中产生磁盘 IO。因此同一份数据会产生两次磁盘 IO。 阿⾥ Redis 在最初也遇到了这些AOF的重写问题在内部经过多次迭代开发实现了Multi-part AOF 机制来解决同时也贡献给了社区并随此次 7.0 发布。具体⽅法是采⽤ base全量数据incr增量数据独⽴⽂件存储的⽅式。 Multi-part AOF 顾名思义MP-AOF 就是将原来的单个 AOF 文件拆分成多个 AOF 文件。在 MP-AOF中我们将 AOF 分为三种类型分别为 BASE表示基础 AOF它一般由子进程通过重写产生该文件最多只有一个INCR表示增量 AOF它一般会在 AOFRW 开始执行时被创建该文件可能存在多个HISTORY表示历史 AOF它由 BASE 和 INCR AOF 变化而来每次 AOFRW 成功完成时本次 AOFRW 之前对应的 BASE 和 INCR AOF 都将变为 HISTORYHISTORY 类型的 AOF 会被 Redis 自动删除。
为了管理这些 AOF 文件我们引入了一个 manifest清单文件来跟踪、管理这些AOF。同时为了便于 AOF 备份和拷贝我们将所有的 AOF 文件和 manifest 文件放入一个单独的文件目录中目录名由 appenddirname 配置Redis7.0 新增配置项决定。 图 2 展示的是在 MP-AOF 中执行一次 AOFRW 的大致流程。在开始时我们依然会fork 一个子进程进行重写操作在主进程中我们会同时打开一个新的 INCR 类型的 AOF 文件在子进程重写操作期间所有的数据变化都会被写入到这个新打开的INCR AOF 中。子进程的重写操作完全是独立的重写期间不会与主进程进行任何的数据和控制交互最终重写操作会产生一个 BASE AOF。新生成的 BASE AOF 和新打开的 INCR AOF 就代表了当前时刻 Redis 的全部数据。AOFRW 结束时主进程会负责更新 manifest 文件将新生成的 BASE AOF 和 INCR AOF 信息加入进去并将之前的 BASE AOF 和 INCR AOF 标记为 HISTORY这些 HISTORY AOF 会被 Redis 异步删除。一旦 manifest 文件更新完毕就标志整个 AOFRW 流程结束。 由图 2 可以看到我们在 AOFRW 期间不再需要 aof_rewrite_buf因此去掉了对应的内存消耗。同时主进程和子进程之间也不再有数据传输和控制交互因此对应的 CPU 开销也全部去掉。 Redis 4.0 混合持久化
重启 Redis 时我们很少使用 RDB来恢复内存状态因为会丢失大量数据。我们通常使用 AOF 日志重放但是重放 AOF 日志性能相对 RDB来说要慢很多这样在 Redis 实例很大的情况下启动需要花费很长的时间。 Redis 4.0 为了解决这个问题带来了一个新的持久化选项——混合持久化。 通过如下配置可以开启混合持久化(必须先开启aof) # aof‐use‐rdb‐preamble yes 如果开启了混合持久化AOF在重写时不再是单纯将内存数据转换为RESP命令写入AOF文件而是将重写这一刻之前的内存做RDB快照处理并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起都写入新的AOF文件新的文件一开始不叫appendonly.aof等到重写完新的AOF文件才会进行改名覆盖原有的AOF文件完成新旧两个AOF文件的替换。 于是在 Redis 重启的时候可以先加载 RDB 的内容然后再重放增量 AOF 日志就可以完全替代之前的AOF 全量文件重放因此重启效率大幅得到提升。
混合持久化AOF文件结构如下 Redis主从工作原理
Redis主从架构 Redis主从工作原理
如果你为master配置了一个slave不管这个slave是否是第一次连接上Master它都会发送一个PSYNC命令给master请求复制数据。
master收到PSYNC命令后会在后台进行数据持久化通过bgsave生成最新的rdb快照文件持久化期间master会继续接收客户端的请求它会把这些可能修改数据集的请求缓存在内存中。当持久化进行完毕以后master会把这份rdb文件数据集发送给slaveslave会把接收到的数据进行持久化生成rdb然后再加载到内存中。然后master再将之前缓存在内存中的命令发送给slave。
当master与slave之间的连接由于某些原因而断开时slave能够自动重连Master如果master收到了多个slave并发连接请求它只会进行一次持久化而不是一个连接一次然后再把这一份持久化的数据发送给多个并发连接的slave。
主从复制(全量复制)流程图 数据部分复制
当master和slave断开重连后一般都会对整份数据进行复制。但从redis2.8版本开始redis改用可以支持部分数据复制的命令PSYNC去master同步数据slave与master能够在网络连接断开重连后只进行部分数据复制(断点续传)。
master会在其内存中创建一个复制数据用的缓存队列缓存最近一段时间的数据master和它所有的slave都维护了复制的数据下标offset和master的进程id因此当网络连接断开后slave会请求master继续进行未完成的复制从所记录的数据下标开始。如果master进程id变化了或者从节点数据下标offset太旧已经不在master的缓存队列里了那么将会进行一次全量数据的复制。
主从复制(部分复制断点续传)流程图 如果有很多从节点为了缓解主从复制风暴(多个从节点同时复制主节点导致主节点压力过大)可以做如下架构让部分从节点与从节点(与主节点同步)同步数据 总结
RDB和AOF对比 持久化可以保证数据安全但会带来额外的开销请遵循下列建议 • ⽤来做缓存的Redis实例尽量不要开启持久化功能 • 建议关闭RDB持久化功能使⽤AOF持久化 • 利⽤脚本定期在slave节点做RDB实现数据备份 • 设置合理的rewrite阈值避免频繁的bgrewrite • 配置no-appendfsync-on-rewrite yes禁⽌在rewrite期间做aof避免因AOF引起的阻塞 部署建议 • Redis实例的物理机要预留⾜够内存应对fork和rewrite • 单个Redis实例内存上限不要太⼤例如8G。可以加快fork的速度、减少主从同步、数据迁移压⼒ • 不要与CPU密集型应⽤部署在⼀起 • 不要与⾼硬盘负载应⽤⼀起部署。例如数据库、消息队列