国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Redis熱點之底層實現篇

存儲 存儲軟件 Redis
Redis提供了Java、C/C++、C#、 PHP 、JavaScript、 Perl 、Object-C、Python、Ruby、Erlang、Golang等多種主流語言的客戶端,因此無論使用者是什么語言棧總會找到屬于自己的那款客戶端,受眾非常廣。

 [[327904]]

通過本文你將了解到以下內容:

  • Redis的作者、發展演進和江湖地位
  • Redis面試問題的概況

Redis底層實現相關的問題包括:

常用數據類型底層實現、SDS的原理和優勢、字典的實現原理、跳表和有序集合的原理、Redis的線程模式和服務模型

溫馨提示:內容并不難,就怕你不看。

看不懂可以先收藏先Mark,等到深入研究的時間再翻出來看看,你就發現真是24K干貨呀!停止吹噓,寫點不一樣的文字吧!

1.Redis往事

Redis是一個使用ANSI C編寫的開源、支持網絡、基于內存、可選持久化的高性能鍵值對數據庫。Redis的之父是來自意大利的西西里島的Salvatore Sanfilippo,Github網名antirez,筆者找了作者的一些簡要信息并翻譯了一下,如圖:

 

Redis面試熱點之底層實現篇

 

從2009年第一個版本起Redis已經走過了10個年頭,目前Redis仍然是最流行的key-value型內存數據庫的之一。

優秀的開源項目離不開大公司的支持,在2013年5月之前,其開發由VMware贊助,而2013年5月至2015年6月期間,其開發由畢威拓贊助,從2015年6月開始,Redis的開發由Redis Labs贊助。

 

Redis面試熱點之底層實現篇

 

筆者也使用過一些其他的NoSQL,有的支持的value類型非常單一,因此很多操作都必須在客戶端實現,比如value是一個結構化的數據,需要修改其中某個字段就需要整體讀出來修改再整體寫入,顯得很笨重,但是Redis的value支持多種類型,實現了很多操作在服務端就可以完成了,這個對客戶端而言非常方便。

當然Redis由于是內存型的數據庫,數據量存儲量有限而且分布式集群成本也會非常高,因此有很多公司開發了基于SSD的類Redis系統,比如360開發的SSDB、Pika等數據庫,但是筆者認為從0到1的難度是大于從1到2的難度的,毋庸置疑Redis是NoSQL中濃墨重彩的一筆,值得我們去深入研究和使用。

2.Redis的江湖地位

Redis提供了Java、C/C++、C#、 PHP 、JavaScript、 Perl 、Object-C、Python、Ruby、Erlang、Golang等多種主流語言的客戶端,因此無論使用者是什么語言棧總會找到屬于自己的那款客戶端,受眾非常廣。

筆者查了http://datanyze.com網站看了下Redis和MySQL的最新市場份額和排名對比以及全球Top站點的部署量對比(網站數據更新到寫作當日2019.12.11):

 

Redis面試熱點之底層實現篇

 

 

Redis面試熱點之底層實現篇

 

可以看到Redis總體份額排名第9并且在全球Top100站點中部署數量與MySQL基本持平,所以Redis還是有一定的江湖地位的。

3.聊聊實戰

目前Redis發布的穩定版本已經到了5.x,功能也越來越強大,從國內外互聯網公司來看Redis幾乎是標配了。作為開發人員在日常筆試面試和工作中遇到Redis相關問題的概率非常大,掌握Redis的相關知識點都十分有必要。

學習和梳理一個復雜的東西肯定不能胡子眉毛一把抓,每個人都有自己的認知思路,筆者認為要從充分掌握Redis需要從底向上、從外到內去理解Redis。

Redis的實戰知識點可以簡單分為三個層次:

  • 底層實現:主要是從Redis的源碼中提煉的問題,包括但不限于底層數據結構、服務模型、算法設計等。
  • 基礎架構:可用概況為Redis整體對外的功能點和表現,包括但不限于單機版主從架構實現、主從數據同步、哨兵機制、集群實現、分布式一致性、故障遷移等。
  • 實際應用:實戰中Redis可用幫你做什么,包括但不限于單機緩存、分布式緩存、分布式鎖、一些應用。

 

Redis面試熱點之底層實現篇

 

深入理解和熟練使用Redis需要時間錘煉,要做到信手拈來著實不易,想在短時間內突破只能從熱點題目入手,雖然這樣感覺有些功利,不過也算無可厚非吧,為了吃飯我們還是傾向于原諒懶惰的自己,要不然吃土喝風?

 

