浅谈Redis缓冲区机制


Posted in Redis onJune 05, 2022

Redis缓冲区机制

Redis中的缓冲区机制就是为了平衡客户端发送命令和服务端处理命令的速度差异,如果客户端写入过快或者服务端读取过慢这就会导致缓冲区溢出,缓冲区一旦溢出将引发一系列的性能问题,下面我们详细聊聊。

客户端缓冲机制

Redis为每一个客户端都分配了一个输入缓冲区和输出缓冲区,输入缓冲区会把客户端的请求命令暂存起来,Redis主线程会从缓冲区中获取命令,当Redis处理完命令后会将结果写入到输出缓冲区中,通过输出缓冲区返回给客户端,如下所示

浅谈Redis缓冲区机制

应对输入缓冲区溢出

输入缓冲区溢出一般就是两种情况

  • 写入数据过快,或者写入bigkey的数据占满数据缓冲区。
  • 服务端处理数据过慢,一般是主线程被阻塞无法正常响应客户端请求。

查看输入缓冲区信息

我们可以采用client list查看输入缓冲区的具体信息

127.0.0.1:6379> client list
id=13 addr=127.0.0.1:50484 fd=7 name= age=1136 idle=1 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 user=default
id=14 addr=127.0.0.1:50486 fd=8 name= age=1114 idle=6 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=client user=default

每连接上一个客户端就会多一条输入缓冲区信息,上面命令是我本地连接两个客户端的结果,我们查看缓冲区主要关注内存相关的两个参数

  • qbuf:缓冲区已经使用的长度(字节为单位,0表示没有分配缓冲区)。
  • qbuf-free:缓冲区剩余空闲空间(字节为单位),上面一个客户端的qbuf=26,空闲缓冲区qbuf-free=32742,那么分配内存总大小为26+32742=32768字节也就是32KB。

如果输入缓冲区信息中的qbuf-free很小并且qbuf很大时就需要注意了,这时输入缓冲区可能已经快溢出了,如果此时还有大量请求写入输入缓冲区,Redis的解决办法就是关闭和这个客户端的连接,那么业务数据将无法正常存取。

而且还有一个问题就是输入缓冲区是每一个客户端都会存在,那么当所有客户端的输入缓冲区内存总和超过了maxmemory配置,那么将引发内存淘汰,部分淘汰的数据再次访问需要从后台数据库获取,获取的耗时肯定比Redis直接读取慢的多,所以这也是Redis产生延迟的一个原因。

如何解决输入缓冲区溢出

输入缓冲区溢出本质就是缓冲区的容量不够,所以第一个思路就是扩大输入缓冲区的大小,很不幸Redis没有提供给我们修改输入缓冲区大小的配置,Redis要求每个客户端的输入缓冲区最大不能超过1G,注意是每个客户端!!!,如果客户端的输入缓冲区超过一个1G将关闭客户端连接,所以这个是行不通的。

那就只能从客户端发送数据的大小以及服务端处理命令的速度,客户端需要避免bigkey的写入bigkey的劣势太多一般都需要拆分,第二服务端的命令处理速度这个一般依赖于主线程是否阻塞,需要尽量的避免一些阻塞操作如AOF文件重写,键值删除,fork线程等等。

应对输出缓冲区溢出

对于服务端而言,客户端的输入信息通常都是不可预测的,但是输出信息大多可以预测,如Set命令返回信息只是一个简单的OK,又如一些报错信息,Redis为这些不变的返回信息分配了16KB的固定缓冲空间,也就是说输出缓冲区分为两个部分一部分是输出缓冲区固定返回信息,一部分是可变的返回信息。

输出缓冲区溢出分为三种情况

  • 输出bigkey等容量大的键值。
  • 客户端执行Monitor命令,监控Redis执行。
  • 缓冲区设置不合理。

bigkey是老生常谈的一个问题,当服务端输出一个bigkey或者keys这类命令,对输出缓冲区的考验是非常大的,因为查询的一瞬间会占据输入缓冲区大量的内存空间。

Monitor命令的执行

Monitor命令一般是一个debug命令,用来监控Redis的具体执行情况,能够返回服务器处理的每一个命令。

127.0.0.1:6379> monitor
OK
1652184977.609761 [0 127.0.0.1:50484] "get" "name"
1652185391.529292 [0 127.0.0.1:50484] "set" "test" "lisi"
......

一直运行monitor将一直占据输出缓冲区,也就是说占据时间越长,越容易造成输出缓冲区的溢出,所以Monitor命令仅仅只适用于调试环境,不能在生产上执行这些命令。

输出缓冲区设置不合理

