百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

面试被问哭:Redis 如何做持久化与恢复?

toyiye 2024-07-16 05:45 10 浏览 0 评论

专注于Java领域优质技术,欢迎关注

一、前言

本文主要讲了 Redis 的持久化相关功能,持久化一直是影响 Redis 性能的高发地,也是面试中经常被问到的。

包括 RDB 相关的特定和优缺点,AOF 的优缺点,事实上,由于 RDB 的数据实时性问题,目前用 AOF 比较多了,而持久化恢复也是优先 AOF。

RDB 是旧的模式,现在基本上都使用 AOF,当然,今天两个都会一起聊聊。

二、RDB

RDB 流程图:

RDB 特点:

  1. RDB 是一种快照模式,即——保存的是 key value 数据内容。
  2. RDB 有 2 种持久方式,同步 save 模式和异步 bgsave 模式。由于 save 是同步的,所以可以保证数据一致性,而 bgsave 则不能。
  3. save 可以在客户端显式触发,也可以在 shutdown 时自动触发;bgsave 可以在客户端显式触发,也可以通过配置由定时任务触发,也可以在 slave 节点触发。
  4. save 导致 redis 同步阻塞,基本已经废弃。bgsave 则不会导致阻塞,但也有缺点:在 fork 时,需要增加内存服务器开销,因为当内存不够时,将使用虚拟内存,导致阻塞 Redis 运行。所以,需要保证空闲内存足够。
  5. 默认执行 shutdown 时,如果没有开启 AOF,则自动执行 bgsave。
  6. 每次的 RDB 文件都是替换的。

关于优化:

Redis 会压缩 RDB 文件,使用 LZF 算法,让最终的 RDB 文件远小于内存大小,默认开启。但会消耗 CPU。

RDB 缺点:

  1. 无法秒级持久化。
  2. 老版本 Redis 无法兼容新版本 RDB。

RDB 优点:

  1. 文件紧凑,适合备份,全量复制场景。例如每 6 小时执行 bgsave,保存到文件系统之类的。
  2. Redis 加载 RDB 恢复数据远远快于 AOF。

三、AOF

由于 RDB 的数据实时性问题,AOF(append only file) 是目前 Redis 持久化的主流方式。

AOF 特点:

  1. 默认文件名是 appendonly.aof。和 RDB 一样,保存在配置中 dir 目录下。
  2. AOF 相比较于 RDB,每次都会保存写命令,数据实时性更高。
  3. AOF 由于每次都会记录写命令,文件会很大,因此需要进行优化,称之为“重写机制”(下面详细说)。
  4. AOF 每次保存的写命令都放在一个缓冲区,根据不同的策略(下面详细说)同步到磁盘。

“重写机制” 细节:

  1. fork 子进程(类似 bgsave)
  2. 主进程会写到2个缓冲区,一个是原有的 “AOF 缓存区”,一个是专门为子进程准备的 “AOF 重写缓冲区”;
  3. 子进程写到到新的 AOF 文件中,批量的,默认 32m;写完后通知主进程。
  4. 主进程把“AOF 重写缓冲区”的数据写到新 AOF 文件中。
  5. 将新的 AOF 文件替换老文件。

重写流程图:

缓冲区同步策略,由参数 appendfsync 控制,一共3种:

  1. always:调用系统 fsync 函数,直到同步到硬盘返回;严重影响redis性能。
  2. everysec:先调用 OS write 函数, 写到缓冲区,然后 redis 每秒执行一次 OS fsync 函数。推荐使用这种方式。
  3. no: 只执行 write OS 函数,具体同步硬盘策略由 OS 决定;不推荐,数据不安全,容易丢失数据。

四、持久化恢复

AOF 和 RDB 文件都可以用于服务器重启时的数据恢复,具体流程如下图:

从图中可以看出优先加载 AOF,当没有 AOF 时才加载 RDB。当 AOF 或者 RDB 存在错误,则加载失败。

五、问题排查和性能优化

Redis 持久化是影响 Redis 性能的高发地,也是面试中常问的问题。

1、fork 操作

当 Redis 做 RDB 或者 AOF 重写时,必然要进行 fork 操作,对于 OS 来说,fork 都是一个重量级操作。而且,fork 还会拷贝一些数据,虽然不会拷贝主进程所有的物理空间,但会复制主进程的空间内存页表。对于 10GB 的 Redis 进程,需要复制大约 20MB 的内存页表,因此 fork 操作耗时跟进程总内存量息息相关,再加上,如果使用虚拟化技术,例如 Xen 虚拟机,fork 会更加耗时。

一个正常的 fork 耗时大概在 20毫秒左右。为什么呢,假设一个 Redis 实例的 OPS 在 5 万以上,如果 fork 操作耗时在秒级,那么僵拖慢几万条命令的执行,对生产环境影响明显。

