Redis第5课:正确认识 Redis 持久化和开发运维问题

持久化的概念及其作用

首先我们来看下什么是 Redis 的持久化。Redis 的所有数据都保持在内存中,对数据的更新将异步保存到磁盘上。如果 Redis 需要恢复时,就会从硬盘再到内存的过程。简而言之,持久化就是把内存中的数据保存到硬盘中的过程。


v2-27b1e118e12e5feb1b8b989f71878d34_b.jpg


由上图可知,Redis 持久化就是从内存到硬盘的过程,因为 Redis 本身就在内存中运行的;当突然断电或者死机后,我们可以从硬盘中拷贝数据到内存,这是整个过程。

这就是 Redis 持久化的用处。持久化是为了让硬盘成为备份,以保证数据库数据的完整。

持久化有哪些方式呢?你会看到网上和书上会有很多分类,但是其实大致只分成两种。

1.快照 RDB

2.日志 AOF

快照——RDB

顾名思义,快照就是拍个照片,做个备份,而这种备份是 Redis 自动完成的。

这个功能是 Redis 内置的一个持久化方式,即使你不设置,它也会通过配置文件自动做快照持久化的操作。你可以通过配置信息,设置每过多长时间超过多少条数据做一次快照。具体的操作如下:

        save 500 100 // 这里的意思是每过500秒超过100个 key 被修改就执行快照。
      

我们再来看看它们的运行状况。

1.Redis 调用 fork() 进程,同时拥有父进程和子进程。

2.子进程将数据都写到一个临时 RDB 文件之中。

3.当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换旧的 RDB 文件。

这个过程使 Redis 可以从写时复制中得到备份。

接下来我们讲解三种 RDB 的触发机制。

1.save(同步):其他的命令都要排队。

2.bgsave(异步):返回 ok,但是后台会新开一个线程去执行。

3.自动触发 RDB 文件。

save(同步)


v2-480c1dd39d7ec5b2dbbbf7a1128126a3_b.png


如果有1000万条数据,执行 save 命令,Redis 就会对1000万条数据打包,而这个时候是同步的,Redis 就会进入阻塞状态。这也是 save 的缺点,接下来我们讲异步命令 bgsave。

bgsave(异步命令)


v2-9d82aaa4272f7031b4e819928006ed23_b.jpg


上图可知,客户端会在 Redis 发出 bgsave 命令,Redis 会另外开一个进程调用 fork() 方法,这个进程同时会创建 RDB 文件。这样,你在父进程里操作别的命令,就不会受影响了。

快照方式虽然是 Redis 自动的,但是如果 Redis 服务器挂掉后,那么最近写入的,是不会被拷入快照中的。所以 RDB 存在两方面的缺点。

1.耗时耗性能。

2.容易丢失数据和不可控制。


v2-353e6141313f210e9da7b8e7c4542dff_b.jpg


我们对上面的缺点分别做下说明。

耗时耗性能:Redis 写 RDB 文件是 dump 操作,所以需要的时间是 O(n),需要所有命令都执行一遍,非常耗时耗性能。

容易丢失数据和不可控制:如果我们在某个时间 T1 内写多个命令,这个时候 T2 时间执行 RDB 文件操作,T3 时间又执行多个命令,T4 时间就会出现宕机了。那么 T3 到 T4 的数据就会丢失了。

虽然 RDB 有缺陷,但是依然在生产环境中会使用,RDB 适合冷备,就是当用户数据不高的时候,比如在午夜时分就可 RDB 备份。其他时候我们通常使用 AOF 日志备份。

日志--AOF

这个时候我们就需要使用 AOF(Append-only File),AOF 是用日志方式,通俗点讲就是当写一条命令的时候,如 set 某个值,Redis 就会去日志里写一条 set 某个值的语句。如下图:


v2-dc74f7dd0703251a4fc3eca2df6c0a9d_b.jpg


当服务器宕机后,Redis 就会调用 AOF 日志文件,并且这个过程一般是实时的,不需要时间消耗。

AOF三种策略

这三种策略分别是 always、everysec、no。


v2-dae047a6bbda27236286c0a2ed035e61_b.jpg


