接下來我們來一起研究下redis工程架構(gòu)相關(guān)的問題,這部分內(nèi)容出現(xiàn)的概率相對大一些,因為并不是所有人都會去研究源碼,如果面試一味問源碼那么可能注定是一場尬聊。
梨樹網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)于2013年創(chuàng)立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
面試時在不要求候選人對Redis非常熟練的前提下,工程問題將是不二之選。
通過本文你將了解到以下內(nèi)容:
1.Redis的內(nèi)存回收詳解
2.Redis的持久化機制
1.1 為什么要回收內(nèi)存?
Redis作為內(nèi)存型數(shù)據(jù)庫,如果單純的只進不出早晚就撐爆了,事實上很多把Redis當做主存儲DB用的家伙們早晚會嘗到這個苦果,當然除非你家廠子確實不差錢,數(shù)T級別的內(nèi)存都毛毛雨,或者數(shù)據(jù)增長一定程度之后不再增長的場景,就另當別論了。
對于我們這種把節(jié)約成本當做KPI的普通廠子,還是把Redis當緩存用比較符合家里的經(jīng)濟條件,所以這么看面試官的問題還算是比較貼合實際,比起那些手撕RBTree好一些,如果問題剛好在你知識射程范圍內(nèi),先給面試官點個贊再說!
為了讓Redis服務安全穩(wěn)定的運行,讓使用內(nèi)存保持在一定的閾值內(nèi)是非常有必要的,因此我們就需要刪除該刪除的,清理該清理的,把內(nèi)存留給需要的鍵值對,試想一條大河需要設(shè)置幾個警戒水位來確保不決堤不枯竭,Redis也是一樣的,只不過Redis只關(guān)心決堤即可,來一張圖:
圖中設(shè)定機器內(nèi)存為128GB,占用64GB算是比較安全的水平,如果內(nèi)存接近80%也就是100GB左右,那么認為Redis目前承載能力已經(jīng)比較大了,具體的比例可以根據(jù)公司和個人的業(yè)務經(jīng)驗來確定。
筆者只是想表達出于安全和穩(wěn)定的考慮,不要覺得128GB的內(nèi)存就意味著存儲128GB的數(shù)據(jù),都是要打折的。
1.2 內(nèi)存從哪里回收?
Redis占用的內(nèi)存是分為兩部分:存儲鍵值對消耗和本身運行消耗。顯然后者我們無法回收,因此只能從鍵值對下手了,鍵值對可以分為幾種:帶過期的、不帶過期的、熱點數(shù)據(jù)、冷數(shù)據(jù)。對于帶過期的鍵值是需要刪除的,如果刪除了所有的過期鍵值對之后內(nèi)存仍然不足怎么辦?那只能把部分數(shù)據(jù)給踢掉了。
人生無處不取舍,這個讓筆者腦海浮現(xiàn)了《泰坦尼克》,郵輪撞到了冰山頃刻間海水涌入,面臨數(shù)量不足的救生艇,人們做出了抉擇:讓女士和孩童先走,紳士們選擇留下,海上逃生場景如圖:
要實施對鍵值對的刪除我們需要明白如下幾點:
老規(guī)矩來到github看下源碼,src/server.h中給的redisDb結(jié)構(gòu)體給出了答案:
typedef struct redisDb {
dict *dict; /* The keyspace for this DB */
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
unsigned long expires_cursor; /* Cursor of the active expire cycle. */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;
Redis本質(zhì)上就是一個大的key-value,key就是字符串,value有是幾種對象:字符串、列表、有序列表、集合、哈希等,這些key-value都是存儲在redisDb的dict中的,來看下黃健宏畫的一張非常贊的圖:
看到這里,對于刪除機制又清晰了一步,我們只要把redisDb中dict中的目標key-value刪掉就行,不過貌似沒有這么簡單,Redis對于過期鍵值對肯定有自己的組織規(guī)則,讓我們繼續(xù)研究吧!
redisDb的expires成員的類型也是dict,和鍵值對是一樣的,本質(zhì)上expires是dict的子集,expires保存的是所有帶過期的鍵值對,稱之為過期字典吧,它才是我們研究的重點。
對于鍵,我們可以設(shè)置絕對和相對過期時間、以及查看剩余時間:
上述三組命令在設(shè)計緩存時用處比較大,有心的讀者可以留意。
過期字典expires和鍵值對空間dict存儲的內(nèi)容并不完全一樣,過期字典expires的key是指向Redis對應對象的指針,其value是long long型的unix時間戳,前面的EXPIRE和PEXPIRE相對時長最終也會轉(zhuǎn)換為時間戳,來看下過期字典expires的結(jié)構(gòu),筆者畫了個圖:
判斷鍵是否過期可刪除,需要先查過期字典是否存在該值,如果存在則進一步判斷過期時間戳和當前時間戳的相對大小,做出刪除判斷,簡單的流程如圖:
經(jīng)過前面的幾個環(huán)節(jié),我們知道了Redis的兩種存儲位置:鍵空間和過期字典,以及過期字典expires的結(jié)構(gòu)、判斷是否過期的方法,那么該如何實施刪除呢?
先拋開Redis來想一下可能的幾種刪除策略:
在上述的三種策略中定時刪除和定期刪除屬于不同時間粒度的主動刪除,惰性刪除屬于被動刪除。
三種策略都有各自的優(yōu)缺點:
定時刪除對內(nèi)存使用率有優(yōu)勢,但是對CPU不友好,惰性刪除對內(nèi)存不友好,如果某些鍵值對一直不被使用,那么會造成一定量的內(nèi)存浪費,定期刪除是定時刪除和惰性刪除的折中。
Reids采用的是惰性刪除和定時刪除的結(jié)合,一般來說可以借助最小堆來實現(xiàn)定時器,不過Redis的設(shè)計考慮到時間事件的有限種類和數(shù)量,使用了無序鏈表存儲時間事件,這樣如果在此基礎(chǔ)上實現(xiàn)定時刪除,就意味著O(N)遍歷獲取最近需要刪除的數(shù)據(jù)。
但是我覺得antirez如果非要使用定時刪除,那么他肯定不會使用原來的無序鏈表機制,所以個人認為已存在的無序鏈表不能作為Redis不使用定時刪除的根本理由,冒昧猜測唯一可能的是antirez覺得沒有必要使用定時刪除。
定期刪除聽著很簡單,但是如何控制執(zhí)行的頻率和時長呢?
試想一下如果執(zhí)行頻率太少就退化為惰性刪除了,如果執(zhí)行時間太長又和定時刪除類似了,想想還確實是個難題!并且執(zhí)行定期刪除的時機也需要考慮,所以我們繼續(xù)來看看Redis是如何實現(xiàn)定期刪除的吧!筆者在src/expire.c文件中找到了activeExpireCycle函數(shù),定期刪除就是由此函數(shù)實現(xiàn)的,在代碼中antirez做了比較詳盡的注釋,不過都是英文的,試著讀了一下模模糊糊弄個大概,所以學習英文并閱讀外文資料是很重要的學習途徑。
由于筆者對Redis源碼了解不多,只能做個模糊版本的解讀,所以難免有問題,還是建議有條件的讀者自行前往源碼區(qū)閱讀,拋磚引玉看下筆者的模糊版本:
主體意思:定期刪除是個自適應的閉環(huán)并且概率化的抽樣掃描過程,過程中都有執(zhí)行時間和cpu時間的限制,如果觸發(fā)閾值就停止,可以說是盡量在不影響對客戶端的響應下潤物細無聲地進行的。
1.3.5 DEL刪除鍵值對
在Redis4.0之前執(zhí)行del操作時如果key-value很大,那么可能導致阻塞,在新版本中引入了BIO線程以及一些新的命令,實現(xiàn)了del的延時懶刪除,最后會有BIO線程來實現(xiàn)內(nèi)存的清理回收。
為了保證Redis的安全穩(wěn)定運行,設(shè)置了一個max-memory的閾值,那么當內(nèi)存用量到達閾值,新寫入的鍵值對無法寫入,此時就需要內(nèi)存淘汰機制,在Redis的配置中有幾種淘汰策略可以選擇,詳細如下:
后三種策略都是針對過期字典的處理,但是在過期字典為空時會noeviction一樣返回寫入失敗,毫無策略地隨機刪除也不太可取,所以一般選擇第二種allkeys-lru基于LRU策略進行淘汰。
個人認為antirez一向都是工程化思維,善于使用概率化設(shè)計來做近似實現(xiàn),LRU算法也不例外,Redis中實現(xiàn)了近似LRU算法,并且經(jīng)過幾個版本的迭代效果已經(jīng)比較接近理論LRU算法的效果了,這個也是個不錯的內(nèi)容,由于篇幅限制,本文計劃后續(xù)單獨講LRU算法時再進行詳細討論。
過期健刪除策略強調(diào)的是對過期健的操作,如果有健過期而內(nèi)存足夠,Redis不會使用內(nèi)存淘汰機制來騰退空間,這時會優(yōu)先使用過期健刪除策略刪除過期健。
內(nèi)存淘汰機制強調(diào)的是對內(nèi)存數(shù)據(jù)的淘汰操作,當內(nèi)存不足時,即使有的健沒有到達過期時間或者根本沒有設(shè)置過期也要根據(jù)一定的策略來刪除一部分,騰退空間保證新數(shù)據(jù)的寫入。
Q2:講講你對Redis持久化機制的理解。
個人認為Redis持久化既是數(shù)據(jù)庫本身的亮點,也是面試的熱點,主要考察的方向包括:RDB機制原理、AOF機制原理、各自的優(yōu)缺點、工程上的對于RDB和AOF的取舍、新版本Redis混合持久化策略等,如能把握要點,持久化問題就過關(guān)了。
網(wǎng)頁題目:Redis掃盲:淺談Redis面試必問——工程架構(gòu)篇
文章出自:http://jinyejixie.com/article24/iehpce.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導航、服務器托管、定制開發(fā)、自適應網(wǎng)站、App設(shè)計、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)