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

學(xué)無(wú)先后,達(dá)者為師

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

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

作者:Zong_0915 更新時(shí)間: 2022-08-13 編程語(yǔ)言

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

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

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

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

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

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

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

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

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

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

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

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

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


緊接著就是外因部分了:

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

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

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

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

info memory

結(jié)果如下:
在這里插入圖片描述
請(qǐng)看我紅色框框圈起來(lái)的地方:

mem_fragmentation_ratio:3.22

mem_fragmentation_ratio代表Redis實(shí)例當(dāng)前的內(nèi)存碎片率。其計(jì)算公式為:

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

針對(duì)mem_fragmentation_ratio,有兩個(gè)參考:

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

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

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

開(kāi)啟自動(dòng)清理機(jī)制之后,需要同時(shí)滿足兩個(gè)條件才可以觸發(fā)執(zhí)行:

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

在這里插入圖片描述

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

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

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

上述4個(gè)相關(guān)的配置如下(我的機(jī)器):
在這里插入圖片描述

問(wèn)題來(lái)了,如果mem_fragmentation_ratio的值小于1,代表什么?

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

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

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

1.3 總結(jié)

到這里為止,文章中個(gè)人認(rèn)為最重要的幾個(gè)點(diǎn)是:

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

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

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

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

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

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

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

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

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

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

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

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

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

client list

結(jié)果如下:

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

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

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

那么倘若 qbuf-free值太小,就需要引起注意,因?yàn)榇藭r(shí)一旦寫(xiě)入大量命令,就容易引起緩沖區(qū)的溢出。

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

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

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

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

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

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

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

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

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

然后是monitor命令,我們來(lái)看下他是干啥的:

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

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

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

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


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

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

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

倘若該客戶端是主要進(jìn)行讀寫(xiě)命令交互的普通客戶端:

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

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

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

上述配置代表:

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

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

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

  • 全量復(fù)制。

  • 增量復(fù)制。

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

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

因此,倘若RDB傳輸過(guò)程比較久,同時(shí)傳輸期間主庫(kù)又接收到大量的寫(xiě)命令,從而導(dǎo)致復(fù)制緩沖區(qū)中的命令越來(lái)越多,最后導(dǎo)致溢出。

解決:

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

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

config get client-output-buffer-limit

結(jié)果如下:

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

  • pubsub:就是訂閱客戶端。
  • normal:常規(guī)的客戶觀(進(jìn)行簡(jiǎn)單的命令交互)。
  • slave該配置項(xiàng)就是針對(duì)復(fù)制緩沖區(qū)的。

那么設(shè)置的時(shí)候我們可以這么來(lái):

# 設(shè)置的時(shí)候請(qǐng)加上slave,因?yàn)橐还灿腥N,這里需要指定的是復(fù)制緩沖區(qū)的配置
# 復(fù)制緩沖區(qū)上限為512mb,超過(guò)了就斷開(kāi)連接
# 2分鐘內(nèi)寫(xiě)入的數(shù)據(jù)超過(guò)64mb,斷開(kāi)連接
config set client-output-buffer-limit slave 512mb 64mb 120

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

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

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

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

因?yàn)樵谙嚓P(guān)文章中講到過(guò)了,這里就截個(gè)圖:
在這里插入圖片描述
因此可以適當(dāng)調(diào)大一點(diǎn)這個(gè)值。

2.3 總結(jié)

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

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

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

  1. 服務(wù)端和每個(gè)客戶端之間都存在對(duì)應(yīng)的幾種緩沖區(qū)。
  2. 當(dāng)發(fā)生了緩沖區(qū)溢出,服務(wù)端會(huì)斷開(kāi)與對(duì)應(yīng)客戶端之間的連接。
  3. 此時(shí)會(huì)導(dǎo)致朱從節(jié)點(diǎn)同步失敗,或者程序無(wú)法讀寫(xiě)Redis

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

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

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

命令數(shù)據(jù)處理太慢:減少Redis主線程上的阻塞操作??梢杂嗅槍?duì)的利用異步機(jī)制。


緩沖區(qū)太小了:

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

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

欄目分類
最近更新