偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

大廠經(jīng)典面試題:Redis為什么這么快?

存儲 存儲軟件 Redis
Redis是基于內(nèi)存存儲實現(xiàn)的數(shù)據(jù)庫,相對于數(shù)據(jù)存在磁盤的數(shù)據(jù)庫,就省去磁盤磁盤I/O的消耗。MySQL等磁盤數(shù)據(jù)庫,需要建立索引來加快查詢效率,而Redis數(shù)據(jù)存放在內(nèi)存,直接操作內(nèi)存,所以就很快。

 [[407551]]

前言

大家好呀,我是撿田螺的小男孩。我們都知道Redis很快,它QPS可達(dá)10萬(每秒請求數(shù))。Redis為什么這么快呢,本文將跟大家一起學(xué)習(xí)。

基于內(nèi)存實現(xiàn)

我們都知道內(nèi)存讀寫是比磁盤讀寫快很多的。Redis是基于內(nèi)存存儲實現(xiàn)的數(shù)據(jù)庫,相對于數(shù)據(jù)存在磁盤的數(shù)據(jù)庫,就省去磁盤磁盤I/O的消耗。MySQL等磁盤數(shù)據(jù)庫,需要建立索引來加快查詢效率,而Redis數(shù)據(jù)存放在內(nèi)存,直接操作內(nèi)存,所以就很快。

高效的數(shù)據(jù)結(jié)構(gòu)

我們知道,MySQL索引為了提高效率,選擇了B+樹的數(shù)據(jù)結(jié)構(gòu)。其實合理的數(shù)據(jù)結(jié)構(gòu),就是可以讓你的應(yīng)用/程序更快。先看下Redis的數(shù)據(jù)結(jié)構(gòu)&內(nèi)部編碼圖:

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

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

字符串長度處理

在C語言中,要獲取撿田螺的小男孩這個字符串的長度,需要從頭開始遍歷,復(fù)雜度為O(n); 在Redis中, 已經(jīng)有一個len字段記錄當(dāng)前字符串的長度啦,直接獲取即可,時間復(fù)雜度為O(1)。

減少內(nèi)存重新分配的次數(shù)

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

空間預(yù)分配

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

  • SDS修改后,len的長度小于1M,那么將額外分配與len相同長度的未使用空間。比如len=100,重新分配后,buf 的實際長度會變?yōu)?00(已使用空間)+100(額外空間)+1(空字符)=201。
  • SDS修改后, len長度大于1M,那么程序?qū)⒎峙?M的未使用空間。

惰性空間釋放

當(dāng)SDS縮短時,不是回收多余的內(nèi)存空間,而是用free記錄下多余的空間。后續(xù)再有修改操作,直接使用free中的空間,減少內(nèi)存分配。

哈希

Redis 作為一個K-V的內(nèi)存數(shù)據(jù)庫,它使用用一張全局的哈希來保存所有的鍵值對。這張哈希表,有多個哈希桶組成,哈希桶中的entry元素保存了*key和*value指針,其中*key指向了實際的鍵,*value指向了實際的值。

哈希表查找速率很快的,有點類似于Java中的HashMap,它讓我們在O(1) 的時間復(fù)雜度快速找到鍵值對。首先通過key計算哈希值,找到對應(yīng)的哈希桶位置,然后定位到entry,在entry找到對應(yīng)的數(shù)據(jù)。

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

  • 哈希沖突: 通過不同的key,計算出一樣的哈希值,導(dǎo)致落在同一個哈希桶中。”

Redis為了解決哈希沖突,采用了鏈?zhǔn)焦?。鏈?zhǔn)焦J侵竿粋€哈希桶中,多個元素用一個鏈表來保存,它們之間依次用指針連接。

有些小伙伴可能還會有疑問:哈希沖突鏈上的元素只能通過指針逐一查找再操作。當(dāng)往哈希表插入數(shù)據(jù)很多,沖突也會越多,沖突鏈表就會越長,那查詢效率就會降低了。

