21 | 缓冲区:一个可能引发“惨案”的地方

123 阅读4分钟

基本概念

  • 缓冲区:解决发送发和接收方速度差异过大,举个栗子:消息队列

    • 这里特指:用一块内存空间来暂时存放命令数据,以免出现因为数据和命令的处理速度慢于发送速度而导致的数据丢失和性能问题
    • 当速度差异过大时,堆积数据增加,会导致缓冲区溢出
  • redis中缓冲区

    • 将客户端的命令数据缓存下来
    • 主从节点同步时,暂存主节点接收的写命令和速度

客户端输入和输出缓冲区

  • 服务器端给每个连接的客户端都设置了一个输入缓冲区输出缓冲区(有n个客户端,即有n段缓冲区)

    • 输入缓冲区 先把客户端发送过来的命令暂存起来,等待redis主线程读取指令
    • 输出缓冲区 redis处理完成后,将结果写到输出缓冲区中

如何应对输入缓冲区溢出?

  • 溢出的情况

    • 1.写入了 bigkey,比如一下子写入了多个百万级别的集合类型数据
    • 2.服务器端处理请求的速度过慢,导致缓存区堆积越来越多
  • 如何查看输入缓冲区的内存使用情况\

    • 使用 CLIENT LIST 命令查看缓冲区使用情况\

      • 重点关注

      • 服务器端连接的客户端的信息\

      • cmd 客户端最新执行的命令\

      • qbuf 缓冲区已经使用的大小\

      • qbuf-free 缓冲区尚未使用的大小\

      • 缓冲区总量:qbuf+qbuf-free

  • 当缓冲区溢出后,redis会去淘汰数据

  • 如何解决输入缓冲区溢出\

    • 调大缓冲区

      • Redis 服务器端允许为每个客户端最多暂存 1GB 的命令和数据
      • 没有提供调大缓冲区的方法
    • 数据命令的发送和处理速度

      • 避免客户端写入 bigkey,以及避免 Redis 主线程阻塞

如何应对输出缓冲区溢出?

  • 返回消息

    • OK 响应\

    • 报错信息\

    • 大小不固定的、包含具体数据的执行结果\

  • redis输出缓冲区组成

    • 大小16kb的固定缓冲空间  ok和出错信息
    • 动态增加缓冲空间,缓存大小可变的响应结果
  • 什么情况会导致缓冲区溢出

    • 服务器端返回 bigkey 的大量结果\

    • 执行了 MONITOR 命令\

      • 监测redis执行的,持续输出监测到各个命令操作
      • MONITOR 的输出结果会持续占用输出缓冲区\
    • 缓冲区大小设置得不合理\

      • 设置输出缓冲区持续写入数据的数量上限阈值\

      • 持续写入数据的时间的上限阈值\

      • client-output-buffer-limit\

        • 设置缓冲区大小的上限阈值\

        • 设置输出缓冲区持续写入数据的数量上限阈值,和持续写入数据的时间的上限阈值\

  • redis客户端类型

    • 普通客户端 client-output-buffer-limit normal 0 0 0\

    • 订阅客户端 client-output-buffer-limit pubsub 8mb 2mb 60\

  • 怎么处理

    • 避免 bigkey 操作返回大量数据结果

    • 避免在线上环境中持续使用 MONITOR 命令\

    • 使用 client-output-buffer-limit 设置合理的缓冲区大小上限,或是缓冲区连续写入时间和写入量上限\

主从集群中的缓冲区

  • 主从同步方式

    • 全量复制:同步所有数据

      • 原理

        • 主节点在向从节点传输 RDB 文件的同时,会继续接收客户端发送的写命令请求\

        • 这些写命令就会先保存在复制缓冲区中,等 RDB 文件传输完成后,再发送给从节点去执行\

        • 如果从节点消费速度慢,会导致缓冲区堆积

      • 解决办法

        • 控制数据量在2~4GB
        • 使用 client-output-buffer-limit 配置项,来设置合理的复制缓冲区大小 config set client-output-buffer-limit slave 512mb 128mb 60\
    • 增量复制:只会返回断网期间的命令(复制积压缓冲区的溢出问题)

      • 基本概念

        • 一个大小有限的环形缓冲区\

        • 调整大小:repl_backlog_size

      • \

  • 主从用到的缓冲区是n个从节点*缓存区大小

\

总结

  • 缓冲区分类

    • 客户端的输入缓冲区

    • 客户端的输出缓冲区\

    • 主从集群中主节点上的复制缓冲区\

    • 复制积压缓冲区\

  • 问题

    • 缓冲区溢出导致网络连接关闭\

    • 缓冲区溢出导致命令数据丢失\

  • 缓冲区溢出的原因

    • 针对命令数据发送过快过大的问题,对于普通客户端来说可以避免 bigkey,而对于复制缓冲区来说,就是避免过大的 RDB 文件。\

    • 针对命令数据处理较慢的问题,解决方案就是减少 Redis 主线程上的阻塞操作,例如使用异步的删除操作\

    • 针对缓冲区空间过小的问题,解决方案就是使用 client-output-buffer-limit 配置项设置合理的输出缓冲区、复制缓冲区和复制积压缓冲区大小(输入缓冲区不需要修改)\

\