[[327907]]

 

4.底層實現熱點題目

底層實現篇的題目主要是與Redis的源碼和設計相關,可以說是Redis功能的基石,了解底層實現可以讓我們更好地掌握功能,由于底層代碼很多,在后續的基礎架構篇中仍然會穿插源碼來分析,因此本篇只列舉一些熱點的問題。

Q1: Redis常用五種數據類型是如何實現的?

Redis支持的常用5種數據類型指的是value類型,分別為:字符串String、列表List、哈希Hash、集合Set、有序集合Zset,但是Redis后續又豐富了幾種數據類型分別是Bitmaps、HyperLogLogs、GEO。

由于Redis是基于標準C寫的,只有最基礎的數據類型,因此Redis為了滿足對外使用的5種數據類型,開發了屬于自己獨有的一套基礎數據結構,使用這些數據結構來實現5種數據類型。

Redis底層的數據結構包括:簡單動態數組SDS、鏈表、哈希表、跳躍鏈表、整數集合、壓縮列表、對象。

Redis為了平衡空間和時間效率,針對value的具體類型在底層會采用不同的數據結構來實現,其中哈希表和壓縮列表是復用比較多的數據結構,如下圖展示了對外數據類型和底層數據結構之間的映射關系:

 

Redis面試熱點之底層實現篇

 

 

Redis面試熱點之底層實現篇

 

從圖中可以看到ziplist壓縮列表可以作為Zset、Set、List三種數據類型的底層實現,看來很強大,壓縮列表是一種為了節約內存而開發的且經過特殊編碼之后的連續內存塊順序型數據結構,底層結構還是比較復雜的。

Q2: Redis的SDS和C中字符串相比有什么優勢?

在C語言中使用N+1長度的字符數組來表示字符串,尾部使用'\0'作為結尾標志,對于此種實現無法滿足Redis對于安全性、效率、豐富的功能的要求,因此Redis單獨封裝了SDS簡單動態字符串結構。

在理解SDS的優勢之前需要先看下SDS的實現細節,找了github最新的src/sds.h的定義看下:

看了前面的定義,筆者畫了個圖:

 

Redis面試熱點之底層實現篇

 

從圖中可以知道sds本質分為三部分:header、buf、null結尾符,其中header可以認為是整個sds的指引部分,給定了使用的空間大小、最大分配大小等信息,再用一張網上的圖來清晰看下sdshdr8的實例:

 

Redis面試熱點之底層實現篇

 

在sds.h/sds.c源碼中可清楚地看到sds完整的實現細節,本文就不展開了要不然篇幅就過長了,快速進入主題說下sds的優勢:

  • O(1)獲取長度: C字符串需要遍歷而sds中有len可以直接獲得;
  • 防止緩沖區溢出bufferoverflow: 當sds需要對字符串進行修改時,首先借助于len和alloc檢查空間是否滿足修改所需的要求,如果空間不夠的話,SDS會自動擴展空間,避免了像C字符串操作中的覆蓋情況;
  • 有效降低內存分配次數:C字符串在涉及增加或者清除操作時會改變底層數組的大小造成重新分配、sds使用了空間預分配和惰性空間釋放機制,說白了就是每次在擴展時是成倍的多分配的,在縮容是也是先留著并不正式歸還給OS,這兩個機制也是比較好理解的;

二進制安全:C語言字符串只能保存ascii碼,對于圖片、音頻等信息無法保存,sds是二進制安全的,寫入什么讀取就是什么,不做任何過濾和限制;

老規矩上一張黃健宏大神總結好的圖:

 

Redis面試熱點之底層實現篇

 

Q3:Redis的字典是如何實現的?簡述漸進式rehash的過程。

字典算是Redis5中常用數據類型中的明星成員了,前面說過字典可以基于ziplist和hashtable來實現,我們只討論基于hashtable實現的原理。

字典是個層次非常明顯的數據類型,如圖:

 

Redis面試熱點之底層實現篇

 