输入缓冲区的大小不能设置,但是输出缓冲区的是可以设置的我们可以通过配置项client-output-buffer-limit来设置,设置的内容就是两部分

  • 缓冲区的内存大小,当超过缓冲区配置的大小,服务端会关闭和客户端的连接。
  • 持续写入的时间限制和持续写入的容量限制,当超过持续写入时间限制和容量限制,服务端也会强制关闭和客户端的连接。

客户端种类

在聊缓冲区配置时,我们需要先了解下客户端的种类,本文中强调的客户端并不是单纯指通过命令./redis-cli -c -h 127.0.0.1 -p 6379去连接Redis服务器这类客户端称为常规客户端,我们还有通过消息订阅Redis频道的客户端,还有一种最为特殊的主从同步,从节点也是一个特殊的客户端称为从节点客户端。

配置项client-output-buffer-limit也是针对这三种,给出了不一样的配置,如下所示

## 普通客户端配置
client-output-buffer-limit normal 0 0 0
## 从节点客户端配置
client-output-buffer-limit replica 256mb 64mb 60
## 消息订阅频道的客户端
client-output-buffer-limit pubsub 32mb 8mb 60

######################配置解释######################
## 第一个参数:代表分配给客户端的缓存大小,为0代表没有限制
## 第二个参数:表示持续写入的最大内存,为0代表没有限制
## 第三个参数:表示持续写入的最长时间,为0代表没有限制

普通客户端设置

普通客户端就是传输的一些普通的指令,一个指令发送完需要等待其返回后才会发送下一个指令,也就是说只要不是返回的bigkey数据,占用输出缓冲区的内存就极少,能够立即发送给客户端响应,所以一般正常客户端默认配置都是0,也就是不限制。

消息订阅频道客户端

当订阅频道产生消息后,会将消息通过输出缓冲区发送给客户端,这种属于非阻塞的方式,一瞬间可能有多个指令到达,所以需要指定缓冲区大小。

如何解决输出缓冲区溢出

到这里其实我们已经能够得到输出缓冲区溢出的解决方案了

  • bigkey应当避免使用。
  • Monitor命令只在调试的时候使用,不能应用到生产。
  • 合理设置输出缓冲区上限、持续写入时间上限以及持续写入内存容量上限。

主从集群中的缓冲区

除了输入缓冲区和输出缓冲区外在主从集群场景下还存在两种缓冲区,我们称为复制缓冲区和复制积压缓冲区,这两个缓冲区的溢出和输入输出缓冲区稍有不同。

复制缓冲区

复制缓冲区这个名词看着很陌生,但是我们之前在聊主从同步时讲过,主从全量同步期间从节点会加载主节点的RDB文件,这时主节点同样还能写入数据,但是从节点在加载RDB文件没办法实时同步,所以Redis就为每一个从节点开辟了一片空间,用来存放主从全量同步期间产生的操作命令,这就是replication buffer,也就是复制缓冲区。

浅谈Redis缓冲区机制

复制缓冲区溢出

复制缓冲区什么时候会溢出呢?

  • 当从节点在加载RDB文件这个过程中如果存在大量的写操作就会造成复制缓冲区内存溢出。
  • 从节点加载RDB文件的时间过长。

发生溢出后,主节点会关闭与从节点的连接,导致全量同步失败。

解决复制缓冲区溢出

控制主节点实例的大小,减小生成的RDB文件,这样就能减少从节点加载RDB文件的时间,减小复制缓冲区的压力。

从节点其本质就是主节点的特殊客户端,所以使用的是输出缓冲区(也就是指replication buffer),可以设置client-output-buffer-limit replica 256mb 64mb 60扩大缓冲区大小。

注意:主节点上的复制缓冲区会为每一个从节点分配一个,那么从节点的数量过多即使每个从节点没有达到maxmemory,但累加的结果也会给主节点带来内存压力

复制积压缓冲区

复制积压缓冲区溢出

主从集群在写操作时会将操作写入复制缓冲区和复制积压缓冲区中,一旦网络发送故障后恢复连接,在2.8版本之前主从节点会进行全量同步开销非常大,所以2.8版本后还是采用了增量同步,仅仅将网络断开这段时间的操作同步给从节点,所以在网络恢复连接后从节点会将自己的复制偏移量slave_repl_offset发送给主节点,主节点将自身的写入偏移量master_repl_offset和slave_repl_offset在复制积压缓冲区中做对比得到网络断连期间的操作。

复制积压缓冲区又叫repl_backlog_buffer,是一个环形缓冲区,同步示意图如下。

浅谈Redis缓冲区机制

