Redis設計思路學習與總結



Redis設計思路學習與總結

宋增寬,騰訊工程師,16年畢業(yè)加入騰訊译秦,從事海量服務后臺設計與研發(fā)工作,現(xiàn)在負責QQ群后臺等項目永毅,喜歡研究技術,并思考技術演變人弓,專注于高并發(fā)業(yè)務架構的設計與性能優(yōu)化沼死。

下半年利用空余時間研究和分析了部分Redis源碼,本文從網(wǎng)絡模型崔赌、數(shù)據(jù)結構和內存管理意蛀、持久化和多機協(xié)作四個角度對redis的設計思路進行了分析,若有不正確之處峰鄙,希望各路大神指出。

Redis是業(yè)界普遍應用的緩存組件太雨,研究一個組件框架吟榴,最直觀的辦法就是從應用方的角度出發(fā),將每個步驟的考慮一番囊扳,從這些步驟入手去研究往往能夠最快的體會到一個組件框架的設計哲學吩翻。以Redis為例,每當發(fā)起一條請求時锥咸,redis是如何管理管理網(wǎng)絡請求狭瞎,收到請求后又是通過什么樣的數(shù)據(jù)結構進行組織并操作內存,這些數(shù)據(jù)又是如何dump到磁盤實現(xiàn)持久化搏予,再到多機環(huán)境下如何同步和保證一致性……本文就是從網(wǎng)絡模型熊锭、數(shù)據(jù)結構設計與內存管理、持久化方法和多機四個角度簡要描述了redis的設計和自己的一點體會。

一.網(wǎng)絡模型

Redis是典型的基于Reactor的事件驅動模型碗殷,單進程單線程精绎,高效的框架總是類似的。網(wǎng)絡模型與spp的異步模型幾乎一致锌妻。

Redis流程上整體分為接受請求處理器代乃、響應處理器和應答處理器三個同步模塊,每一個請求都是要經歷這三個部分仿粹。

Redis集成了libevent/epoll/kqueue/select等多種事件管理機制搁吓,可以根據(jù)操作系統(tǒng)版本自由選擇合適的管理機制,其中l(wèi)ibevent是最優(yōu)選擇的機制吭历。

Redis的網(wǎng)絡模型有著所有事件驅動模型的優(yōu)點堕仔,高效低耗。但是面對耗時較長的操作的時候毒涧,同樣無法處理請求贮预,只能等到事件處理完畢才能響應,之前在業(yè)務中也遇到過這樣的場景契讲,刪除redis中全量的key-value仿吞,整個操作時間較長,操作期間所有的請求都無法響應捡偏。所以了解清楚網(wǎng)絡模型有助于在業(yè)務中揚長避短唤冈,減少長耗時的請求,盡可能多一些簡單的短耗時請求發(fā)揮異步模型的最大的威力银伟,事實上在Redis的設計中也多次體現(xiàn)這一點你虹。

二.數(shù)據(jù)結構和內存管理

1.字符串

1.1 結構

Redis的字符串是對C語言原始字符串的二次封裝,結構如下:

structsdshdr {longlen;longfree;charbuf[];};

可以看出彤避,每當定義一個字符串時傅物,除了保存字符的空間,Redis還分配了額外的空間用于管理屬性字段琉预。

1.2 內存管理方式

動態(tài)內存管理方式董饰,動態(tài)方式最大的好處就是能夠較為充分的利用內存空間,減少內存碎片化圆米,與此同時帶來的劣勢就是容易引起頻繁的內存抖動卒暂,通常采用“空間預分配”和“惰性空間釋放”兩種優(yōu)化策略來減少內存抖動,redis也不例外娄帖。

每次修改字符串內容時也祠,首先檢查內存空間是否符合要求,否則就擴大2倍或者按M增長近速;減少字符串內容時诈嘿,內存并不會立刻回收堪旧,而是按需回收。

關于內存管理的優(yōu)化永淌,最基本的出發(fā)點就是浪費一點空間還是犧牲一些時間的權衡崎场,像STL、tcmalloc遂蛀、protobuf3的arena機制等采用的核心思路都是“預分配遲回收”谭跨,Redis也是一樣的。

1.3 二進制安全

判斷字符串結束與否的標識是len字段李滴,而不是C語言的'\0'螃宙,因此是二進制安全的。

放心的將pb序列化后的二進制字符串存入redis所坯。

簡而言之谆扎,通過redis的簡單封裝,redis的字符串的操作更加方便芹助,性能更友好堂湖,并且屏蔽了C語言字符串的一些需要用戶關心的問題。

2.字典(哈希)

字典的底層一定是hash状土,涉及到hash一定會涉及到hash算法无蜂、沖突的解決方法和hash表擴容和縮容。

