自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為什么刪除數(shù)據(jù)后,Redis 內(nèi)存占用依然很高?

數(shù)據(jù)庫(kù) Redis 系統(tǒng)
本文以師弟的一個(gè)疑問(wèn)開頭介紹了刪除數(shù)據(jù)導(dǎo)致內(nèi)存占用還是很高的原因是存在內(nèi)存碎片,導(dǎo)致內(nèi)存碎片的兩個(gè)原因。

前言

上周剛來(lái)了個(gè)應(yīng)屆小師弟,組長(zhǎng)說(shuō)讓我?guī)е?,周二?wèn)了我這樣一個(gè)問(wèn)題:師兄啊,我用top命令看了下服務(wù)器的內(nèi)存占用情況,發(fā)現(xiàn)Redis內(nèi)存占用嚴(yán)重,于是我就刪除了大部分不用的keys,為什么內(nèi)存占用還是很嚴(yán)重,并沒(méi)有釋放呢?

嗯?為什么呢?今天就帶著這個(gè)問(wèn)題來(lái)介紹一下如何正確釋放Redis的內(nèi)存。

什么是內(nèi)存碎片?

內(nèi)存碎片這個(gè)概念應(yīng)該不是第一聽說(shuō)了,熟悉JVM或者操作系統(tǒng)的應(yīng)該都熟悉,以火車賣票為例,一個(gè)車廂128個(gè)車位,由于高峰期,只剩余兩個(gè)位置了,但是此時(shí)三個(gè)人想要坐在一起,能夠吹吹牛批,喝喝酒的,那么這三個(gè)人肯定不會(huì)買這節(jié)車廂的兩個(gè)位置了,此時(shí)這兩個(gè)位置可以稱之為座位碎片 。

操作系統(tǒng)中對(duì)于內(nèi)存分配也是一樣的,比如應(yīng)用需要申請(qǐng)一塊連續(xù)N個(gè)字節(jié)的空間,雖然剩余內(nèi)存總量大于N個(gè)字節(jié),但是沒(méi)有一塊連續(xù)的內(nèi)存空間是N個(gè)字節(jié),那么剩余的空間就是內(nèi)存碎片。如下圖:

上圖中的空閑3個(gè)字節(jié)和空閑2個(gè)字節(jié)都是內(nèi)存碎片。

那么什么原因會(huì)造成內(nèi)存碎片呢?這個(gè)其實(shí)大致分為兩個(gè)原因,一個(gè)是操作系統(tǒng)的內(nèi)存分配策略,一個(gè)是Redis自身原因,下面就這兩個(gè)原因詳細(xì)分析。

內(nèi)存分配器的分配策略

內(nèi)存分配器的分配策略一般是按照固定大小來(lái)分配內(nèi)存,而不是按照應(yīng)用程序申請(qǐng)的內(nèi)存空間按需分配。比如8字節(jié)、16字節(jié)、32字節(jié)......

Redis提供了多種的內(nèi)存分配策略,比如libc、jemalloc、tcmalloc,默認(rèn)使用jemalloc。

jemalloc這種分配策略,是按照固定的空間分配,比如8字節(jié)、32字節(jié)....2KB、4KB等。當(dāng)應(yīng)用程序申請(qǐng)的內(nèi)存接近某個(gè)固定值的時(shí)候,jemalloc則會(huì)分配固定的大小。比如申請(qǐng)了6字節(jié),則會(huì)分配8字節(jié)的空間。

這種分配的方式的好處很明顯,則會(huì)減少內(nèi)存分配的次數(shù),比如申請(qǐng)了20字節(jié)的內(nèi)存,實(shí)際分配的是32字節(jié)的內(nèi)存空間,當(dāng)應(yīng)用再寫入10字節(jié)的數(shù)據(jù)時(shí),則不會(huì)再次分配,剩余的12字節(jié)足夠用了。這樣就避免了一次的內(nèi)存分配。如下圖:

但是壞處也很明顯,申請(qǐng)的和分配的空間不一樣,則剩余的空間很可能形成內(nèi)存碎片,一旦內(nèi)存碎片多了,內(nèi)存利用率也會(huì)隨之降低,這是很可怕的。

Redis自身的原因

Redis作為鍵值對(duì)存儲(chǔ)的數(shù)據(jù)庫(kù),本身鍵值對(duì)的大小就是不確定的,正如上面的例子中,Redis申請(qǐng)了20字節(jié)的空間,但實(shí)際分配卻是32字節(jié),那么剩余的12字節(jié)則會(huì)被閑置成為內(nèi)存碎片。如下圖:

上圖中剩余12個(gè)字節(jié)空間則是閑置的,很有可能成為內(nèi)存碎片,因此鍵值對(duì)大小不同則會(huì)造成一定的內(nèi)存碎片,這是第一個(gè)原因。

第二個(gè)原因其實(shí)理解起來(lái)很簡(jiǎn)單,鍵值對(duì)的修改或者刪除肯定會(huì)造成空間的擴(kuò)容或者釋放;

一方面,如果修改后的鍵值對(duì)變大或者變小了,勢(shì)必會(huì)將占用的空間擴(kuò)大或者釋放不用的空間,如下圖:

上圖中鍵值對(duì)修改后變小了,從原來(lái)的10個(gè)字節(jié)變成了7個(gè)字節(jié),從而釋放了3個(gè)字節(jié),此時(shí)剩余了5個(gè)字節(jié)的空閑空間。

另一方面,如果鍵值對(duì)刪除了,則會(huì)釋放掉占用的空間,形成空閑空間。

如何判斷存在內(nèi)存碎片?

這個(gè)對(duì)于運(yùn)維人員來(lái)說(shuō)很重要,一旦出現(xiàn)Redis運(yùn)行緩慢或者阻塞了,一定需要先判斷內(nèi)存的占用情況,而不是說(shuō)胡亂的重啟Redis。

Redis自身提供了INFO命令,可以用來(lái)查詢內(nèi)存的使用情況,命令如下:

INFO memory
# Memory
used_memory:1073741736
used_memory_human:1024.00M
used_memory_rss:1997159792
used_memory_rss_human:1.86G
…
mem_fragmentation_ratio:1.86

上面的各種屬性含義如下:

mem_fragmentation_ratio這個(gè)指標(biāo)很清楚的展示了當(dāng)前內(nèi)存的碎片率,比如Redis申請(qǐng)了1000字節(jié),但是操作系統(tǒng)實(shí)際分配的內(nèi)存1800個(gè)字節(jié),則mem_fragmentation_ratio=1800/1000=1.8。

從上文也知道了,由于內(nèi)存分配器的局限性,實(shí)際分配的內(nèi)存絕大部分都是大于實(shí)際申請(qǐng)的內(nèi)存,則如何通過(guò)mem_fragmentation_ratio這個(gè)值來(lái)衡量呢?這個(gè)值的范圍在多少是正常的呢?

作者這里參照了許多開發(fā)人員的建議,列出了以下經(jīng)驗(yàn)閥值:

  • >1&&<1.5:在這個(gè)范圍內(nèi)是合理的,畢竟大部分情況下操作系統(tǒng)分配的內(nèi)存總是總是大于實(shí)際申請(qǐng)的空間。
  • >1.5:這表明內(nèi)存碎片率已經(jīng)超過(guò)50%,此時(shí)需要采取一些措施來(lái)降低碎片率了。
  • <1:what?表明實(shí)際分配的內(nèi)存小于申請(qǐng)的內(nèi)存了,很顯然內(nèi)存不足了,這樣會(huì)導(dǎo)致部分?jǐn)?shù)據(jù)寫入到Swap中,之后Redis訪問(wèn)Swap中的數(shù)據(jù)時(shí),延遲會(huì)變大,性能會(huì)降低。

如何清理內(nèi)存碎片?

既然存在內(nèi)存碎片,那么的一定有方法清除內(nèi)存碎片,最簡(jiǎn)單的方法則是重啟Redis

但是這也存在一些風(fēng)險(xiǎn),如下;

  • 如果Redis未持久化,則數(shù)據(jù)會(huì)丟失(忽略從后端恢復(fù))
  • 即使持久化了,但是恢復(fù)數(shù)據(jù)時(shí)長(zhǎng)不定,這個(gè)要根據(jù)AOF和RDB文件大小決定,在恢復(fù)階段則無(wú)法提供服務(wù)。

好在Redis 4.0-RC3版本之后,Redis自身提供了一種清除內(nèi)存碎片的方法。

清除的原理很簡(jiǎn)單,通過(guò)復(fù)制拷貝將不連續(xù)的存放的數(shù)據(jù)搬到一起形成一塊連續(xù)的內(nèi)存空間,如下圖:

如上圖,清除之前A和B不是連續(xù)的,中間隔著兩個(gè)字節(jié)空閑1,但是在執(zhí)行清除內(nèi)存碎片操作之后,Redis拷貝了B到空閑1,釋放掉之前B的空間,此時(shí)空閑1和空閑2則變成了連續(xù)的空閑空間了。

