Redis持久化——问题定位与优化(三)
核心知识点:
1.fork操作
a.在RDB或AOF重写时,会执行fork操作创建子进程,fork操作是一个重量级操作。
b.改善fork操作耗时的手段:避免使用Xen、配置Redis实例最大使用内存、合理配置Liunx内存使用技术、降低fork操作的频率。
2.子进程开销监控与优化
1).CPU
2).内存
3).硬盘
3.AOF追加阻塞
Redis持久化功能一直是影响Redis性能的高发地,下面我们结合常见的持久化功能问题进行分析定位和优化。
一、fork操作
当Redis做RDB或AOF重写时,一个必不可少的操作就是执行fork操作创建子进程,对于大多是系统来说fork是一个重量级操作。
虽然fork创建的子进程不需要拷贝父进程的物理内存空间,但是会复制父进程的空间内存页表。
例如对于10GB的Redis进程,需要复制大约20MB的内存页表,因此fork操作耗时跟进程总内存息息相关,
如果使用虚拟化技术,特别是Xen虚拟机,fork操作会更耗时。
fork耗时问题定位:对于高流量的Redis实例OPS可达5万以上,
如果fork操作耗时在秒级别将拖慢Redis几万条命令执行,对线上应用延迟影响非常明显。
正常情况下,fork耗时应该是每GB消耗20毫秒。可以在info stats统计中查latest_fork_usec指标获取最近一次fork操作耗时,单位微秒。
如何改善fork操作的耗时:
1)优先使用物理机或者高效支持fork操作的虚拟机技术,避免使用Xen。
2)控制Redis实例最大可用内存,fork耗时跟内存量成正比,线上建议每个Redis实例内存控制在10GB以内。
3)合理配置Linux内存分配策略,避免物理内存不足导致fork失败。
4)降低fork操作的频率,如适度放宽AOF自动触发时机,避免不必要的全量复制等
二、子进程开销监控和优化
子进程负责AOF或者RDB文件的重写,它的运行过程主要涉及CPU、内存、硬盘三部分的消耗。
1.CPU
(1)CPU开销分析
子进程负责把进程内的数据分批写入文件,这个过程属于CPU密集操作,通常子进程对单核CPU利用率接近90%。
(2)CPU消耗。
Redis是CPU密集型操作,不要做绑定单核CPU的操作。由于子进程非常消耗CPU,会和父进程产生单核资源竞争。
不要和其他CPU密集型服务部署在一起,造成CPU过度竞争。
如果部署多个Redis实例,尽量保证同一时刻只有一个子进程执行重写工作。
2.内存
(1)内存消耗分析
子进程通过fork操作产生,占用内存大小等同于父进程,理论上需要两倍的内存来完成持久化的操作,但是Linux有写时复制机制。
父进程会共享相同的物理内存页,当父进程处理写请求时会把要修改的页创建副本,而子进程在fork操作过程中共享整个父进程内存快照。
(2)内存消耗监控
如果重写过程中存在内存页操作,父进程负责创建所修改内存页的副本,从日志中可以看出这部分的内存消耗。
父进程维护页副本消耗同RDB重写过程类似,不同之处在于AOF重写需要AOF重写缓冲区。
提示:编写shell脚本根据Redis日志可快速定位子进程重写期间内存过度消耗的情况。
(3)内存消耗优化
- 同CPU优化一样,如果部署多个Redis实例,尽量保证同一时刻只有一个子进程在工作。
- 避免大量写入时做子进程重写操作,这样将导致父进程维护大量页副本,造成内存消耗。
在Linux kernel在2.6.38内核增加了Transparent Huge pages(THP),支持huge page(2MB)的页分配,默认开启。
当开启时可以降低fork创建子进程的速度,但执行fork之后,如果开启HTP,复制页单位会从原来4KB变为2MB,会大幅增加重写期间父进程的内存消耗。
3.硬盘
(1)硬盘开销分析
子进程主要职责是把AOF或者RDB文件写入硬盘持久化,势必会造成硬盘写入压力,
根据Redis重写AOF/RDB的数据量,结合系统工具如sar、iotop等,可分析出重写期间硬盘负载情况。
(2)硬盘开销优化
- 不要和其它高硬盘负载的服务部署在一起。如:存储服务、消息队列服务。
- AOF重写时会消耗大量硬盘IO,可以开启配置no-appendfsync-on-rewrite,默认关闭。表示在AOF重写期间不做fsync操作。
- 当开启AOF功能的Redis用于高流量写入场景时,如果使用普通机械磁盘,写入吞吐一般在100MB/s左右,这是瓶颈主要在AOF同步硬盘上。
- 对于单机配置多个Redis实例的情况,可以配置不同实例分盘存储AOF文件,分摊硬盘写入压力。
三、AOF追加阻塞
当开启持久化时,常用的同步硬盘的策略是everysec,用于平衡性能和数据安全性。
对于这种方式,Redis使用另一条线程每秒执行fsync同步硬盘。当系统硬盘资源繁忙时,会造成Redis主线程阻塞。
1.阻塞流程分析:
(1)主线程负责写入AOF缓冲区。
(2)AOF线程负责每秒执行一次同步操作,并记录最近一次同步时间。
(3)主线程负责每秒执行一次同步磁盘操作,并记录最近一次同步时间。
- 如果距上次同步成功时间在2秒内,主线程直接返回。
- 如果距上次同步时间超过两秒,主线程将会阻塞,直到同步操作完成。
通过分析AOF阻塞流程可以发现两个问题:
(1)everysec配置最多可能丢失2秒数据,不是1秒。
(2)如果系统fsync缓慢,将会导致Redis主线程阻塞影响效率。
2.AOF阻塞问题定位
(1)发生AOF阻塞问题,Redis会在日志中记录其行为。
(2)每当发生AOF追加阻塞事件,在info Persistence统计中,aof_delayed_fsync指标会累加,查看这个指标方便定位AOF阻塞问题。
(3)AOF同步最多允许2秒延迟,当延迟发生时说明硬盘存在高负载问题,可以通过监控工具如iotop,定位消耗硬盘IO资源的进程。