2.1 hash算法

Redis使用的就是常用的Murmurhash2蒙谓,Murmurhash算法能夠給出在任意輸入序列下的散列分布性斥季,并且計算速度很快。之前做共享內存的Local-Cache的需求時也正是利用了Murmurhash的優(yōu)勢累驮,解決了原有結構的hash函數(shù)散列分布性差的問題酣倾。

2.2 hash沖突解決方法

鏈地址法解決hash沖突,通用解決方案沒什么特殊的谤专。多說一句躁锡,如果選用鏈地址解決沖突,那么勢必要有一個散列性非常好的hash函數(shù)置侍,否則hash的性能將會大大折扣映之。Redis選用了Murmurhash,所以可以放心大膽的采用鏈地址方案墅垮。

2.3 hash擴容和縮容

維持hash表在一個合理的負載范圍之內惕医,簡稱為rehash過程耕漱。

rehash的過程也是一個權衡的過程算色,在做評估之前首先明確一點,不管中間采用什么樣的rehash策略螟够,rehash在宏觀上看一定是:分配一個新的內存塊灾梦,老數(shù)據(jù)搬到新的內存塊上峡钓,釋放舊內存塊。

老數(shù)據(jù)何時搬若河?怎么搬能岩?就變成了一個需要權衡的問題。

第一部分的網(wǎng)絡模型上明確的指出Redis的事件驅動模型特點萧福,不適合玩長耗時操作拉鹃。如果一個hashtable非常大,需要進行擴容就一次性把老數(shù)據(jù)copy過去鲫忍,那就會非常耗時膏燕,違背事件驅動的特點。所以Redis依舊采用了一種惰性的方案:

新空間分配完畢后悟民,啟動rehashidx標識符表明rehash過程的開始坝辫;之后所有增刪改查涉及的操作時都會將數(shù)據(jù)遷移到新空間,直到老空間數(shù)據(jù)大小為0表明數(shù)據(jù)已經全部在新空間射亏,將rehashidx禁用近忙,表明rehash結束。

將一次性的集中問題分而治之智润,在Redis的設計哲學中體現(xiàn)的淋漓盡致及舍,主要是為了避免大耗時操作,影響Redis響應客戶請求做鹰。

3.整數(shù)集合

變長整數(shù)存儲击纬,整數(shù)分為16/32/64三個變長尺度,根據(jù)存入的數(shù)據(jù)所屬的類型钾麸,進行規(guī)劃更振。

每次插入新元素都有可能導致尺度升級(例如由16位漲到32位),因此插入整數(shù)的時間復雜度為O(n)饭尝。這里也是一個權衡肯腕,內存空間和時間的一個折中,盡可能節(jié)省內存钥平。

4.跳躍表

Redis的skilplist和普通的skiplist沒什么不同实撒,都是冗余數(shù)據(jù)實現(xiàn)的從粗到細的多層次鏈表,Redis中應用跳表的地方不多涉瘾,常見的就是有序集合知态。

Redis的跳表和普通skiplist沒有什么特殊之處。

5.鏈表

Redis的鏈表是雙向非循環(huán)鏈表立叛,擁有表頭和表尾指針负敏,對于首尾的操作時間復雜度是O(1),查找時間復雜度O(n)秘蛇,插入時間復雜度O(1)其做。

Redis的鏈表和普通鏈表沒有什么特殊之處顶考。

三.AOF和RDB持久化

AOF持久化日志,RDB持久化實體數(shù)據(jù)妖泄,AOF優(yōu)先級大于RDB驹沿。

1.AOF持久化

機制:通過定時事件將aof緩沖區(qū)內的數(shù)據(jù)定時寫到磁盤上。

2.AOF重寫

為了減少AOF大小蹈胡,Redis提供了AOF重寫功能渊季,這個重寫功能做的工作就是創(chuàng)建一個新AOF文件代替老的AOF,并且這個新的AOF文件沒有一條冗余指令罚渐。(例如對list先插入A/B/C梭域,后刪除B/C,再插入D共6條指令搅轿,最終狀態(tài)為A/D病涨,只需1條指令就可以)

實現(xiàn)原理就是讀現(xiàn)有數(shù)據(jù)庫的狀態(tài),根據(jù)狀態(tài)反推指令璧坟,跟之前的AOF無關既穆。同樣,為了避免長時間耗時雀鹃,重寫工作放在子進程進行幻工。

3.RDB持久化

SAVE和BGSAVE兩個命令都是用于生成RDB文件,區(qū)別在于BGSAVE會fork出一個子進程單獨進行黎茎,不影響Redis處理正常請求囊颅。