有了個大概的概念,我們看下最新的src/dict.h源碼定義:

  1. //哈希節點結構 
  2. typedef struct dictEntry { 
  3.  void *key
  4.  union { 
  5.  void *val; 
  6.  uint64_t u64; 
  7.  int64_t s64; 
  8.  double d; 
  9.  } v; 
  10.  struct dictEntry *next
  11. } dictEntry; 
  12.  
  13. //封裝的是字典的操作函數指針 
  14. typedef struct dictType { 
  15.  uint64_t (*hashFunction)(const void *key); 
  16.  void *(*keyDup)(void *privdata, const void *key); 
  17.  void *(*valDup)(void *privdata, const void *obj); 
  18.  int (*keyCompare)(void *privdata, const void *key1, const void *key2); 
  19.  void (*keyDestructor)(void *privdata, void *key); 
  20.  void (*valDestructor)(void *privdata, void *obj); 
  21. } dictType; 
  22.  
  23. /* This is our hash table structure. Every dictionary has two of this as we 
  24.  * implement incremental rehashing, for the old to the new table. */ 
  25. //哈希表結構 該部分是理解字典的關鍵 
  26. typedef struct dictht { 
  27.  dictEntry **table
  28.  unsigned long size
  29.  unsigned long sizemask; 
  30.  unsigned long used; 
  31. } dictht; 
  32.  
  33. //字典結構 
  34. typedef struct dict { 
  35.  dictType *type; 
  36.  void *privdata; 
  37.  dictht ht[2]; 
  38.  long rehashidx; /* rehashing not in progress if rehashidx == -1 */ 
  39.  unsigned long iterators; /* number of iterators currently running */ 
  40. } dict; 

C語言的好處在于定義必須是由最底層向外的,因此我們可以看到一個明顯的層次變化,于是筆者又畫一圖來展現具體的層次概念:

 

Redis面試熱點之底層實現篇

 

  • 關于dictEntry

dictEntry是哈希表節點,也就是我們存儲數據地方,其保護的成員有:key,v,next指針。key保存著鍵值對中的鍵,v保存著鍵值對中的值,值可以是一個指針或者是uint64_t或者是int64_t。next是指向另一個哈希表節點的指針,這個指針可以將多個哈希值相同的鍵值對連接在一次,以此來解決哈希沖突的問題。

如圖為兩個沖突的哈希節點的連接關系:

 

Redis面試熱點之底層實現篇

 

  • 關于dictht

從源碼看哈希表包括的成員有table、size、used、sizemask。table是一個數組,數組中的每個元素都是一個指向dictEntry結構的指針, 每個dictEntry結構保存著一個鍵值對;size 屬性記錄了哈希表table的大小,而used屬性則記錄了哈希表目前已有節點的數量。sizemask等于size-1和哈希值計算一個鍵在table數組的索引,也就是計算index時用到的。

 

Redis面試熱點之底層實現篇

 

如上圖展示了一個大小為4的table中的哈希節點情況,其中k1和k0在index=2發生了哈希沖突,進行開鏈表存在,本質上是先存儲的k0,k1放置是發生沖突為了保證效率直接放在沖突鏈表的最前面,因為該鏈表沒有尾指針。

  • 關于dict

從源碼中看到dict結構體就是字典的定義,包含的成員有type,privdata、ht、rehashidx。其中dictType指針類型的type指向了操作字典的api,理解為函數指針即可,ht是包含2個dictht的數組,也就是字典包含了2個哈希表,rehashidx進行rehash時使用的變量,privdata配合dictType指向的函數作為參數使用,這樣就對字典的幾個成員有了初步的認識。

 

Redis面試熱點之底層實現篇

 

字典的哈希算法

redis使用MurmurHash算法計算哈希值,該算法最初由Austin Appleby在2008年發明,MurmurHash算法的無論數據輸入情況如何都可以給出隨機分布性較好的哈希值并且計算速度非常快,目前有MurmurHash2和MurmurHash3等版本。

普通Rehash重新散列

哈希表保存的鍵值對數量是動態變化的,為了讓哈希表的負載因子維持在一個合理的范圍之內,就需要對哈希表進行擴縮容。

擴縮容是通過執行rehash重新散列來完成,對字典的哈希表執行普通rehash的基本步驟為分配空間->逐個遷移->交換哈希表,詳細過程如下:

1.為字典的ht[1]哈希表分配空間,分配的空間大小取決于要執行的操作以及ht[0]當前包含的鍵值對數量:

擴展操作時ht[1]的大小為第一個大于等于ht[0].used*2的2^n;

收縮操作時ht[1]的大小為第一個大于等于ht[0].used的2^n ;

擴展時比如h[0].used=200,那么需要選擇大于400的第一個2的冪,也就是2^9=512。

2.將保存在ht[0]中的所有鍵值對重新計算鍵的哈希值和索引值rehash到ht[1]上;

3.重復rehash直到ht[0]包含的所有鍵值對全部遷移到了ht[1]之后釋放 ht[0], 將ht[1]設置為 ht[0],并在ht[1]新創建一個空白哈希表, 為下一次rehash做準備。

  • 漸進Rehash過程