為了保持高效,Redis 會對哈希表做rehash操作,也就是增加哈希桶,減少沖突。為了rehash更高效,Redis還默認(rèn)使用了兩個全局哈希表,一個用于當(dāng)前使用,稱為主哈希表,一個用于擴(kuò)容,稱為備用哈希表。

跳躍表

跳躍表是Redis特有的數(shù)據(jù)結(jié)構(gòu),它其實就是在鏈表的基礎(chǔ)上,增加多級索引,以提高查找效率。跳躍表的簡單原理圖如下:

每一層都有一條有序的鏈表,最底層的鏈表包含了所有的元素。

跳躍表支持平均 O(logN),最壞 O(N)復(fù)雜度的節(jié)點查找,還可以通過順序性操作批量處理節(jié)點。

壓縮列表ziplist

壓縮列表ziplist是列表鍵和字典鍵的的底層實現(xiàn)之一。它是由一系列特殊編碼的內(nèi)存塊構(gòu)成的列表, 一個ziplist可以包含多個entry, 每個entry可以保存一個長度受限的字符數(shù)組或者整數(shù),如下:

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

由于內(nèi)存是連續(xù)分配的,所以遍歷速度很快。。

合理的數(shù)據(jù)編碼

Redis支持多種數(shù)據(jù)基本類型,每種基本類型對應(yīng)不同的數(shù)據(jù)結(jié)構(gòu),每種數(shù)據(jù)結(jié)構(gòu)對應(yīng)不一樣的編碼。為了提高性能,Redis設(shè)計者總結(jié)出,數(shù)據(jù)結(jié)構(gòu)最適合的編碼搭配。

Redis是使用對象(redisObject)來表示數(shù)據(jù)庫中的鍵值,當(dāng)我們在 Redis 中創(chuàng)建一個鍵值對時,至少創(chuàng)建兩個對象,一個對象是用做鍵值對的鍵對象,另一個是鍵值對的值對象。

  1. //關(guān)注公眾號:撿田螺的小男孩 
  2. typedef struct redisObject{ 
  3.     //類型 
  4.    unsigned type:4; 
  5.    //編碼 
  6.    unsigned encoding:4; 
  7.    //指向底層數(shù)據(jù)結(jié)構(gòu)的指針 
  8.    void *ptr; 
  9.     //... 
  10.  }robj; 

redisObject中,type 對應(yīng)的是對象類型,包含String對象、List對象、Hash對象、Set對象、zset對象。encoding 對應(yīng)的是編碼。

  • String:如果存儲數(shù)字的話,是用int類型的編碼;如果存儲非數(shù)字,小于等于39字節(jié)的字符串,是embstr;大于39個字節(jié),則是raw編碼。
  • List:如果列表的元素個數(shù)小于512個,列表每個元素的值都小于64字節(jié)(默認(rèn)),使用ziplist編碼,否則使用linkedlist編碼
  • Hash:哈希類型元素個數(shù)小于512個,所有值小于64字節(jié)的話,使用ziplist編碼,否則使用hashtable編碼。
  • Set:如果集合中的元素都是整數(shù)且元素個數(shù)小于512個,使用intset編碼,否則使用hashtable編碼。
  • Zset:當(dāng)有序集合的元素個數(shù)小于128個,每個元素的值小于64字節(jié)時,使用ziplist編碼,否則使用skiplist(跳躍表)編碼

合理的線程模型

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

Redis是單線程的,其實是指Redis的網(wǎng)絡(luò)IO和鍵值對讀寫是由一個線程來完成的。但Redis的其他功能,比如持久化、異步刪除、集群數(shù)據(jù)同步等等,實際是由額外的線程執(zhí)行的。

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

什么是上下文切換?舉個粟子:

  • 比如你在看一本英文小說,你看到某一頁,發(fā)現(xiàn)有個單詞不會讀,你加了個書簽,然后去查字典。查完字典后,你回來從書簽?zāi)抢锢^續(xù)開始讀,這個流程就很舒暢。
  • 如果你一個人讀這本書,肯定沒啥問題。但是如果你去查字典的時候,別的小伙伴翻了一下你的書,然后溜了。你再回來看的時候,發(fā)現(xiàn)書不是你看的那一頁了,你得花時間找到你的那一頁。
  • 一本書,你一個人怎么看怎么打標(biāo)簽都沒事,但是人多了翻來翻去,這本書各種標(biāo)記就很亂了??赡苓@個解釋很粗糙,但是道理應(yīng)該是一樣的。

