Redis為什么這么快坝辫?

我們都知道Redis很快蔚出,它QPS可達10萬(每秒請求數)

基于內存實現

我們都知道內存讀寫是比磁盤讀寫快很多的。Redis是基于內存存儲實現的數據庫箩做,相對于數據存在磁盤的數據庫莽红,就省去磁盤磁盤I/O的消耗。MySQL等磁盤數據庫邦邦,需要建立索引來加快查詢效率安吁,而Redis數據存放在內存,直接操作內存燃辖,所以就很快鬼店。

高效的數據結構

我們知道,MySQL索引為了提高效率黔龟,選擇了B+樹的數據結構妇智。其實合理的數據結構,就是可以讓你的應用/程序更快氏身。先看下Redis的數據結構&內部編碼圖:

SDS簡單動態(tài)字符串

struct sdshdr { //SDS簡單動態(tài)字符串
    int len;    //記錄buf中已使用的空間
    int free;   // buf中空閑空間長度
    char buf[]; //存儲的實際內容
}

字符串長度處理

在C語言中巍棱,要獲取撿田螺的小男孩這個字符串的長度,需要從頭開始遍歷蛋欣,復雜度為O(n); 在Redis中航徙, 已經有一個len字段記錄當前字符串的長度啦,直接獲取即可陷虎,時間復雜度為O(1)捉偏。

減少內存重新分配的次數

在C語言中,修改一個字符串泻红,需要重新分配內存夭禽,修改越頻繁,內存分配就越頻繁谊路,而分配內存是會消耗性能的讹躯。而在Redis中,SDS提供了兩種優(yōu)化策略:空間預分配和惰性空間釋放。

空間預分配

當SDS簡單動態(tài)字符串修改和空間擴充時潮梯,除了分配必需的內存空間骗灶,還會額外分配未使用的空間。分配規(guī)則是醬紫的:

  • SDS修改后秉馏,len的長度小于1M耙旦,那么將額外分配與len相同長度的未使用空間。比如len=100萝究,重新分配后免都,buf 的實際長度會變?yōu)?00(已使用空間)+100(額外空間)+1(空字符)=201。
  • SDS修改后, len長度大于1M帆竹,那么程序將分配1M的未使用空間绕娘。

惰性空間釋放

當SDS縮短時,不是回收多余的內存空間栽连,而是用free記錄下多余的空間险领。后續(xù)再有修改操作,直接使用free中的空間秒紧,減少內存分配绢陌。

哈希

Redis 作為一個K-V的內存數據庫,它使用用一張全局的哈希來保存所有的鍵值對熔恢。這張哈希表下面,有多個哈希桶組成,哈希桶中的entry元素保存了*key*value指針绩聘,其中*key指向了實際的鍵沥割,*value指向了實際的值。

哈希表查找速率很快的凿菩,有點類似于Java中的HashMap机杜,它讓我們在O(1) 的時間復雜度快速找到鍵值對。首先通過key計算哈希值衅谷,找到對應的哈希桶位置椒拗,然后定位到entry,在entry找到對應的數據获黔。

有些小伙伴可能會有疑問:你往哈希表中寫入大量數據時蚀苛,不是會遇到哈希沖突問題嘛,那效率就會降下來啦玷氏。

哈希沖突: 通過不同的key堵未,計算出一樣的哈希值,導致落在同一個哈希桶中盏触。

Redis為了解決哈希沖突渗蟹,采用了鏈式哈希块饺。鏈式哈希是指同一個哈希桶中,多個元素用一個鏈表來保存雌芽,它們之間依次用指針連接授艰。

有些小伙伴可能還會有疑問:哈希沖突鏈上的元素只能通過指針逐一查找再操作。當往哈希表插入數據很多世落,沖突也會越多淮腾,沖突鏈表就會越長,那查詢效率就會降低了屉佳。

為了保持高效谷朝,Redis 會對哈希表做rehash操作,也就是增加哈希桶忘古,減少沖突。為了rehash更高效诅诱,Redis還默認使用了兩個全局哈希表髓堪,一個用于當前使用,稱為主哈希表娘荡,一個用于擴容干旁,稱為備用哈希表。

跳躍表