Redis的rehash動作并不是一次性完成的,而是分多次、漸進式地完成的,原因在于當哈希表里保存的鍵值對數量很大時, 一次性將這些鍵值對全部rehash到ht[1]可能會導致服務器在一段時間內停止服務,這個是無法接受的。

針對這種情況Redis采用了漸進式rehash,過程的詳細步驟:

  1. 為ht[1]分配空間,這個過程和普通Rehash沒有區別;
  2. 將rehashidx設置為0,表示rehash工作正式開始,同時這個rehashidx是遞增的,從0開始表示從數組第一個元素開始rehash。
  3. 在rehash進行期間,每次對字典執行增刪改查操作時,順帶將ht[0]哈希表在rehashidx索引上的鍵值對rehash到 ht[1],完成后將rehashidx加1,指向下一個需要rehash的鍵值對。
  4. 隨著字典操作的不斷執行,最終ht[0]的所有鍵值對都會被rehash至ht[1],再將rehashidx屬性的值設為-1來表示 rehash操作已完成。

漸進式 rehash的思想在于將rehash鍵值對所需的計算工作分散到對字典的每個添加、刪除、查找和更新操作上,從而避免了集中式rehash而帶來的阻塞問題。

看到這里不禁去想這種捎帶腳式的rehash會不會導致整個過程非常漫長?如果某個value一直沒有操作那么需要擴容時由于一直不用所以影響不大,需要縮容時如果一直不處理可能造成內存浪費,具體的還沒來得及研究,先埋個問題吧!

 

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2013-03-19 10:29:49

MySQLMySQL ProxyMySQL底層

2015-09-09 10:34:58

底層網絡技術網絡技術

2024-11-22 15:00:00

開源Redis鏈表

2020-05-14 11:19:19

降序索引子集

2021-08-29 07:41:48

數據HashMap底層

2023-03-01 22:28:15

Redis高可用

2021-08-31 07:36:22

LinkedListAndroid數據結構

2023-01-04 07:54:03

HashMap底層JDK

2021-03-28 21:33:07

Redis熱點key

2025-08-26 02:15:00

Redis字符串)SDS

2021-09-28 09:36:13

redisHash結構

2020-03-20 10:47:51

Redis數據庫字符串

2019-06-21 15:20:05

Redis數據結構數據庫

2022-12-19 08:00:00

SpringBootWeb開發

2022-11-15 08:10:23

SpringMyBatis底層

2023-10-31 15:08:56

WorkBoxServiceWorker

2014-11-26 10:44:33

DockerOpenStack云計算

2019-06-12 22:51:57

Redis軟件開發

2023-07-17 08:32:40

2024-04-11 11:04:05

Redis
點贊
收藏

51CTO技術棧公眾號

