日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網(wǎng)站首頁 編程語言 正文

Redis 性能影響 - 內(nèi)存碎片和緩沖區(qū)

作者:Zong_0915 更新時間: 2022-08-13 編程語言

Redis 性能影響 - 內(nèi)存碎片和緩沖區(qū)

  • 一. 內(nèi)存碎片帶來的性能影響
    • 1.1 內(nèi)存碎片的形成
    • 1.2 清理內(nèi)存碎片
    • 1.3 總結
  • 二. 內(nèi)存緩沖區(qū)溢出問題
    • 2.1 客戶端通信中的緩沖區(qū)
      • 2.1.1 輸入緩沖區(qū)溢出和避免
      • 2.1.2 輸出緩沖區(qū)溢出和避免
    • 2.2 主從集群中的緩沖區(qū)
      • 2.2.1 復制緩沖區(qū)溢出和避免
      • 2.2.2 復制積壓緩沖區(qū)溢出和避免
    • 2.3 總結

一. 內(nèi)存碎片帶來的性能影響

首先,我們需要明確并且知道一點:Redis中刪除某個數(shù)據(jù)之后,實際上是將Redis 釋放的內(nèi)存空間會由內(nèi)存分配器管理,并不會立即返回給操作系統(tǒng)。因此在一定的時間操作系統(tǒng)仍然記錄著這個刪除的key占用的內(nèi)存。

問題:Redis釋放的內(nèi)存不一定是連續(xù)的,因此這種不連續(xù)的內(nèi)存空間就有可能無法拿來保存數(shù)據(jù)。那么就會變相的減少Redis能夠實際保存的數(shù)據(jù)量

換句話說:應用程序申請的是一塊連續(xù)的內(nèi)存地址,但是實際上機器提供的卻是內(nèi)存碎片。

1.1 內(nèi)存碎片的形成

內(nèi)存碎片形成的原因主要有2點:

  • 內(nèi)因:操作系統(tǒng)的內(nèi)存分配機制。
  • 外因:Redis的負載特征造成。

首先來說下內(nèi)因:內(nèi)存分配器會按照固定大小來分配內(nèi)存,而不是按需分配。例如Linux下默認是4KB,開啟內(nèi)存大頁機制后就變成2MB

Redis中使用jemalloc分配器來分配內(nèi)存。它會按照一系列固定大小的內(nèi)存來進行分配。例如當Redis中需要申請一個20B大小的空間來保存數(shù)據(jù),那么jemalloc分配器就會分配32B

  • 倘若此時應用還要寫入5B大小的數(shù)據(jù),那么無需申請額外的空間。
  • 倘若此時應用還要寫入20B大小的數(shù)據(jù),那么必須在申請額外的空間了,此時就會有產(chǎn)生內(nèi)存碎片的風險(之前分配的32B中,10B就是內(nèi)存碎片了)

如圖:
在這里插入圖片描述


緊接著就是外因部分了:

首先我們一個Redis實例,里面有著不同大小的鍵值對,那么根據(jù)內(nèi)存分配器的分配機制來看。就有可能分配著不同大小的連續(xù)內(nèi)存空間。

另一方面,我們對鍵值對也有可能有著不同的操作,增刪改查。那么看下這個圖:
在這里插入圖片描述
上圖中,白色部分的就是內(nèi)存碎片,可以看出大小不一的鍵值對以及修改刪除操作導致產(chǎn)生了內(nèi)存碎片。

1.2 清理內(nèi)存碎片

清理內(nèi)存碎片之前,首先應該做的就是判斷是否有內(nèi)存碎片:

info memory

結果如下:
在這里插入圖片描述
請看我紅色框框圈起來的地方:

mem_fragmentation_ratio:3.22

mem_fragmentation_ratio代表Redis實例當前的內(nèi)存碎片率。其計算公式為:

mem_fragmentation_ratio = used_memory_rss / used_memory
  • used_memory_rss:操作系統(tǒng)實際分配Redis的物理內(nèi)存空間。
  • used_memoryRedis為了保存數(shù)據(jù)而實際申請的空間。

針對mem_fragmentation_ratio,有兩個參考:

  • mem_fragmentation_ratio ∈ (1, 1.5]:屬于合理范圍內(nèi),暫時可以放放。
  • mem_fragmentation_ratio ∈ (1.5, +∞)表明內(nèi)存碎片率超過了50%,需要采取措施降低內(nèi)存碎片率。

那么如何清理內(nèi)存碎片呢(一般不會重啟實例,因為生產(chǎn)上往往不允許這種神操作出現(xiàn)),在Redis4.0-RC3 版本以后,Redis提供了內(nèi)置的內(nèi)存碎片清理機制。