上图表示客户端向 AOF 文件写入的时候,是会通过缓冲的,缓冲是系统机制,是为了提高文件的写入效率。

always

客户端是不会直接把命令写入 AOF 文件的,Liunx 系统会有一个缓冲机制,把一部分命令打包再同步到 AOF 文件,从而提高效率。

但是如果你是 always 命令,就表示每条命令都写入 AOF 文件中,这样是为了保证每条命令都不丢失。

everysec

每秒策略,简而言之,就是说每一秒的缓冲区的数据都会刷新到硬盘当中。但是它不像 always 那样,每条数据都会写入硬盘中,如果硬盘发生故障有可能丢失1秒的数据。

no

这个 no 的配置相当于把控制权给了操作系统,操作系统来决定什么时候刷新数据到硬盘。不需要我们考虑哪种情况。

| 命令 | always | everysec | no | | --- | --- | --- | --- | | 优点 | 不丢失数据 | 每秒一次同步,丢一秒数据 | 不需要管 | | 缺点 | IO开销大,一般sata盘只有TPS | 丢一秒数据 | 不可控制 |

关于 AOF,我们补充一点。对于 AOF 操作,Redis 在写入的时候,会压缩命令。它既可以减少硬盘的占用量,同时可以提高恢复硬盘的速度。 例如如下的表格。

| 原生AOF | AOF复写 | | --- | --- | | set hello a1 | set hello a3 | | set hello a2 | | | set hello a3 | | | incr counter | set counter 2 | | incr counter | | | rpush hello a | rpush hello a b c | | rpush hello b | | | rpush hello c | |

上表可以看到,set hello 有三个值,但是 a1 和 a2 是无效的,最终会 AOF 会自动 set 最后一个 a3 的值;incr counter两次,AOF 自动识别为2次;rpush 三个值,那么 rpush 会自动简写为一条数据。

针对上面的 Redis 的 AOF 复写。Redis 提供了两种命令。

AOF 重写实现的两种命令

这两种命令是 bgrewriteaof 和 AOF 重写配置。bgrewriteaof 类似 RDB 中的 bgsave 命令,它还是 fork() 子进程,然后完成 AOF 的过程。

AOF 重写配置包含两个配置命令,见如下表格。

| 配置名 | 含义 | | --- | --- | | auto-aof-rewrite-min-size | AOF文件重写最小的尺寸 | | auto-aof-rewrite-percentage | AOF文件增长率 |

auto-aof-rewrite-min-size 表示配置最小尺寸,超过这个尺寸就进行重写。

auto-aof-rewrite-percentage 是指当前 AOF 文件比上次重写的增长比例大小。AOF 文件过大而实际内存数据小的问题(频繁修改数据问题)。

auto-aof-rewrite-percentage,这里说的是 AOF 文件增长比例,指当前 AOF 文件比上次重写的增长比例大小。AOF 重写即 AOF 文件在一定大小之后,重新将整个内存写到 AOF 文件当中,以反映最新的状态(相当于 bgsave)。这样就避免了,AOF 文件过大而实际内存数据小的问题(频繁修改数据问题)。

接下来看下统计配置(见下表),有了它,就可以对上面的配置命令进行控制。

| 配置名 | 含义 | | --- | --- | | aof-current-size | AOF当前尺寸(字节) | | aof-base-size | AOF上一次启动和重写的尺寸(字节) |


v2-255cad6159af8771e5358fe6157c9677_b.jpg


上图可知,bgrewriteaof 命令后,Redis 会在父进程 fork 一个子进程,同时父进程会 aof_bufaof_rewrite_buf 命令,分别对旧的 AOF 文件和新的 AOF 文件,同时子进程会写新的 AOF 文件,并通知父进程,然后 Redis 会使用 aof_rewrite_buf 命令写入新的 AOF 文件。

实际配置过程如下

        appendonly yes // appendonly默认是no
appendfilename "append only - ${port}.aof" //设置 AOF 名字
appendfsync everysec // 每秒同步
dir /diskpath // 新建一个目录
no-appendfsync-on-rewrite yes // AOF 性能上需要权衡,为了减少磁盘压力。默认是 no,不会丢失数据,但是延迟会比较高。为了减低延迟,一般我们设置成 yes,这样可能丢数据。
      

