redis客户端缓冲区

redis客户端缓冲区

Posted by Liangjf on July 20, 2020

redis客户端缓冲区

客户端缓冲区原理

redis网络架构是Reactor模型, 基于io多路复用, 每个客户端一条连接, 然后redis负责监听每个连接的非阻塞io的读写事件, 然后触发对应的响应处理函数

读事件监听是一直存在的, 但是写事件是在需要的时候通过构造一个写对象的结构, 发送到对象结构的客户端写缓冲区, 另外一端会根据客户端写缓冲区的对象有无来触发一次写事件, 然后就会触发ae的写事件响应函数, 发数据发送给客户端. 这样异步处理方式使redis server不会因为网络原因阻塞其他请求的处理.

在这里面, 有一个比较重要的地方:客户端缓冲区, 它是redis服务端提高性能的重要组成.包括了输入缓冲区和写入缓冲区, 输入缓冲区无法控制,最大空间为 1G,如果超过将断开连接。而写入缓冲区可以通过配置来设置大小

每个客户端拥有一个应答缓冲区, 是单线程操作的, 负责把redis对客户端的响应缓存发送出去, 提高性能.

output buffer是Redis为client分配的缓冲区,若为某个客户端分配的output buffer超过了设定的大小,Redis可能会根据配置策略关闭与该端的连接。

参数设置

client-output-buffer-limit

  • 【class】:支持3种客户端:
      1. normal(normal clients)
      1. slave clients and MONITOR clients;
      1. pubsub(clients subcribed to at least one pubsub channel or pattern)
  • 【hard limit】:若output buffer大小超过该值,Redis会立即关闭与对应client的连接
  • 【soft limit】 【soft seconds】:若output buffer大小超过soft limit且这种情况的持续时间超过soft seconds,则Redis会关闭与对应client的连接。

默认的配置如下

  • client-output-buffer-limit normal 0 0 0
  • client-output-buffer-limit slave 256mb 64mb 60
  • client-output-buffer-limit pubsub 32mb 8mb 60

client-output-buffer会占据redis的maxmemory, 所以client-output-buffer设置过大, 那就留给redis存储kv的空间变小, 因此容易触发内存淘汰.

保护机制

redis server触发保护机制主要有两种情况

  • 1) 持续性限制: client-output-buffer达到soft limit, 并持续soft seconds,将立即断开和客户端的连接
  • 2) 大小限制: client-output-buffer达到hard limit, 会立即断开和客户端的连接

##例子

  1. keys命令, 会把所有的kv都拉到client-output-buffer, 非常容易超过限制, 就会触发内存淘汰, 把一些kv清理出去, 这样可以会对现有的系统造成影响, 比如当前的qps非常大, 那么就会因淘汰了kv, 造成请求穿透到db, 击垮db, 从而造成联级反应, 整个系统雪崩

所以生产环境要禁止使用keys命令, 可以用SCAN命令代替

  1. 主从复制同步时, 数据量较大, 有可能撑爆client-output-buffer, 所以发生主从复制延时, 而导致client-output-buffer上涨的情况要监控, 避免因 主从复制拖垮整个系统

内存监控

输入输出缓冲区在大流量场景中容易失控,造成Redis内存不稳定,因此需要重点监控。

可以定期执行 client list 命令,监控每个客户端的输入输出缓冲区大小和其他信息。 但是client list 命令执行速度慢,客户端较多时频繁执行存在阻塞redis的可能,所以一般先使用 info clients 命令获取最大的客户端缓冲区大小, 然后针对性的查询对应的client信息。

127.0.0.1:6379> CLIENT LIST
id=5 addr=127.0.0.1:41776 fd=8 name= age=12 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client
127.0.0.1:6379> info clients
# Clients
connected_clients:1
client_recent_max_input_buffer:2
client_recent_max_output_buffer:0
blocked_clients:0