Redis-07-阻塞

内在原因

  1. API 或数据结构使用不合理

    对于高并发的场景我们应该尽量避免在大对象上执行算法复杂度超过 O(n) 的命令

    • 发现慢查询:执行 slowlog get {n}命令可以获取最近的 n 条慢查询命令
    • 发现大对象:redis-cli -h {ip} -p {port} --bigkeys
  2. CPU 饱和

    使用统计命令 redis-cli -h {ip} -p {port} --stat获取当前 Redis 使用情况,该命令每秒输出一行统计信息

  3. 持久化相关阻塞

    • fork 阻塞:fork 操作本身耗时过长,会导致主线程的阻塞
    • AOF 刷盘阻塞
    • HugePage 写操作阻塞

外在原因

  1. CPU 竞争

    • 进程竞争
    • 绑定 CPU
  2. 内存交换

    识别 Redis 内存交换的检查方法:
    1) 查询 Redis 进程号:redis-cli -p {port} info server | grep process_id
    2) 根据进程号查询内存交换信息:cat /proc/{process_id}/smaps | grep Swap

    如果交换量都是 0KB 或者个别的是 4KB,则是正常现象,说明 Redis 进程内存没有被交换。预防内存交换的方法有:

    • 保证机器充足的可用内存
    • 确保所有 Redis 实例设置都已最大可用内存(maxmemory),防止极端情况下 Redis 内存不可控的增长
    • 降低系统使用 swap 优先级,如 echo10>/proc/sys/vm/swappiness
  3. 网络问题

    • 连接拒绝
      • 网络闪断:一般发生在网络割接或者带宽耗尽的情况,对于网络闪断的识别比较困难,常见的做法可以通过 sar-n DEV 查看本机历史流量是否正常,或者借助外部系统监控工具(如Ganglia)进行识别
      • Redis 连接拒绝:Redis 通过 maxclients 参数控制客户端最大连接数,默认10000。当 Redis 连接数大于 maxclients 时会拒绝新的连接进入,info stats的rejected_connections 统计指标记录所有被拒绝连接的数量
      • 连接溢出:这是指操作系统或者 Redis 客户端在连接时的问题,可能是以下原因:
        • 进程限制:客户端想成功连接上 Redis 服务需要操作系统和 Redis 的限制都通过才可以
        • backlog 队列溢出:系统对于特定端口的 TCP 连接使用 backlog 队列保存。Redis 默认的长度为 511,通过 tcp-backlog 参数设置。如果怀疑是 backlog 队列溢出,线上可以使用 cron 定时执行 netstat -s | grep overflowed 统计,查看是否有持续增长的连接拒绝情况
    • 网络延迟:Redis 提供了测量机器之间网络延迟的工具,在 redis-cli -h {host} -p {port} 命令后面加入如下参数进行延迟测试:
      • --latency:持续进行延迟测试,分别统计:最小值、最大值、平均值、采样次数
      • --latency-history:统计结果同 --latency,但默认每 15 秒完成一行统计,可通过 -i 参数控制采样时间
      • --latency-dist:使用统计图的形式展示延迟统计,每 1 秒采样一次
    • 网卡软中断:指由于单个网卡队列只能使用一个 CPU,高并发下网卡数据交互都集中在同一个 CPU,导致无法充分利用多核 CPU 的情况