跳躍表是Redis特有的數據結構炮沐,它其實就是在鏈表的基礎上争群,增加多級索引,以提高查找效率大年。跳躍表的簡單原理圖如下:

  • 每一層都有一條有序的鏈表换薄,最底層的鏈表包含了所有的元素。
  • 跳躍表支持平均 O(logN),最壞 O(N)復雜度的節(jié)點查找翔试,還可以通過順序性操作批量處理節(jié)點轻要。

壓縮列表ziplist

壓縮列表ziplist是列表鍵和字典鍵的的底層實現之一。它是由一系列特殊編碼的內存塊構成的列表垦缅, 一個ziplist可以包含多個entry冲泥, 每個entry可以保存一個長度受限的字符數組或者整數,如下:

  • zlbytes :記錄整個壓縮列表占用的內存字節(jié)數
  • zltail: 尾節(jié)點至起始節(jié)點的偏移量
  • zllen : 記錄整個壓縮列表包含的節(jié)點數量
  • entryX: 壓縮列表包含的各個節(jié)點
  • zlend : 特殊值0xFF(十進制255)壁涎,用于標記壓縮列表末端

由于內存是連續(xù)分配的凡恍,所以遍歷速度很快。怔球。

合理的數據編碼

Redis支持多種數據基本類型嚼酝,每種基本類型對應不同的數據結構,每種數據結構對應不一樣的編碼竟坛。為了提高性能革半,Redis設計者總結出碑定,數據結構最適合的編碼搭配。

Redis是使用對象(redisObject)來表示數據庫中的鍵值又官,當我們在 Redis 中創(chuàng)建一個鍵值對時延刘,至少創(chuàng)建兩個對象,一個對象是用做鍵值對的鍵對象六敬,另一個是鍵值對的值對象碘赖。

typedef struct redisObject{
    //類型
   unsigned type:4;
   //編碼
   unsigned encoding:4;
   //指向底層數據結構的指針
   void *ptr;
    //...
 }robj;

redisObject中,type 對應的是對象類型外构,包含String對象普泡、List對象、Hash對象审编、Set對象撼班、zset對象。encoding 對應的是編碼垒酬。

  • String:如果存儲數字的話砰嘁,是用int類型的編碼;如果存儲非數字,小于等于39字節(jié)的字符串勘究,是embstr矮湘;大于39個字節(jié),則是raw編碼口糕。
  • List:如果列表的元素個數小于512個缅阳,列表每個元素的值都小于64字節(jié)(默認),使用ziplist編碼景描,否則使用linkedlist編碼
  • Hash:哈希類型元素個數小于512個十办,所有值小于64字節(jié)的話,使用ziplist編碼,否則使用hashtable編碼超棺。
  • Set:如果集合中的元素都是整數且元素個數小于512個橘洞,使用intset編碼,否則使用hashtable編碼说搅。
  • Zset:當有序集合的元素個數小于128個炸枣,每個元素的值小于64字節(jié)時,使用ziplist編碼弄唧,否則使用skiplist(跳躍表)編碼

合理的線程模型

單線程模型:避免了上下文切換

Redis是單線程的适肠,其實是指Redis的網絡IO和鍵值對讀寫是由一個線程來完成的。但Redis的其他功能候引,比如持久化侯养、異步刪除、集群數據同步等等澄干,實際是由額外的線程執(zhí)行的逛揩。

Redis的單線程模型柠傍,避免了CPU不必要的上下文切換競爭鎖的消耗。也正因為是單線程辩稽,如果某個命令執(zhí)行過長(如hgetall命令)惧笛,會造成阻塞。Redis是面向快速執(zhí)行場景的內存數據庫逞泄,所以要慎用如lrange和smembers患整、hgetall等命令。

什么是上下文切換喷众?

舉個粟子:

  • 比如你在看一本英文小說各谚,你看到某一頁,發(fā)現有個單詞不會讀到千,你加了個書簽昌渤,然后去查字典。查完字典后憔四,你回來從書簽那里繼續(xù)開始讀膀息,這個流程就很舒暢。
  • 如果你一個人讀這本書加矛,肯定沒啥問題履婉。但是如果你去查字典的時候煤篙,別的小伙伴翻了一下你的書斟览,然后溜了。你再回來看的時候辑奈,發(fā)現書不是你看的那一頁了苛茂,你得花時間找到你的那一頁。
  • 一本書鸠窗,你一個人怎么看怎么打標簽都沒事妓羊,但是人多了翻來翻去,這本書各種標記就很亂了稍计≡瓿瘢可能這個解釋很粗糙,但是道理應該是一樣的臣嚣。