I/O 多路復(fù)用

什么是I/O多路復(fù)用?

  • I/O :網(wǎng)絡(luò) I/O
  • 多路 :多個網(wǎng)絡(luò)連接
  • 復(fù)用:復(fù)用同一個線程。
  • IO多路復(fù)用其實就是一種同步IO模型,它實現(xiàn)了一個線程可以監(jiān)視多個文件句柄;一旦某個文件句柄就緒,就能夠通知應(yīng)用程序進(jìn)行相應(yīng)的讀寫操作;而沒有文件句柄就緒時,就會阻塞應(yīng)用程序,交出cpu。

  • 多路I/O復(fù)用技術(shù)可以讓單個線程高效的處理多個連接請求,而Redis使用用epoll作為I/O多路復(fù)用技術(shù)的實現(xiàn)。并且Redis自身的事件處理模型將epoll中的連接、讀寫、關(guān)閉都轉(zhuǎn)換為事件,不在網(wǎng)絡(luò)I/O上浪費過多的時間。”

虛擬內(nèi)存機(jī)制

Redis直接自己構(gòu)建了VM機(jī)制 ,不會像一般的系統(tǒng)會調(diào)用系統(tǒng)函數(shù)處理,會浪費一定的時間去移動和請求。

Redis的虛擬內(nèi)存機(jī)制是啥呢?

  • 虛擬內(nèi)存機(jī)制就是暫時把不經(jīng)常訪問的數(shù)據(jù)(冷數(shù)據(jù))從內(nèi)存交換到磁盤中,從而騰出寶貴的內(nèi)存空間用于其它需要訪問的數(shù)據(jù)(熱數(shù)據(jù))。通過VM功能可以實現(xiàn)冷熱數(shù)據(jù)分離,使熱數(shù)據(jù)仍在內(nèi)存中、冷數(shù)據(jù)保存到磁盤。這樣就可以避免因為內(nèi)存不足而造成訪問速度下降的問題。”

參考資料

[1]Redis之VM機(jī)制: https://www.codenong.com/cs106843764/

[2]一文揭秘單線程的Redis為什么這么快?: https://zhuanlan.zhihu.com/p/57089960

[3]洞察|Redis是單線程的,但Redis為什么這么快?: https://zhuanlan.zhihu.com/p/42272979

責(zé)任編輯:武曉燕 來源: 撿田螺的小男孩
相關(guān)推薦

2024-07-24 08:38:07

2023-08-29 07:46:08

Redis數(shù)據(jù)ReHash

2019-10-18 09:40:19

程序員固態(tài)硬盤Linux

2023-03-21 08:02:36

Redis6.0IO多線程

2024-02-26 21:15:20

Kafka緩存參數(shù)

2020-02-27 15:44:41

Nginx服務(wù)器反向代理

2020-02-27 21:03:30

調(diào)度器架構(gòu)效率

2025-06-18 08:20:00

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

2020-10-21 09:17:52

Redis面試內(nèi)存

2022-01-04 08:54:32

Redis數(shù)據(jù)庫數(shù)據(jù)類型

2020-03-30 15:05:46

Kafka消息數(shù)據(jù)

2014-07-28 14:00:40

linux面試題

2019-06-17 14:20:51

Redis數(shù)據(jù)庫Java

2020-04-26 09:48:11

MySQL數(shù)據(jù)庫架構(gòu)

2021-05-27 20:56:51

esbuild 工具JavaScript

2020-10-15 09:19:36

Elasticsear查詢速度

2012-08-22 09:32:54

面試面試題

2020-05-06 15:02:58

MySQL數(shù)據(jù)庫技術(shù)

2023-05-04 11:39:17

經(jīng)營分析流量項目

2022-03-31 11:38:09

經(jīng)營分析傳統(tǒng)企業(yè)運營商
點贊
收藏

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