如何解决redis 的阻塞问题

当 redis 阻塞时,应用会收到大量的redis 超时异常,应当将这些异常加入统计并通过邮件等方式报警。

日常监控命令的耗时、慢查询、持久化阻塞、连接拒绝、CPU\磁盘\IO网络负载等等。

内在原因

  • API 或数据结构不合理

  • CPU 饱和问题

  • 持久化相关的阻塞

API 数据结构不合理

如对一个包含上万个元素的hash结构执行hgetall操作。

  1. 发现慢查询 slowlog get [n] 获取最近n条查询慢的命令。
  2. 修改低算法的命令,例如替换hgetall 为hmget,禁止 keys、sort 等。
  3. 调整大对象,防止一次操作过多数据。 redis-cli bigkeys,其原理是采用分段scan 操作。把历史扫描过的最大对象统计出来进行分析优化。

CPU 饱和

redis-cli –stat 获取redis 的使用情况。

持久化阻塞

fork阻塞

fork操作发生在RDB和AOF重写时,Redis主线程调用fork操作产生共享内存的子进程,由子进程完成持久化文件重写工作。如果fork操作本身耗时过长,必然会导致主线程的阻塞
可以执行info stats命令获取到latest_fork_usec指标,表示Redis最近一次fork操作耗时,如果耗时很大,比如超过1秒,则需要做出优化调整,如避免使用过大的内存实例和规避fork缓慢的操作系统等
aof 刷盘阻塞

当我们开启AOF持久化功能时,文件刷盘的方式一般采用每秒一次,后台线程每秒对AOF文件做fsync操作。当硬盘压力过大时,fsync操作需要等待,直到写入完成。如果主线程发现距离上一次的fsync成功超过2秒,为了数据安全性它会阻塞直到后台线程执行fsync操作完成。这种阻塞行为主要是硬盘压力引起。

外在原因

CPU 竞争

  • 进程竞争,可以通过top、sar等命令定位到CPU消耗的时间点和具体进程

  • 绑定CPU,部署Redis时为了充分利用多核CPU,通常一台机器部署多个实例。常见的一种优化是把Redis进程绑定到CPU上,用于降低CPU频繁上下文切换的开销。

内存交换

  • 保障内存充足
  • 确保所有Redis实例设置最大可用内存(maxmemory),防止极端情况
    下Redis内存不可控的增长。
  • 降低系统使用swap优先级,如echo10>/proc/sys/vm/swappiness

网络问题

  • 连接被拒绝
    • 网络闪断,通过sar-n DEV查看本机历史流量是否正常,或者借助外部系统监控工具(如Ganglia)进行识别
    • redis连接拒绝,maxclients参数现在默认1000,客户端访问Redis时尽量采用NIO长连接或者连接池的方式。
    • 连接溢出,检查进程限制,例如过ulimit、以及backlog队列Redis默认的长度为511,通过tcp-backlog参数设置。
  • 网络延迟,取决于网络环境。

参考资料 https://redis.io/topics/latency