# 開啟自動內(nèi)存碎片清理功能
config set activedefrag yes

開啟自動清理機制之后,需要同時滿足兩個條件才可以觸發(fā)執(zhí)行:

  • active-defrag-ignore-bytes 100mb:表示內(nèi)存碎片的字節(jié)數(shù)達到 100MB 時,開始清理。
  • active-defrag-threshold-lower 10:表示內(nèi)存碎片空間占操作系統(tǒng)分配給 Redis 的總空間比例達到 10% 時,開始清理。

在這里插入圖片描述

除此之外,值得注意的是,雖然Redis提供了這樣的自動內(nèi)存清理機制,能夠帶來清理內(nèi)存碎片的好處,但是與此同時的必定有著其對應的犧牲,也就是性能影響問題:

  • 碎片清理是有代價的:操作系統(tǒng)需要把多份數(shù)據(jù)拷貝到新位置,把原有空間釋放出來,這會帶來時間開銷
  • Redis 是單線程,在數(shù)據(jù)拷貝時,Redis 進入阻塞狀態(tài),從而導致 Redis 無法及時處理請求,性能就會降低。

因此在開啟自動清理內(nèi)存碎片機制的情況下,需要合理考慮得失。Redis就提供了另外的兩個參數(shù):控制清理操作占用的 CPU 時間比例的上下限。
active-defrag-cycle-min 25: 表示自動清理過程所用 CPU 時間的比例不低于 25%,保證清理能正常開展。
active-defrag-cycle-max 75:表示自動清理過程所用 CPU 時間的比例不高于 75%一旦超過,就停止清理。

上述4個相關的配置如下(我的機器):
在這里插入圖片描述

問題來了,如果mem_fragmentation_ratio的值小于1,代表什么?

前面我們知道,著個指標的計算用大白話來說就是 總物理內(nèi)存 / 實際數(shù)據(jù)所需內(nèi)存。小于1,代表總物理內(nèi)存不夠數(shù)據(jù)存儲了,那不就開啟swap機制了嗎!

  1. Redis沒有足夠的物理內(nèi)存可以使用,這會導致Redis一部分內(nèi)存數(shù)據(jù)會被換到Swap中。
  2. 那么之后當Redis訪問Swap中的數(shù)據(jù)時,延遲會變大,性能下降。

那可不行,那如果你的Redis實例中,這個指標小于1,趕緊加大內(nèi)存,或者考慮搞成Redis集群!

1.3 總結

到這里為止,文章中個人認為最重要的幾個點是:

  1. 通過info memory命令查看內(nèi)存的使用情況。
  2. mem_fragmentation_ratio,如果超過了1.5,建議可以考慮進行內(nèi)存碎片的清理了。
  3. 內(nèi)存碎片的清理可以開啟自動清理內(nèi)存碎片機制,是主線程執(zhí)行的會發(fā)生阻塞。需要合理配置對應的參數(shù),保證Redis的高性能。
  4. mem_fragmentation_ratio如果值小于1,說明物理內(nèi)存不夠真實數(shù)據(jù)的保存了,此時機器應該開啟了swap機制,會導致Redis性能的嚴重下降。應該考慮增加機器的內(nèi)存配置了,或者搞集群。

二. 內(nèi)存緩沖區(qū)溢出問題

背景:客戶端和服務端之間,有一個輸入和輸出緩沖區(qū)。主要用來避免請求或者數(shù)據(jù)丟失。在Redis中主要有兩個應用場景:

  • 就是在客戶端和服務器端之間進行通信時:用來暫存客戶端發(fā)送的命令數(shù)據(jù),或者是服務器端返回給客戶端的數(shù)據(jù)結果。
  • 主從節(jié)點間進行數(shù)據(jù)同步時:用來暫存主節(jié)點接收的寫命令和數(shù)據(jù)。

服務器會和每個連接的客戶端都設置一個輸入輸出緩沖區(qū),大概圖如下:
在這里插入圖片描述

2.1 客戶端通信中的緩沖區(qū)

緩沖區(qū)的功能我們說過:主要就是用一塊內(nèi)存空間來暫時存放命令數(shù)據(jù)。

那么什么是緩沖區(qū)溢出?

倘若如果往里面寫入數(shù)據(jù)的速度持續(xù)地大于從里面讀取數(shù)據(jù)的速度,就會導致緩沖區(qū)需要越來越多的內(nèi)存來暫存數(shù)據(jù)。當緩沖區(qū)占用的內(nèi)存超出了設定的上限閾值時,就會出現(xiàn)緩沖區(qū)溢出。