定時和定次數(shù)后進行持久化操作。

簡而言之傅瞻,RDB的過程其實是比較簡單的踢代,滿足條件后直接去寫RDB文件就結束了。

四.多機和集群

1.主從服務器

避免單點是所有服務的通用問題嗅骄,Redis也不例外胳挎。解決單點就要有備機,有備機就要解決固有的數(shù)據(jù)同步問題溺森。

1.1 sync——原始版主從同步

Redis最初的同步做法是sync指令慕爬,通過sync每次都會全量數(shù)據(jù),顯然每次都全量復制的設計比較消耗資源屏积。改進思路也是常規(guī)邏輯医窿,第一次全量,剩下的增量炊林,這就是現(xiàn)在的psync指令的活姥卢。

1.2 psync

部分重同步實現(xiàn)的技術手段是“偏移序號+積壓緩沖區(qū)”,具體做法如下:

(1)主從分別維護一個seq铛铁,主每次完成一個請求便seq+1隔显,從每同步完后更新自己seq;

(2)從每次打算同步時都是攜帶著自己的seq到主饵逐,主將自身的seq與從做差結果與積壓緩沖區(qū)大小比較括眠,如果小于積壓緩沖區(qū)大小,直接從積壓緩沖區(qū)取相應的操作進行部分重同步倍权;

(3)否則說明積壓緩沖區(qū)不能夠cover掉主從不一致的數(shù)據(jù)掷豺,進行全量同步。

本質做法用空間換時間薄声,顯然在這里犧牲部分空間換回高效的部分重同步当船,收益比很大。

2.Sentinel

本質:多主從服務器的Redis系統(tǒng)默辨,多臺主從上加了管理監(jiān)控德频,以保證系統(tǒng)高可用性。

3.集群

Redis的官方版集群尚未在工業(yè)界普及起來缩幸,下面主要介紹一下集群的管理體系和運轉體系壹置。

2.1 slot-集群單位

集群的數(shù)據(jù)區(qū)由slot組成,每個節(jié)點負責的slot是在集群啟動時分配的表谊。

2.2 客戶請求

客戶請求時如果相應數(shù)據(jù)hash后不屬于請求節(jié)點所管理的slots钞护,會給客戶返回MOVED錯誤,并給出正確的slots爆办。

從這個層面看难咕,redis的集群還不夠友好,集群內部的狀態(tài)必須由客戶感知距辆。

2.3 容災

主從服務器余佃,從用于備份主,一旦主故障跨算,從代替主咙冗。

通過Redis的研究,深刻體會到的一點就是:所有設計的過程都是權衡和割舍的過程漂彤。同樣放到日常的工作和開發(fā)中也是如此雾消,一句代碼寫的好不好,一個模塊設計的是否科學挫望,就從速度和內存的角度去衡量看是否需要優(yōu)化立润,并去評估每一種優(yōu)化會收益到什么,同時會損失什么媳板,收益遠大于損失的就是好的優(yōu)化桑腮,這樣往往對于開發(fā)和提升更有針對性,更能提高效率蛉幸。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末破讨,一起剝皮案震驚了整個濱河市丛晦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌提陶,老刑警劉巖烫沙,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異隙笆,居然都是意外死亡锌蓄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門撑柔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘸爽,“玉大人,你說我怎么就攤上這事铅忿〖艟觯” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵檀训,是天一觀的道長昼捍。 經常有香客問我,道長肢扯,這世上最難降的妖魔是什么妒茬? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蔚晨,結果婚禮上乍钻,老公的妹妹穿的比我還像新娘。我一直安慰自己铭腕,他們只是感情好银择,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著累舷,像睡著了一般浩考。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上被盈,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天析孽,我揣著相機與錄音,去河邊找鬼只怎。 笑死袜瞬,一個胖子當著我的面吹牛,可吹牛的內容都是我干的身堡。 我是一名探鬼主播邓尤,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了汞扎?” 一聲冷哼從身側響起季稳,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎澈魄,沒想到半個月后景鼠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡一忱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谭确。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帘营。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逐哈,靈堂內的尸體忽然破棺而出芬迄,到底是詐尸還是另有隱情,我是刑警寧澤昂秃,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布禀梳,位于F島的核電站,受9級特大地震影響肠骆,放射性物質發(fā)生泄漏算途。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一蚀腿、第九天 我趴在偏房一處隱蔽的房頂上張望嘴瓤。 院中可真熱鬧,春花似錦莉钙、人聲如沸廓脆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽停忿。三九已至,卻和暖如春蚊伞,著一層夾襖步出監(jiān)牢的瞬間席赂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工时迫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留氧枣,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓别垮,卻偏偏與公主長得像便监,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內容