Redis-13丨Redis持久化功能优化

Posted by jiefang on January 15, 2020

Redis持久化功能优化

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操作耗时:

  • 优先使用物理机或者高效支持fork操作的虚拟化技术,避免使用 Xen;
  • 控制Redis实例最大可用内存,fork耗时跟内存量成正比,线上建议 每个Redis实例内存控制在10GB以内;
  • 合理配置Linux内存分配策略,避免物理内存不足导致fork失败;
  • 降低fork操作的频率,如适度放宽AOF自动触发时机,避免不必要的全量复制等;

子进程开销监控和优化

子进程负责AOF或者RDB文件的重写,它的运行过程主要涉及CPU、内 存、硬盘三部分的消耗。

CPU

  • CPU开销分析:子进程负责把进程内的数据分批写入文件,这个过程 属于CPU密集操作,通常子进程对单核CPU利用率接近90%;
  • CPU消耗优化:Redis是CPU密集型服务,不要做绑定单核CPU操作。 由于子进程非常消耗CPU,会和父进程产生单核资源竞争;
  • 不要和其他CPU密集型服务部署在一起,造成CPU过度竞争;
  • 如果部署多个Redis实例,尽量保证同一时刻只有一个子进程执行重写工作;

内存

  • 内存消耗分析:子进程通过fork操作产生,占用内存大小等同于父进程,理论上需要两倍的内存来完成持久化操作,但Linux有写时复制机制 (copy-on-write)。父子进程会共享相同的物理内存页,当父进程处理写请 求时会把要修改的页创建副本,而子进程在fork操作过程中共享整个父进程内存快照;

内存消耗优化:

  • 同CPU优化一样,如果部署多个Redis实例,尽量保证同一时刻只有 一个子进程在工作;
  • 避免在大量写入时做子进程重写操作,这样将导致父进程维护大量页副本,造成内存消耗;

硬盘

硬盘开销分析:子进程主要职责是把AOF或者RDB文件写入硬盘持久 化。势必造成硬盘写入压力。根据Redis重写AOF/RDB的数据量,结合系统 工具如sar、iostat、iotop等,可分析出重写期间硬盘负载情况。

硬盘开销优化:

  • 不要和其他高硬盘负载的服务部署在一起。如:存储服务、消息队 列服务等;
  • AOF重写时会消耗大量硬盘IO,可以开启配置no-appendfsync-on- rewrite,默认关闭。表示在AOF重写期间不做fsync操作;
  • 当开启AOF功能的Redis用于高流量写入场景时,如果使用普通机械磁盘,写入吞吐一般在100MB/s左右,这时Redis实例的瓶颈主要在AOF同步硬盘上;
  • 对于单机配置多个Redis实例的情况,可以配置不同实例分盘存储 AOF文件,分摊硬盘写入压力;