>  기사  >  데이터 베이스  >  Redis 버퍼 메커니즘 분석 예시

Redis 버퍼 메커니즘 분석 예시

王林
王林앞으로
2023-05-31 08:40:401496검색

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

## 普通客户端配置
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代表没有限制

클라이언트가 연결될 때마다 입력 버퍼 정보가 하나 더 생성됩니다 , 위 명령은 두 클라이언트에 대한 로컬 연결의 결과입니다. 버퍼를 볼 때 주로 두 가지 메모리 관련 매개 변수
  • 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 쓰기를 피해야 하며 일반적으로 명령 처리를 분할해야 합니다. 서버의 속도는 일반적으로 메인 스레드의 차단 여부에 따라 AOF 파일 재작성, 키 값 삭제, 포크 스레드 등과 같은 일부 차단 작업을 피해야 합니다. 🎜🎜출력 버퍼 오버플로에 대한 대처🎜🎜서버의 경우 클라이언트의 입력 정보는 일반적으로 예측할 수 없지만 출력 정보는 대부분 예측 가능합니다. 예를 들어 Set 명령은 간단한 OK를 반환하고 일부 오류 메시지는 Redis에서 할당합니다. 이러한 상수 반환 정보에 대한 16KB의 고정 버퍼 공간은 출력 버퍼가 두 부분으로 나누어져 있음을 의미합니다. 한 부분은 출력 버퍼 고정 반환 정보이고 다른 부분은 가변 반환 정보입니다. 🎜🎜출력 버퍼 오버플로는 세 가지 상황으로 구분됩니다. 🎜🎜🎜🎜bigkey와 같은 대용량의 키 값을 출력합니다. 🎜🎜🎜🎜클라이언트는 Monitor 명령을 실행하여 Redis 실행을 모니터링합니다. 🎜🎜🎜🎜버퍼 설정이 무리네요. 🎜🎜🎜🎜Bigkey는 서버가 bigkey나 키와 같은 명령을 출력할 때 쿼리가 입력 버퍼에서 많은 양의 메모리 공간을 순간적으로 차지하기 때문에 출력 버퍼에 대한 테스트가 매우 큰 문제입니다. . 🎜🎜Monitor 명령 실행🎜🎜Monitor 명령은 일반적으로 Redis의 특정 실행을 모니터링하는 데 사용되는 디버그 명령이며 서버에서 처리되는 모든 명령을 반환할 수 있습니다. 🎜rrreee🎜 모니터를 계속 실행하면 항상 출력 버퍼를 차지하게 됩니다. 즉, 차지하는 시간이 길어질수록 출력 버퍼가 오버플로되기 쉽습니다. 따라서 모니터 명령은 디버깅 환경에만 적합하며 사용할 수 없습니다. 생산에서 실행됩니다. 🎜🎜출력 버퍼 설정이 무리입니다🎜🎜입력 버퍼의 크기는 설정할 수 없으나, 출력 버퍼의 크기는 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 버퍼 메커니즘 분석 예시의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제