Redis 運(yùn)維必備技能:內(nèi)存使用和管理

本文從Redis數(shù)據(jù)庫最關(guān)鍵的特性——內(nèi)存出發(fā),詳細(xì)介紹了Redis的內(nèi)存使用和內(nèi)存管理,而這也是成為一名專業(yè)Redis運(yùn)維人員的核心技能。

【摘要】本文從Redis數(shù)據(jù)庫最關(guān)鍵的特性——內(nèi)存出發(fā),詳細(xì)介紹了Redis的內(nèi)存使用和內(nèi)存管理,而這也是成為一名專業(yè)Redis運(yùn)維人員的核心技能。

【作者】姜文浩,從事銀行業(yè)務(wù)系統(tǒng)開發(fā)運(yùn)維多年,前期偏向于傳統(tǒng)的業(yè)務(wù)中間件、消息中間件以及SOA、ESB架構(gòu),近期逐漸轉(zhuǎn)向于分布式架構(gòu)以及開源中間件、NoSQL 數(shù)據(jù)庫等,在系統(tǒng)優(yōu)化、系統(tǒng)架構(gòu)方面有著一定經(jīng)驗(yàn)。

Redis是當(dāng)今很火爆的內(nèi)存數(shù)據(jù)庫,我們的所有數(shù)據(jù)都存在了內(nèi)存之中,因此我們的每次寫入、讀取都是從內(nèi)存中進(jìn)行操作,所以在帶來速度的同時(shí),也從內(nèi)存的使用上給我們帶來了挑戰(zhàn)。眾所周知,在硬件資源中內(nèi)存價(jià)格是高于硬盤價(jià)格的,通過學(xué)習(xí)Redis的內(nèi)存知識(shí)可以使我們?cè)诒Wo(hù)Redis數(shù)據(jù)庫的同時(shí)更高效的發(fā)揮出Redis的作用,進(jìn)而管理內(nèi)存,減少內(nèi)存消耗和硬件成本。

Redis作為內(nèi)存數(shù)據(jù)庫,對(duì)于自身所使用的內(nèi)存情況是有命令可以統(tǒng)計(jì)的,通過獲取到的相關(guān)信息可以了解Redis自身內(nèi)存的使用現(xiàn)狀,進(jìn)而有助于判斷內(nèi)存使用健康度。Redis提供查看內(nèi)存的指令為info memory。

在以上各項(xiàng)指標(biāo)中需要重點(diǎn)關(guān)注的指標(biāo)有:used_memory_rss和used_memory以及它們的比值mem_fragmentation_ratio。

當(dāng)mem_fragmentation_ratio>1 時(shí),說明used_memory_rss-used_memory多出的部分內(nèi)存并沒有用于數(shù)據(jù)存儲(chǔ),而是被內(nèi)存碎片所消耗,這個(gè)值越大,表明內(nèi)存碎片越多。

當(dāng)mem_fragmentation_ratio<1 時(shí),這種情況說明正在使用虛擬內(nèi)存,也就是在使用主機(jī)的硬盤,由于硬盤性能是遠(yuǎn)遠(yuǎn)低于內(nèi)存的,所以要小心因?yàn)樾阅軉栴}導(dǎo)致整體Redis故障。根據(jù)日常使用的情況mem_fragmentation_ratio的數(shù)值在1 ~ 1.5之間是比較健康的。在出現(xiàn)內(nèi)存碎片過多的問題怎么處理呢?最簡(jiǎn)單暴力的辦法就是重啟,在Redis4.0版本之后支持在運(yùn)行期進(jìn)行自動(dòng)內(nèi)存碎片清理,主要通過設(shè)置config set activedefrag yes來進(jìn)行實(shí)現(xiàn),同時(shí)也提供了memory purge命令來手動(dòng)進(jìn)行內(nèi)存碎片清理。

Redis默認(rèn)是無限使用內(nèi)存的,所以防止系統(tǒng)內(nèi)存被耗盡,需要對(duì)Redis的內(nèi)存上限進(jìn)行設(shè)置,Redis使用maxmemory參數(shù)限制最大可用內(nèi)存。通過前面的介紹我們可以得知maxmemory配置的是Redis實(shí)際使用的內(nèi)存量,也就是used_memory統(tǒng)計(jì)項(xiàng)對(duì)應(yīng)的內(nèi)存。由于內(nèi)存碎片率的存在,實(shí)際消耗的內(nèi)存可能會(huì)比maxmemory設(shè)置的更大,實(shí)際使用時(shí)要小心這部分內(nèi)存溢出。根據(jù)慣例一般會(huì)預(yù)留出20%的服務(wù)器空閑內(nèi)存防止內(nèi)存溢出通過。

Redis的內(nèi)存上限可以通過config set maxmemory進(jìn)行動(dòng)態(tài)修改,即修改最大可用內(nèi)存。通過動(dòng)態(tài)修改maxmemory,可以實(shí)現(xiàn)在當(dāng)前服務(wù)器下動(dòng)態(tài)伸縮Redis內(nèi)存的目的,考慮到現(xiàn)在在部署Redis時(shí)大多采用集群或哨兵模式,單臺(tái)主機(jī)上并非Redis單實(shí)例,因此建議針對(duì)所有的Redis進(jìn)程都要配置maxmemory。