2.1.1 輸入緩沖區(qū)溢出和避免

導致輸入緩沖區(qū)溢出的情況主要分為兩種:

  • 寫入bigkey
  • 服務器端處理請求的速度太慢。比如Redis主線程出現(xiàn)了阻塞。

那么如何避免溢出呢?可以使用以下命令來查看服務端和客戶端之間的輸入緩沖區(qū)的使用情況:

client list

結果如下:

id=7392 addr=127.0.0.1:54854 laddr=127.0.0.1:6379 fd=9 name= age=5007 idle=0 flags=N db=0 sub=0 psub=0 
multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 
tot-mem=61466 events=r cmd=client user=default redir=-1

圖示:
在這里插入圖片描述
其中比較重要的幾個參數(shù):

  • addr:不同客戶端的IP和端口號。
  • qbuf:表示輸入緩沖區(qū)已經(jīng)使用的大小。單位字節(jié)。
  • cmd:客戶端最新執(zhí)行的命令。
  • qbuf-free:輸入緩沖區(qū)剩余的可用空間大小。單位字節(jié)。

那么倘若 qbuf-free值太小,就需要引起注意,因為此時一旦寫入大量命令,就容易引起緩沖區(qū)的溢出。

對于輸入緩沖區(qū)。我們可以從兩個方面去考慮避免溢出:

  • 輸入緩沖區(qū)規(guī)定上限是1GB。因此其無法增大。該方案行不通。
  • 從命令和數(shù)據(jù)發(fā)送方考慮:避免客戶端寫入 bigkey,以及避免 Redis 主線程阻塞。

2.1.2 輸出緩沖區(qū)溢出和避免

對于輸出緩沖區(qū),其主要分為兩個部分:

  • 固定緩沖空間16KB,用于暫存OK響應和出錯信息。例如:
    在這里插入圖片描述

  • 動態(tài)緩沖空間:用來暫存可以變的響應結果。例如:
    在這里插入圖片描述

輸出緩沖區(qū)發(fā)生溢出主要有三種情況:

  • 服務器端返回bigkey的大量數(shù)據(jù)。
  • 執(zhí)行了monitor命令。
  • 緩沖區(qū)大小設置不合理。

對于bigkey,無論是輸入還是輸出緩沖區(qū),都會有很大的影響,而且Redis本身的性能也受其影響,bigkey相關內(nèi)存的開辟和釋放,都需要很大的資源去消耗。無論從各個方面來考慮,bigkey的存在都是不建議有的。

然后是monitor命令,我們來看下他是干啥的:

  1. 首先準備兩個會話,會話1 輸入monitor命令,進入監(jiān)控。
    在這里插入圖片描述

  2. 另外一個 會話2 可以隨便執(zhí)行幾個命令,如圖:
    在這里插入圖片描述

  3. 此時 會話1 的監(jiān)控頁面:
    在這里插入圖片描述

  4. MONITOR 的輸出結果會持續(xù)占用輸出緩沖區(qū),最后的結果就是發(fā)生溢出。 因此這個命令不要再生產(chǎn)上使用。


其次就是關于輸出緩沖區(qū)大小的設置,這點和輸入緩沖區(qū)并不相同,輸入緩沖區(qū)的大小不可設置。而輸出緩沖區(qū)可以。通過client-output-buffer-limit來配置。它主要有四個參數(shù):

  • 客戶端類型。
  • 緩沖區(qū)的大小。
  • 緩沖區(qū)持續(xù)寫入的數(shù)據(jù)量限制。
  • 緩沖區(qū)持續(xù)寫入的時間限制。

如果在持續(xù)寫入的時間限制內(nèi)寫入的數(shù)據(jù)量超過了規(guī)定的量或者超出輸出緩沖區(qū)規(guī)定的大小,則會關閉客戶端連接。此時最好根據(jù)客戶端的性質來具體配置:

倘若該客戶端是主要進行讀寫命令交互的普通客戶端:

# 主要進行讀寫命令交互的普通客戶端 normal表示普通客戶端,0代表不限制
client-output-buffer-limit normal 0 0 0

倘若該客戶端是訂閱客戶端,即訂閱了 Redis 頻道的訂閱客戶端。

# pubsub代表訂閱客戶端
client-output-buffer-limit pubsub 8mb 2mb 60