av网址在线观看免费| 国产丝袜在线播放| 亚洲久久一区二区| 日韩精品在线电影| 一区二区三区视频在线观看免费| 欧美日韩亚州综合| 狠狠色综合网站久久久久久久| 免费在线观看黄色| 9l国产精品久久久久麻豆| 国产精品国产三级国产aⅴ浪潮 | 最近2018中文字幕免费在线视频| 欧美一区网站| 亚洲日韩中文字幕在线播放| 国产1区2区3区| 久久精品72免费观看| 国产91|九色| 欧亚av在线| 一本一道综合狠狠老| 精品视频一区二区在线| 亚洲女人av| 国产成人精品午夜| 电影亚洲精品噜噜在线观看| 色猫猫国产区一区二在线视频| 欧美 日韩精品| 久久在线91| 91在线播放国产| 韩国三级大全久久网站| 欧美肥妇毛茸茸| 狠狠干五月天| 国产精品2024| 亚洲淫片在线视频| 超碰成人免费| 亚洲美女久久久| 日本视频在线| 第一福利永久视频精品| 激情婷婷综合网| 九色porny丨国产精品| 97久久夜色精品国产九色 | 亚洲精品国产精品乱码不99| 成人国产在线看| 亚洲国产清纯| 国产精品99免视看9| 高清国产一区二区三区四区五区| 欧美日韩一本到| 在线黄色国产视频| 国产精品网站导航| 北条麻妃在线视频观看| 激情国产一区二区| 欧美亚洲免费高清在线观看 | 一区二区在线视频观看| 亚洲精品视频免费| a毛片在线观看| 精品高清美女精品国产区| 成人免费黄色网址| 91蜜桃在线免费视频| 福利在线一区二区| 激情欧美日韩一区二区| 亚洲日本无吗高清不卡| 免播放器亚洲| 日韩在线第一区| 日本成人中文字幕| 秋霞毛片久久久久久久久| 99成人免费视频| 91在线在线观看| 中文在线日韩| 91视频网页| 99热在线精品观看| 国产手机精品在线| 妖精视频成人观看www| 久久99精品久久久久久青青日本| 国产一区美女| 国产精品久久久对白| 亚洲精品三级| 青青成人在线| 国产在线精品不卡| 一级黄色录像免费看| 精品在线一区二区| 日本福利视频网站| 久久综合狠狠综合久久激情| 美女一区二区三区视频| 亚洲男人天堂av| 中文字幕在线观| 欧美老年两性高潮| gogo久久| 久久中文字幕国产| 国产成人影院| 国产日韩欧美二区| 蜜臀精品久久久久久蜜臀| 亚洲精品天堂成人片av在线播放| 成人av免费在线| 国产主播色在线| 欧美日韩一区二区三区高清| 九色porny视频在线观看| 久久成人精品一区二区三区| 婷婷精品在线| 国产综合18久久久久久| 三级久久三级久久久| 中文字幕欧美人与畜| 成人小视频在线观看| 牛夜精品久久久久久久| 精品成人久久av| 阿v视频在线观看| 欧美激情综合色综合啪啪五月| 精品免费一区二区| 久久久久久久久久久久久久一区 | 亚洲精品久久久久久久久久久久| 都市激情亚洲一区| 久久久久久成人| 性欧美欧美巨大69| 视频一区二区精品| 久久久久久**毛片大全| 在线免费看污| 亚洲免费中文字幕| 91亚洲国产| 国产精品久久成人免费观看| 国产精品视频免费看| 一级日本在线| 国产一区二区三区在线观看网站| 欧美日韩黄色一区二区| 国产福利在线看| 日韩在线一区二区三区免费视频| 禁断一区二区三区在线| 亚洲视频sss| 一区二区三区四区国产精品| 免费在线中文字幕| 91精品国产高清自在线| 久久国产精品久久久久久电车| 国产在线观看福利| 欧美三级日韩三级| 视频一区在线| 国产伦精品一区二区三区免| 91性感美女视频| 日本中文字幕视频在线| 欧美激情影音先锋| 首页欧美精品中文字幕| 色之综合天天综合色天天棕色| 欧美一区二区三区精品电影| 最新日韩av| 亚洲精品国产一区| 先锋影音久久| 性生活免费在线观看| 欧美成人乱码一区二区三区| 要久久电视剧全集免费| 亚洲av首页在线| 婷婷综合另类小说色区| 成年人在线网站| 91精品在线影院| 国产日韩欧美不卡| 日韩伦理精品| 风间由美久久久| 亚洲女女做受ⅹxx高潮| 波多视频一区| 国产伦精品一区二区三区视频孕妇| 久久婷婷色综合| 欧美韩日亚洲| 国产在线播放91| 欧美国产综合一区二区| 香蕉伊大人中文在线观看| 国产99午夜精品一区二区三区 | 色综合 综合色| 林ゆな中文字幕一区二区| 国产 福利 在线| 日韩亚洲欧美成人| 91视频91自| 警花av一区二区三区| 国产91对白刺激露脸在线观看| 中文字幕不卡av| 久久在线观看免费| 乱亲女h秽乱长久久久| 麻豆一区二区三区四区精品蜜桃| 777精品视频| 亚洲6080在线| 国产高清视频网站| 在线免费观看羞羞视频一区二区| 国产精品影视网| 中文字幕视频一区二区在线有码| 欧美aa在线| 国产成人亚洲综合无码| 日韩在线观看免费高清| 欧美激情一区二区三区不卡| 亚洲成aⅴ人片久久青草影院| jizz蜜桃视频在线观看| 国产精品一香蕉国产线看观看| 午夜电影一区二区三区| 亚洲电影成人| 欧美aa免费在线| 久久久久久久香蕉| 蜜月aⅴ免费一区二区三区| 日本一区二区三区四区| 精品一区二区三区的国产在线观看| 在线视频专区| 欧美亚洲另类在线一区二区三区| 精品国产伦一区二区三区免费| 韩日av一区二区| 日韩视频在线直播| 亚洲精华国产| 欧美日韩天天操| 欧美成人合集magnet| 精品久久香蕉国产线看观看亚洲| 日韩电影一区二区三区四区|