复制积压缓冲区溢出其实也就是因为复制积压缓冲区是一个有限环形结构,一般主节点写入偏移量要大于从节点的读取偏移量,但如果写入偏移量覆盖了从节点的读取偏移量这就引发了复制积压缓冲区溢出。

解决复制积压缓冲区溢出

一般是调整repl_backlog_size这个参数的大小,扩大复制积压缓冲区的大小,减小主节点写入偏移量覆盖从节点读取偏移量的风险。

到此这篇关于浅谈Redis缓冲区机制的文章就介绍到这了,更多相关Redis缓冲区内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

Redis 相关文章推荐
浅谈redis五大数据结构和使用场景
Apr 12 Redis
Redis延迟队列和分布式延迟队列的简答实现
May 13 Redis
详解Redis复制原理
Jun 04 Redis
Redis缓存-序列化对象存储乱码问题的解决
Jun 21 Redis
压缩Redis里的字符串大对象操作
Jun 23 Redis
浅析Redis Sentinel 与 Redis Cluster
Jun 24 Redis
在redisCluster中模糊获取key方式
Jul 09 Redis
厉害!这是Redis可视化工具最全的横向评测
Jul 15 Redis
Redis中缓存穿透/击穿/雪崩问题和解决方法
Dec 04 Redis
Redis集群节点通信过程/原理流程分析
Mar 18 Redis
一文搞懂Redis中String数据类型
Apr 03 Redis
Redis全局ID生成器的实现
Jun 05 #Redis
Redis keys命令的具体使用
Jun 05 #Redis
Redis入门基础常用操作命令整理
Jun 01 #Redis
Redis基本数据类型String常用操作命令
Jun 01 #Redis
Redis基本数据类型List常用操作命令
Jun 01 #Redis
Redis基本数据类型Set常用操作命令
Jun 01 #Redis
Redis基本数据类型哈希Hash常用操作命令
Jun 01 #Redis
You might like
解决控件遮挡问题:关于有窗口元素和无窗口元素
2007/01/28 PHP
php笔记之:文章中图片处理的使用
2013/04/26 PHP
PHP中使用socket方式GET、POST数据实例
2015/04/02 PHP
php生成图片验证码-附五种验证码
2015/08/19 PHP
JavaScript实现动态增加文件域表单
2009/02/12 Javascript
js 多种变量定义(对象直接量,数组直接量和函数直接量)
2010/05/24 Javascript
悄悄用脚本检查你访问过哪些网站的代码
2010/12/04 Javascript
统计jQuery中各字符串出现次数的工具
2012/05/03 Javascript
基于Bootstrap的Metronic框架实现页面链接收藏夹功能
2016/08/29 Javascript
概述javascript在Google IE中的调试技巧
2016/11/24 Javascript
JavaScript三种绑定事件方式及相互之间的区别分析
2017/01/10 Javascript
浅谈ES6 模板字符串的具体使用方法
2017/11/07 Javascript
实例分析js事件循环机制
2017/12/13 Javascript
解决Vue 项目打包后favicon无法正常显示的问题
2018/09/01 Javascript
解决Vue中的生命周期beforeDestory不触发的问题
2020/07/21 Javascript
解决vue-photo-preview 异步图片放大失效的问题
2020/07/29 Javascript
python多线程http下载实现示例
2013/12/30 Python
Python 列表理解及使用方法
2017/10/27 Python
Python基于贪心算法解决背包问题示例
2017/11/27 Python
python 构造三维全零数组的方法
2018/11/12 Python
DataFrame:通过SparkSql将scala类转为DataFrame的方法
2019/01/29 Python
Python pandas RFM模型应用实例详解
2019/11/20 Python
学会python自动收发邮件 代替你问候女友
2020/05/20 Python
Python安装并操作redis实现流程详解
2020/10/13 Python
使用HTML5 Canvas绘制直线或折线等线条的方法讲解
2016/03/14 HTML / CSS
香奈儿美国官网:CHANEL美国
2020/05/20 全球购物
抽象方法、抽象类怎样声明
2014/10/25 面试题
安全负责人任命书
2014/06/06 职场文书
2014年售后服务工作总结
2014/11/18 职场文书
违反工作规定检讨书范文
2014/12/14 职场文书
团代会邀请函
2015/02/02 职场文书
参观邀请函范文
2015/02/02 职场文书
2015年电信员工工作总结
2015/05/26 职场文书
大一新生军训新闻稿
2015/07/17 职场文书
python神经网络编程之手写数字识别
2021/05/08 Python
十大最强岩石系宝可梦,怪颚龙实力最强,第七破坏力很强
2022/03/18 日漫