当 Redis 发生高延迟时,到底发生了什么?( 二 )

 
3.持久化阻塞
 
对于开启了持久化功能的Redis节点,需要排查是否是持久化导致的阻 塞 。持久化引起主线程阻塞的操作主要有:fork 阻塞、AOF刷盘阻塞 。
fork 操作发生在 RDB 和 AOF 重写时,Redis 主线程调用 fork 操作产生共享内存的子进程,由子进程完成对应的持久化工作 。如果 fork 操作本身耗时过长,必然会导致主线程的阻塞 。

当 Redis 发生高延迟时,到底发生了什么?

文章插图
 
Redis 执行 fork 操作产生的子进程内存占用量表现为与父进程相同,理论上需要一倍的物理内存来完成相应的操作 。但是 linux 具有写时复制技术 (copy-on-write),父子进程会共享相同的物理内存页,当父进程处理写请求时会对需要修改的页复制出一份副本完成写操作,而子进程依然读取 fork 时整个父进程的内存快照 。所以,一般来说,fork 不会消耗过多时间 。
可以执行info stats命令获取到 latest_fork_usec 指标,表示 Redis 最近一次 fork 操作耗时,如果耗时很大,比如超过1秒,则需要做出优化调整 。
> redis-cli -c -p 7000 info | grep -w latest_fork_useclatest_fork_usec:315当我们开启AOF持久化功能时,文件刷盘的方式一般采用每秒一次,后 台线程每秒对AOF文件做 fsync 操作 。当硬盘压力过大时,fsync 操作需要等待,直到写入完成 。如果主线程发现距离上一次的 fsync 成功超过2秒,为了数据安全性它会阻塞直到后台线程执行 fsync 操作完成 。这种阻塞行为主要是硬盘压力引起,可以查看 Redis日志识别出这种情况,当发生这种阻塞行为时,会打印如下日志:
Asynchronous AOF fsync is taking too long (disk is busy).  Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.也可以查看 info persistence 统计中的 aof_delayed_fsync 指标,每次发生 fdatasync 阻塞主线程时会累加 。
>info persistenceloading:0aof_pending_bio_fsync:0aof_delayed_fsync:0 
4.内存交换
 
内存交换(swap)对于 Redis 来说是非常致命的,Redis 保证高性能的一个重要前提是所有的数据在内存中 。如果操作系统把 Redis 使用的部分内存换出到硬盘,由于内存与硬盘读写速度差几个数量级,会导致发生交换后的 Redis 性能急剧下降 。识别 Redis 内存交换的检查方法如下:
>redis-cli -p 6383 info server | grep process_id # 查询 redis 进程号>cat /proc/4476/smaps | grep Swap # 查询内存交换大小Swap: 0 kB Swap: 4 kB Swap: 0 kB Swap: 0 kB如果交换量都是0KB或者个别的是4KB,则是正常现象,说明Redis进程内存没有被交换 。
有很多方法可以避免内存交换的发生 。比如说:
  • 保证机器充足的可用内存;
  • 降低系统使用swap优先级,如echo10>/proc/sys/vm/swAppiness;
  • 确保所有Redis实例设置最大可用内存(maxmemory),防止极端情况下 Redis 内存不可控的增长 。




推荐阅读