那么問(wèn)題來(lái)了,這種方式固然好,但是對(duì)于單線程的Redis來(lái)說(shuō),通過(guò)這種拷貝復(fù)制的方式顯然是一種耗時(shí)的操作,性能大大降低,那么有什么好的方法呢?

Redis提供了參數(shù)配置,可以控制清除內(nèi)存碎片的時(shí)機(jī),命令如下:

config set activedefrag yes

以上命令啟動(dòng)自動(dòng)清理,但是具體什么時(shí)候清理,還要受以下兩個(gè)參數(shù)的影響:

  • active-defrag-ignore-bytes 400mb:如果內(nèi)存碎片達(dá)到了400mb,開始清理(自定義)
  • active-defrag-threshold-lower 20:內(nèi)存碎片空間占操作系統(tǒng)分配給 Redis 的總空間比例達(dá)到20%時(shí),開始清理(自定義)

以上兩個(gè)參數(shù)只有全部滿足才會(huì)開始清理。

除了以上觸發(fā)清理內(nèi)存碎片的參數(shù),Redis還提供了兩個(gè)參數(shù)來(lái)保證在清理過(guò)程中不影響處理正常的請(qǐng)求,如下:

  • active-defrag-cycle-min 25:表示自動(dòng)清理過(guò)程所用 CPU 時(shí)間的比例不低于 25%,保證清理能正常開展
  • active-defrag-cycle-max 75:表示自動(dòng)清理過(guò)程所用 CPU 時(shí)間的比例不高于 75%,一旦超過(guò),就停止清理,從而避免在清理時(shí),大量的內(nèi)存拷貝阻塞 Redis,導(dǎo)致響應(yīng)延遲升高。

以上兩個(gè)參數(shù)控制了清理過(guò)程中的CPU時(shí)間占比,保證了正常處理請(qǐng)求不受影響。

總結(jié)

本文以師弟的一個(gè)疑問(wèn)開頭介紹了刪除數(shù)據(jù)導(dǎo)致內(nèi)存占用還是很高的原因是存在內(nèi)存碎片,導(dǎo)致內(nèi)存碎片大致分為兩個(gè)原因,如下:

  • 內(nèi)存分配策略局限性,一般都會(huì)分配固定的空間大小,導(dǎo)致實(shí)際分配的內(nèi)存空間大于實(shí)際申請(qǐng)的,從而多出了許多不連續(xù)的空閑內(nèi)存塊。
  • 鍵值對(duì)的修改、刪除導(dǎo)致了內(nèi)存的擴(kuò)容或者釋放,導(dǎo)致多余的不連續(xù)的空閑內(nèi)存塊。
  • 介紹了如何通過(guò)INFO memory命令查看內(nèi)存的碎片率,通過(guò)mem_fragmentation_ratio的經(jīng)驗(yàn)閥值來(lái)判斷異常。
  • 介紹了Redis清理內(nèi)存碎片的方式以自動(dòng)清理的兩個(gè)觸發(fā)條件、保證正常處理請(qǐng)求的兩個(gè)控制CPU時(shí)間的參數(shù)。
責(zé)任編輯:趙寧寧 來(lái)源: 碼猿技術(shù)專欄
相關(guān)推薦

2023-12-08 08:01:14

Redis存儲(chǔ)內(nèi)存

2020-11-17 09:01:09

MySQLDelete數(shù)據(jù)

2022-09-05 08:39:55

Redis存儲(chǔ)數(shù)據(jù)

2023-09-21 10:50:23

MySQL數(shù)據(jù)庫(kù)

2016-05-26 12:11:00

Redis內(nèi)存開源

2014-04-14 13:05:41

RedisDBA服務(wù)器

2021-03-10 10:40:04

Redis命令Linux

2022-01-02 08:38:22

Redis數(shù)據(jù)單線程

2020-11-02 07:05:54

虛擬內(nèi)存Go

2016-04-01 11:12:26

企業(yè)IT數(shù)據(jù)孤島商業(yè)智能

2011-02-21 10:35:00

查詢刪除數(shù)據(jù)

2011-05-18 15:08:03

mysql刪除修改數(shù)據(jù)

2019-12-20 14:56:50

批量刪除數(shù)據(jù)數(shù)據(jù)刪除

2009-09-04 17:56:22

C#刪除數(shù)據(jù)

2013-03-22 09:29:47

數(shù)據(jù)安全云安全

2018-03-30 11:00:05

混合云云計(jì)算公共云

2022-04-01 15:23:06

人工智能AI換臉數(shù)據(jù)

2010-09-02 10:15:46

SQL刪除

2018-04-25 10:13:30

Redis內(nèi)存模型

2023-03-21 08:02:36

Redis6.0IO多線程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)