Redis針對(duì)內(nèi)存使用情況提供內(nèi)存回收策略供運(yùn)維人員進(jìn)行配置,主要用于刪除到達(dá)過期時(shí)間的鍵對(duì)象以及當(dāng)Redis內(nèi)存使用達(dá)到所設(shè)置的maxmemory上限時(shí)則執(zhí)行內(nèi)存回收策略。

Redis所有的鍵都可以設(shè)置過期屬性,在數(shù)據(jù)庫結(jié)構(gòu)中的expires字典中保存了數(shù)據(jù)庫中所有鍵的過期時(shí)間,我們稱expire這個(gè)字典為過期字典。由于進(jìn)程內(nèi)保存大量的鍵,維護(hù)每個(gè)鍵精準(zhǔn)的過期刪除機(jī)制會(huì)導(dǎo)致消耗大量的CPU,對(duì)于單線程的Redis來說成本過高,因此Redis采用惰性刪除和定時(shí)任務(wù)刪除機(jī)制實(shí)現(xiàn)過期鍵的內(nèi)存回收。

惰性刪除:惰性刪除用于當(dāng)客戶端讀取帶有超時(shí)屬性的鍵時(shí),如果已經(jīng)超過鍵設(shè)置的過期時(shí)間,會(huì)執(zhí)行刪除操作并返回空,這種刪除策略對(duì)CPU是友好的,刪除操作只有在不得不的情況下才會(huì)進(jìn)行,不會(huì)對(duì)其他的expire key上浪費(fèi)無謂的CPU時(shí)間。但是這種策略對(duì)內(nèi)存不友好,一個(gè)key已經(jīng)過期,但是在它被操作之前不會(huì)被刪除,仍然占據(jù)內(nèi)存空間。如果有大量的過期鍵存在但是又很少被訪問到,那會(huì)造成大量的內(nèi)存空間浪費(fèi)。因?yàn)榭赡艽嬖谝恍﹌ey永遠(yuǎn)不會(huì)被再次訪問到,這些設(shè)置了過期時(shí)間的key也是需要在過期后被刪除的,我們甚至可以將這種情況看作是一種內(nèi)存泄露—-無用的垃圾數(shù)據(jù)占用了大量的內(nèi)存,而服務(wù)器卻不會(huì)自己去釋放它們,這對(duì)于運(yùn)行狀態(tài)非常依賴于內(nèi)存的Redis服務(wù)器來說,肯定不是一個(gè)好消息。正因?yàn)槿绱?,Redis還提供另一種定時(shí)任務(wù)刪除機(jī)制作為惰性刪除的補(bǔ)充。

定時(shí)任務(wù)刪除:Redis內(nèi)部維護(hù)一個(gè)定時(shí)任務(wù),默認(rèn)每秒運(yùn)行10次(通過配置server.hz控制)。Redis會(huì)周期性的隨機(jī)測(cè)試一批設(shè)置了過期時(shí)間的key并進(jìn)行處理。測(cè)試到的已過期的key將被刪除。

當(dāng)Redis所用內(nèi)存達(dá)到maxmemory上限時(shí)會(huì)觸發(fā)相應(yīng)的溢出控制策略。具體策略受maxmemory-policy參數(shù)控制,Redis支持6種策略,如下所示:

1)noeviction:默認(rèn)策略,數(shù)據(jù)永不過期,不會(huì)刪除任何數(shù)據(jù),當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),新寫入操作會(huì)報(bào)錯(cuò),一般不推薦使用。

2)volatile-lru:根據(jù)LRU算法刪除設(shè)置了超時(shí)屬性(expire)的鍵,直到騰出足夠空間為止。如果沒有可刪除的鍵對(duì)象,回退到noeviction策略。這種情況一般是把 Redis 既當(dāng)緩存,又做持久化存儲(chǔ)的時(shí)候才用。

3)allkeys-lru:根據(jù)LRU算法刪除鍵,不管數(shù)據(jù)有沒有設(shè)置超時(shí)屬性,直到騰出足夠空間為止。一般推薦使用該策略

4)allkeys-random:內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在鍵空間中,隨機(jī)移除某個(gè) Key。

5)volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的鍵空間中,隨機(jī)移除某個(gè) Key。

6)volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的鍵空間中,有更早過期時(shí)間的 Key 優(yōu)先移除。如果沒有,回退到noeviction策略。

內(nèi)存溢出控制策略可以采用config set maxmemory-policy動(dòng)態(tài)配置。我們上文已經(jīng)介紹了Redis所支持的的內(nèi)存溢出應(yīng)對(duì)策略,運(yùn)維人員可以根據(jù)實(shí)際需求靈活定制。

綜上所述,我們從Redis數(shù)據(jù)庫最關(guān)鍵特性—內(nèi)存出發(fā),詳細(xì)介紹了Redis的內(nèi)存使用和內(nèi)存管理,而這也是成為一名專業(yè)Redis運(yùn)維人員的核心技能。大家通過本文能夠提升對(duì)Redis內(nèi)存的認(rèn)識(shí),但要真正掌握則需要長(zhǎng)時(shí)間的學(xué)習(xí)和使用,希望大家共同努力學(xué)習(xí)和進(jìn)步。

THEEND

最新評(píng)論(評(píng)論僅代表用戶觀點(diǎn))

更多
暫無評(píng)論