Redis 持久化开发运维时遇到的问题

问题可总结为四种,即 fork 操作、进程外的开销和优化、AOF 追加阻塞和单机多实例部署。

fork 操作

fork 操作包括以下三种

        1.同步操作;// bgsave时是否同步
2.与内存量息息相关:内存越大,耗时越长 
3.info:lastest_fork_usec // 持久化
      

改善 fork 的方式有以下四种。

1.使用物理机或支持高效 fork 的虚拟技术。

2.控制 Redis 实例最大可用内存:maxmemory。

3.合理配置 Liunx 系统内存分配策略:vm.overcommit_memory=1。

4.降低频率,如延长 AOF 重写 RDB,不必要的全量复制。

子进程的开销以及优化

这里主要指CPU、内存、硬盘三者的开销与优化。

1.CPU

  • 开销:AOF 和 RDB 生成,属于 CPU 密集型,对 CPU 是巨大开销;
  • 优化:不做CPU绑定,不与CPU密集型部署。

2.内存


v2-30c1d3282f0ce541eb06d9be213ab9bb_b.jpg


  • 开销:需要通过 fork 来消耗内存的,如 copy-on-write。
  • 优化:echo never > /sys/kernel/mm/transparent_hugepage/enabled,有时启动的时候会出现警告的情况,这个时候需要配置这个命令。

3.硬盘

  • 开销:由于大量的 AOF 和 RDB 文件写入,导致硬盘开销大,建议使用 iostat、iotop 分析硬盘状态。
  • 优化:(1)不要和高硬盘负载部署到一起,比如存储服务、消息队列等等;(2)配置文件中的 no-appendfsync-on-rewrite 设置成 yes;(3)当写入量很大的时候,建议更换 SSD 硬盘;(4)单机多实例持久化文件考虑硬盘分配分盘。

AOF追加阻塞


v2-7ca29c649a82b8c3fd2d752e354f6589_b.jpg


我们如果使用 AOF 策略,通常就会使用每秒刷盘的策略(everysec),主线程会阻塞,直到同步完成。首先我们知道主线程是非常宝贵的资源,其次我们每秒刷盘实际上未必是1秒,可能是2秒的数据。

我们如何定位 AOF 阻塞

1.通过 Redis 日志


v2-6b484791d5714b978ce3c6d9f878be75_b.jpg


上图可以看到, Redis 日志会出现上述的语句,告诉你异步 IO 同步时间太长,你的硬盘是否有问题,同时会拖慢 Redis 。

2.当然除了上述的问题,你还可以用 Redis 的info方式来确定问题

        info rersistence // 直接在命令中打这个命令即可。
...
aof_delayed_fsync : 100 // 会记录你发生阻塞的次数,每一次加1
...
...
      

但是这个命令无法看到当前的问题,因为它是历史的累计值。

当然你还可以使用 Liunx 命令 top


v2-bb1d5c19c465427073d5e1e75dbdcd1f_b.jpg


上图能看到 wa 值,wa 值是表示 IO 瓶颈,如果超过50%,就表示 IO 出现阻塞了。

本文,我们首先讲了持久化的概念,持久化的方式有 RDB 和 AOF 两种。RDB 主要是 save(同步)、bgsave(异步)、自动触发 RDB 文件三种触发方式;AOF则是 always、everysec、no 三种方式,同时我们补充了 AOF 重写的命令和如何配置。

最后我们讨论了 Redis 持久化开发运维时遇到的问题,主要有 fork 操作、进程外的开销和优化、AOF 追加阻塞、单机多实例部署四种问题。

这就要求我们在做 RDB 和 AOF 备份的时候,要注意到的这些问题。特别是大数据,需要监控 Redis 是否阻塞、开销是否过大等问题。

如果你有疑问欢迎加微信咨询:


u.wechat.com/MDHWBbNbJR (二维码自动识别)


也可以关注我的公众号想我提问:


weixin.qq.com/r/EEzl-dL (二维码自动识别)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值