I/O 多路復用

什么是I/O多路復用净刮?

  • I/O :網絡 I/O
  • 多路 :多個網絡連接
  • 復用:復用同一個線程。
  • IO多路復用其實就是一種同步IO模型硅则,它實現了一個線程可以監(jiān)視多個文件句柄淹父;一旦某個文件句柄就緒,就能夠通知應用程序進行相應的讀寫操作怎虫;而沒有文件句柄就緒時,就會阻塞應用程序暑认,交出cpu困介。

多路I/O復用技術可以讓單個線程高效的處理多個連接請求,而Redis使用用epoll作為I/O多路復用技術的實現蘸际。并且Redis自身的事件處理模型將epoll中的連接座哩、讀寫、關閉都轉換為事件捡鱼,不在網絡I/O上浪費過多的時間八回。

虛擬內存機制

Redis直接自己構建了VM機制 ,不會像一般的系統(tǒng)會調用系統(tǒng)函數處理驾诈,會浪費一定的時間去移動和請求缠诅。

Redis的虛擬內存機制是啥呢?

虛擬內存機制就是暫時把不經常訪問的數據(冷數據)從內存交換到磁盤中乍迄,從而騰出寶貴的內存空間用于其它需要訪問的數據(熱數據)管引。通過VM功能可以實現冷熱數據分離,使熱數據仍在內存中闯两、冷數據保存到磁盤褥伴。這樣就可以避免因為內存不足而造成訪問速度下降的問題。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末漾狼,一起剝皮案震驚了整個濱河市重慢,隨后出現的幾起案子,更是在濱河造成了極大的恐慌逊躁,老刑警劉巖似踱,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異稽煤,居然都是意外死亡核芽,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門酵熙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轧简,“玉大人,你說我怎么就攤上這事匾二∠溃” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵察藐,是天一觀的道長皮璧。 經常有香客問我,道長转培,這世上最難降的妖魔是什么恶导? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮浸须,結果婚禮上惨寿,老公的妹妹穿的比我還像新娘邦泄。我一直安慰自己,他們只是感情好裂垦,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布顺囊。 她就那樣靜靜地躺著,像睡著了一般蕉拢。 火紅的嫁衣襯著肌膚如雪特碳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天晕换,我揣著相機與錄音午乓,去河邊找鬼。 笑死闸准,一個胖子當著我的面吹牛益愈,可吹牛的內容都是我干的。 我是一名探鬼主播夷家,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼蒸其,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了库快?” 一聲冷哼從身側響起摸袁,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎义屏,沒想到半個月后靠汁,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡湿蛔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年膀曾,在試婚紗的時候發(fā)現自己被綠了县爬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阳啥。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖财喳,靈堂內的尸體忽然破棺而出察迟,到底是詐尸還是另有隱情,我是刑警寧澤耳高,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布扎瓶,位于F島的核電站,受9級特大地震影響泌枪,放射性物質發(fā)生泄漏概荷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一碌燕、第九天 我趴在偏房一處隱蔽的房頂上張望误证。 院中可真熱鬧继薛,春花似錦、人聲如沸愈捅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓝谨。三九已至灌具,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間譬巫,已是汗流浹背咖楣。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芦昔,地道東北人截歉。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像烟零,于是被迫代替她去往敵國和親瘪松。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內容

  • 我們都知道Redis很快,它QPS可達10萬(每秒請求數)墅诡。Redis為什么這么快呢,本文將跟大家一起學習壳嚎。 基于...
    廢柴程序員閱讀 236評論 1 2
  • Redis 作為一種 KV 緩存服務器,有著極高的性能末早,相對于 Memcache烟馅,Redis 支持更多種數據類型,...
    為愛放棄一切閱讀 517評論 0 8
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月然磷,有人笑有人哭郑趁,有人歡樂有人憂愁,有人驚喜有人失落姿搜,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,523評論 28 53
  • 信任包括信任自己和信任他人 很多時候寡润,很多事情,失敗舅柜、遺憾梭纹、錯過,源于不自信致份,不信任他人 覺得自己做不成变抽,別人做不...
    吳氵晃閱讀 6,181評論 4 8
  • 步驟:發(fā)微博01-導航欄內容 -> 發(fā)微博02-自定義TextView -> 發(fā)微博03-完善TextView和...
    dibadalu閱讀 3,127評論 1 3