上述配置代表:

  1. 實際占用緩沖區(qū)的大小 > 8MB ,服務端就會關閉與該客戶端的連接。
  2. 60s內(nèi)如果持續(xù)對輸出緩沖區(qū)寫入超過2MB的數(shù)據(jù),同樣關閉與客戶端之間的連接。

2.2 主從集群中的緩沖區(qū)

主從集群之間主要的操作還是在于數(shù)據(jù)的復制,而數(shù)據(jù)的復制分為兩種:

  • 全量復制。

  • 增量復制。

2.2.1 復制緩沖區(qū)溢出和避免

這一塊主要發(fā)生在全量復制這個階段,主庫在向從庫傳輸RDB文件的同時,會將客戶端發(fā)送的寫命令請求保存到復制緩沖區(qū)中。等待文件傳輸完畢,在發(fā)送給從庫去執(zhí)行。如圖:
在這里插入圖片描述

因此,倘若RDB傳輸過程比較久,同時傳輸期間主庫又接收到大量的寫命令,從而導致復制緩沖區(qū)中的命令越來越多,最后導致溢出。

解決:

  1. 控制主節(jié)點保存的數(shù)據(jù)大小。避免全量同步執(zhí)行速度太慢。
  2. 使用 client-output-buffer-limit 命令,設置復制緩沖區(qū)大小。

我們可以看下復制緩沖區(qū)相關的配置:

config get client-output-buffer-limit

結果如下:

在這里插入圖片描述
還記得 2.1.2 小節(jié)中對于輸出緩沖區(qū)的設置嗎?我們可以發(fā)現(xiàn)用的是同一個命令,只不過有以下區(qū)別:

  • pubsub:就是訂閱客戶端。
  • normal:常規(guī)的客戶觀(進行簡單的命令交互)。
  • slave該配置項就是針對復制緩沖區(qū)的。

那么設置的時候我們可以這么來:

# 設置的時候請加上slave,因為一共有三種,這里需要指定的是復制緩沖區(qū)的配置
# 復制緩沖區(qū)上限為512mb,超過了就斷開連接
# 2分鐘內(nèi)寫入的數(shù)據(jù)超過64mb,斷開連接
config set client-output-buffer-limit slave 512mb 64mb 120

2.2.2 復制積壓緩沖區(qū)溢出和避免

復制積壓緩沖區(qū)(即repl_backlog_buffer,在Redis - Redis主從數(shù)據(jù)一致性和哨兵機制中有提到)主要作用于增量復制

  1. 主節(jié)點在把接收到的寫命令同步給從節(jié)點時,同時會把這些寫命令寫入復制積壓緩沖區(qū)。
  2. 一旦從節(jié)點發(fā)生宕機,當重啟后,從節(jié)點就會從復制積壓緩沖區(qū)中,讀取斷連期間主節(jié)點接收到的寫命令,進而進行增量同步。

如圖:
在這里插入圖片描述

因為在相關文章中講到過了,這里就截個圖:
在這里插入圖片描述
因此可以適當調(diào)大一點這個值。

2.3 總結

文章提到了4個緩沖區(qū)。

  • 輸入緩沖區(qū):保存客戶端發(fā)送的命令。
  • 輸出緩沖區(qū):保存服務端返回的數(shù)據(jù)。
  • 復制緩沖區(qū):用于全量復制時,保存新寫入的命令。
  • 復制積壓緩沖區(qū):用于增量復制時,保存新寫入的命令

從文章的內(nèi)容來看:

  1. 服務端和每個客戶端之間都存在對應的幾種緩沖區(qū)。
  2. 當發(fā)生了緩沖區(qū)溢出,服務端會斷開與對應客戶端之間的連接。
  3. 此時會導致朱從節(jié)點同步失敗,或者程序無法讀寫Redis

緩沖區(qū)溢出,可以從三個方面來分別解決:

命令數(shù)據(jù)發(fā)送太快。

  1. 與普通客戶端:避免bigkey
  2. 復制緩沖區(qū):避免大型RDB文件的產(chǎn)生。

命令數(shù)據(jù)處理太慢:減少Redis主線程上的阻塞操作。可以有針對的利用異步機制。


緩沖區(qū)太小了:

  1. 使用 client-output-buffer-limit 進行相關配置,主要配置輸出緩沖區(qū)和復制緩沖區(qū)。
  2. repl_backlog_buffer進行相關配置,增大復制積壓緩沖區(qū)。
  3. 輸入緩沖區(qū)大小無法修改。
  4. 避免在生產(chǎn)上使用monitor監(jiān)控命令。

原文鏈接:https://blog.csdn.net/Zong_0915/article/details/126302182

欄目分類
最近更新