十月底在公司redis运维组分享了“影响redis的那些阻塞操作”,这两天正好有空整理下,我们首先看下这张图

在上图中我用每个红点标注了redis可能发生阻塞的点,接下来我们将其分为客户端和服务端两组去分析

客户端阻塞

  1. keys *

    Q:遍历key时间复杂度o(n),因为从上图我们可以知道命令在服务器上是排队执行的,键数量多是有可能会造成redis阻塞服务端阻塞无法响应其他命令客户端会明显感到停顿
    A:可以使用dbsize或者scan命令代替,或者考虑在从库执行该命令;scan命令原理类似数据库的limit
  2. hgetall
    Q:当hash元素比较多时,因为要不断的对key进行hash寻址,会存在阻塞redis的可能
    A:可替换为hmget或者hscan(渐进式hash原理)
  3. setbit key offset value
    Q:该命令是基于Bitmaps数据结构,即二进制位的操作,当offset非常大时整个初始化过程会很慢,早晨redis的阻塞
  4. flushdb/flushall
    Q:该命令会将所有数据清除,且当数据库键值对比较多时会对redis早晨阻塞
    A:使用rename-command配置规避该命令
  5. monitor
    Q:用于监控redis正在执行的命令,当redis并发量大时,输出缓冲区会暴涨,占用大量内存早晨阻塞
    A:禁用该命令
  6. 客户端bigkey造成的阻塞
    Q:bigkey造成的阻塞在一定程度上也是比较恐怖的;有可能不定向的造成网络,输入缓冲区,执行器,输出缓冲区,磁盘等一系列故障,虽然故障是偶发的,但既然偶发必然存在风险
    A:规范业务开发规则、定时巡检及时反馈

服务端阻塞

  1. fork操作
    Q:在RDB生成和AOF重写时,会fork一个子进程完成持久化工作,当fork操作执行太过耗时也会造成阻塞,阻塞原因是该操作会复制父进程的空间内存表,即fork操作耗时跟内存量关系较大
    A:fork耗时应该在20ms/GB;应该严格控制每个实例可使用的最大内存10GB以内(复制空间内存表);降低fork操作执行频率
  2. AOF刷盘阻塞
    Q:虽然AOF刷盘是子线程执行的,但是主线程会对比上次刷盘成功时间,如果距上次同步成功时间大于2秒,主线程会阻塞,直到同步完成
    A:everysec最多会丢失两秒的数据,发生阻塞时会有相应的阻塞日志
  3. CPU竞争
    Q:Redis是CPU密集型应用,当其它进程过度消耗CPU时,会严重影响Redis的吞吐量;尽量避免Redis和CPU绑定,因为AOF重写时对CPU占用挺高,产生了父子进程的竞态条件严重影响主进程的性能
    A:避免与其他CPU密集型应用同机器部署,避免和CPU绑定;如果部署多实例,最好保证同一时刻只有一个子进程执行重写
  4. 网络问题
    Q: 1、网络割接、带宽耗尽、网络延迟
      2、达到最大连接数  
      3、机器进程限制连接  
    A:对于Q1这个是考虑到集群部署,如果单纯为了网络性能,不考虑容灾同物理机部署是最优,当然不可能不考虑容灾,可优先考虑同机架同机房部署;
    对于Q2是因为一些访问生命周期较短的应用,在redis层面默认不会主动释放空闲链接,容易造成连接数快速消耗;对此可开启保活机制 即tcp-keepalive和timeout参数
    对于Q3因为每个链接对于机器来说就是一个个的fd(文件句柄),一般默认是1024,当连接数大于该值时机器会在机器层面禁止,所以可适当增大该值

部分阻塞问题定位

  1. client list命令:
    输入缓冲区: redis为每个客户端分配了输入缓冲区,其会将客户端发送命令临时保存,然后取出来执行 qbuf表示总容量,qbuf-free表示剩余容量;大小不能超过1G,当大小超过1G时会将客户端自动关闭,输入缓冲区不收maxmemory限制
    输出缓冲区: 保存命令执行结果obl固定缓冲区,oll动态缓冲区,omem使用字节数,可通过client-output-buffer-limit参数控制
    当大量的key进入输入缓冲区且无法被消费时,即可造成redis阻塞;通过该命令可定位发生阻塞的客户端
  2. info clients命令:
    blocked_clients参数可以查看到当前阻塞的命令
  3. 监控慢查询
    使用slow get n命令监控,将慢查询反馈给业务开发并提出优化建议 禁止keys * ,hgetall,sort,monitor命令的使用
  4. 使用redis-cli – bigkeys查询数据库中的大对象,反馈给业务,进行适当地拆分