我们可以在 Info stats 统计中查询 latestforkusec 指标获取最近一次 fork 操作耗时,单位微秒。

如何优化:

  1. 优先使用物理机或者高效支持 fork 的虚拟化技术,避免使用 Xen。
  2. 控制 redis 实例最大内存,尽量控制在 10GB 以内。
  3. 合理配置 Linux 内存分配策略,避免内存不足导致 fork 失败。
  4. 降低 fork 的频率,如适度放宽 AOF 自动触发时机,避免不必要的全量复制。

2、子进程开销

fork 完毕之后,会创建子进程,子进程负责 RDB 或者 AOF 重写,这部分过程主要涉及到 CPU,内存,硬盘三个地方的优化。

  1. CPU 写入文件的过程是 CPU 密集的过程,通常子进程对单核 CPU 利用率接近 90%。如何优化呢?既然是 CPU 密集型操作,就不要绑定单核 CPU,因为这样会和父 CPU 进行竞争。同时,不要和其他 CPU 密集型服务不是在一个机器上。如果部署了多个 Redis 实例,尽力保证统一时刻只有一个子进程执行重写工作。
  2. 内存子进程通过 fork 操作产生,占用内存大小等同于父进程,理论上需要两倍的内存完成持久化操作,但 Linux 有 copy on write 机制,父子进程会共享相同的物理内存页,当父进程处理写操作时,会把要修改的页创建对应的副本,而子进程在 fork 操作过程中,共享整个父进程内存快照。即——如果重写过程中存在内存修改操作,父进程负责创建所修改内存页的副本。这里就是内存消耗的地方。如何优化呢?尽量保证同一时刻只有一个子进程在工作;避免大量写入时做重写操作。
  3. 硬盘 硬盘开销分析:子进程主要职责是将 RDB 或者 AOF 文件写入硬盘进行持久化,势必对硬盘造成压力,可通过工具例如 iostat,iotop 等,分析硬盘负载情况。

如何优化:

  1. 不要和其他高硬盘负载的服务放在一台机器上,例如 MQ,存储。
  2. AOF 重写时会消耗大量硬盘 IO,可以开启配置 no-appendfsync-on-rewrite,默认关闭。表示在 AOF 重写期间不做 fsync 操作。
  3. 当开启 AOF 的 Redis 在高并发场景下,如果使用普通机械硬盘,每秒的写速率是 100MB左右,这时,Redis 的性能瓶颈在硬盘上,建议使用 SSD。
  4. 对于单机配置多个 Redis 实例的情况,可以配置不同实例分盘存储 AOF 文件,分摊硬盘压力。

3、AOF 追加阻塞

当开启 AOF 持久化时,常用的同步硬盘的策略是“每秒同步” everysec,用于平衡性能和数据安全性,对于这种方式,redis 使用另一条线程每秒执行 fsync 同步硬盘,当系统资源繁忙时,将造成 Redis 主线程阻塞。

流程图如下:

通过上图可以发现:everysec 配置最多可能丢失 2 秒数据,不是 1 秒;如果系统 fsync 缓慢,将会导致 Redis 主线程阻塞影响效率。

问题定位:

  1. 发生 AOF 阻塞时,会输入日志。用于记录 AOF fsync 阻塞导致拖慢 Redis 服务的行为。
  2. 每当 AOF 追加阻塞事件发生时,在 info Persistence 统计中,aofdelayedfsync 指标会累加,查看这个指标方便定位 AOF 阻塞问题。
  3. AOF 同步最多运行 2 秒的延迟,当延迟发生时说明硬盘存在性能问题,可通过监控工具 iotop 查看,定位消耗 IO 的进程。

4、单机多实例部署

Redis 单线程架构无法充分利用多核CPU,通常的做法是一台机器上部署多个实例,当多个实例开启 AOF 后,彼此之间就会产生CPU 和 IO 的竞争。

如何解决这个问题呢?

让所有实例的 AOF 串行执行。

我们通过 info Persistence 中关于 AOF 的信息写出 Shell 脚本,然后串行执行实例的 AOF 持久化。

整个过程如图:

通过不断判断 AOF 的状态,手动执行 AOF 重写,保证 AOF 不会存在竞争。具体的 Shell 编写以及 info 信息判断,可以查看下图:

六、总结

本文主要讲了 Redis 的持久化相关功能,持久化一直是影响 Redis 性能的高发地,也是面试中经常被问到的。包括 RDB 相关的特定和优缺点,AOF 的优缺点,事实上,由于 RDB 的数据实时性问题,目前用 AOF 比较多了。而持久化恢复也是优先 AOF。

关于持久化的问题排查,就很麻烦了,但无非几个方面,fork 耗时,子进程的 CPU,内存,硬盘开销,AOF 的同步阻塞,单机多实例部署。

这些优化,可以通过前面写的分析进行排查。

来自https://www.jianshu.com/p/2255de3aec81

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码