亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Redis高性能的原因及說明

 更新時間:2023年10月25日 10:53:22   作者:leo龍龍  
這篇文章主要介紹了Redis高性能的原因及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

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

Redis 是基于內(nèi)存的數(shù)據(jù)庫,那不可避免的就要與磁盤數(shù)據(jù)庫做對比。

對于磁盤數(shù)據(jù)庫來說,是需要將數(shù)據(jù)讀取到內(nèi)存里的,這個過程會受到磁盤 I/O 的限制。

而對于內(nèi)存數(shù)據(jù)庫來說,本身數(shù)據(jù)就存在于內(nèi)存里,也就沒有了這方面的開銷。

二、高效的數(shù)據(jù)結構

Redis 中有多種數(shù)據(jù)類型,每種數(shù)據(jù)類型的底層都由一種或多種數(shù)據(jù)結構來支持。

正是因為有了這些數(shù)據(jù)結構,Redis 在存儲與讀取上的速度才不受阻礙。

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

(1)字符串長度處理

用一個 len 字段記錄當前字符串的長度。想要獲取長度只需要獲取 len 字段即可,時間復雜度為 O(1)。

(2)內(nèi)存重新分配

修改字符串的時候會重新分配內(nèi)存。修改地越頻繁,內(nèi)存分配也就越頻繁。而內(nèi)存分配是會消耗性能的,那么性能下降在所難免。而 Redis 中會涉及到字符串頻繁的修改操作,于是 SDS 實現(xiàn)了兩種優(yōu)化策略:

  • - 空間預分配

對 SDS 修改及空間擴充時,除了分配所必須的空間外,還會額外分配未使用的空間。

具體分配規(guī)則是這樣的:SDS 修改后,len 長度小于 1M,那么將會額外分配與 len 相同長度的未使用空間。如果修改后長度大于 1M,那么將分配1M的使用空間。

  • - 惰性空間釋放

當然,有空間分配對應的就有空間釋放。

SDS 縮短時,并不會回收多余的內(nèi)存空間,而是使用 free 字段將多出來的空間記錄下來。如果后續(xù)有變更操作,直接使用 free 中記錄的空間,減少了內(nèi)存的分配。

(3)二進制安全

讀取字符串遇到 ‘\0’ 會結束,那 ‘\0’ 之后的數(shù)據(jù)就讀取不上了。但在 SDS 中,是根據(jù) len 長度來判斷字符串結束的,二進制安全的問題就解決了。

2. 雙端鏈表

  • - 頭尾節(jié)點

頭節(jié)點里有 head 和 tail 兩個參數(shù),分別指向頭節(jié)點和尾節(jié)點。這樣的設計能夠?qū)﹄p端節(jié)點的處理時間復雜度降至 O(1) ,對于隊列和棧來說再適合不過。同時鏈表迭代時從兩端都可以進行。

  • - 鏈表長度

頭節(jié)點里同時還有一個參數(shù) len,和上邊提到的 SDS 里類似,這里是用來記錄鏈表長度的。因此獲取鏈表長度時不用再遍歷整個鏈表,直接拿到 len 值就可以了,這個時間復雜度是 O(1)。

  • - 每個節(jié)點

鏈表里每個節(jié)點都帶有兩個指針,prev 指向前節(jié)點,next 指向后節(jié)點。這樣在時間復雜度為 O(1) 內(nèi)就能獲取到前后節(jié)點。

  • - 鏈表結構

3. 壓縮列表

如果在一個鏈表節(jié)點中存儲一個小數(shù)據(jù),比如一個字節(jié)。那么對應的就要保存頭節(jié)點,前后指針等額外的數(shù)據(jù)。

這樣就浪費了空間,同時由于反復申請與釋放也容易導致內(nèi)存碎片化。這樣內(nèi)存的使用效率就太低了。Redis為了節(jié)約內(nèi)存開發(fā)了壓縮列表。

壓縮列表結構

參數(shù)說明:

  • zlbytes:記錄整個壓縮列表占用的內(nèi)存字節(jié)數(shù)。
  • zltail:記錄壓縮列表表尾節(jié)點距離壓縮列表起始地址有多少字節(jié)。
  • zllen:記錄了壓縮列表包含的節(jié)點數(shù)量。
  • entryN:壓縮列表的節(jié)點,節(jié)點長度由節(jié)點保存的內(nèi)容決定。
  • zlend:特殊值0xFF(十進制255),用于標記壓縮列表的末端。

4. 字典

dict結構體是字典中最頂層的結構體,用于指向兩個哈希表,兩個哈希表是為了在擴容時使用

hash擴容:

  • 1 創(chuàng)建ht[1],長度= len(ht[0]) * 2
  • 2 將ht[0]上的數(shù)據(jù)rehash到ht[1]上,即重新計算哈希地址
  • 3 釋放ht[0],將ht[1]設置為ht[0],然后創(chuàng)建新的ht[1]

5. 跳躍表

調(diào)表的結構:

由多層鏈表構成,每層之間部分節(jié)點相連,且每層鏈表的數(shù)據(jù)都是有序的

最底層的鏈表是雙向的,且包含所有元素,可實現(xiàn)類似二分查找,

在調(diào)表中的查找次數(shù)接近層數(shù),時間復雜度為O(logn)

用隨機化來決定哪些節(jié)點需要上浮

跳表中的查找:

類似二分查找,從最頂層開始查找,大數(shù)向右查找,小數(shù)向左查找

如查找17,查找路徑為 13 -> 46 -> 22 -> 17

因為17>13(L3),就在L3中往后走,發(fā)現(xiàn)17<46(L3),

就通過13(L3)到達了13(L2),然后往后走發(fā)現(xiàn)17<22(L2),

就通過13(L2)往下達到了13(L1),然后往后走就遇到了17

查找35 13 -> 46 -> 22 -> 46 -> 35

查找 54 13 -> 46 -> 54

跳表中的插入:

1 先在最底層鏈表中找到合適的位置,并插入

2 然后用拋硬幣的方式?jīng)Q定它是需要上浮的次數(shù)

假如此時鏈表共3層,需要拋兩次硬幣,來決定它上浮幾次

跳表與平衡樹、哈希表的比較

1 skiplist和各種平衡樹(如AVL、紅黑樹等)的元素是有序排列的,而哈希表不是有序的。

因此,在哈希表上只能做單個key的查找,不適宜做范圍查找。所謂范圍查找,指的是查找那些大小在指定的兩個值之間的所有節(jié)點。

2 在做范圍查找的時候,平衡樹比skiplist操作要復雜。

在平衡樹上,我們找到指定范圍的小值之后,還需要以中序遍歷的順序繼續(xù)尋找其它不超過大值的節(jié)點。

如果不對平衡樹進行一定的改造,這里的中序遍歷并不容易實現(xiàn)。

而在skiplist上進行范圍查找就非常簡單,只需要在找到小值之后,對第1層鏈表進行若干步的遍歷就可以實現(xiàn)。

3 平衡樹的插入和刪除操作可能引發(fā)子樹的調(diào)整,邏輯復雜,

而skiplist的插入和刪除只需要修改相鄰節(jié)點的指針,操作簡單又快速。

4 從內(nèi)存占用上來說,skiplist比平衡樹更靈活一些。

一般來說,平衡樹每個節(jié)點包含2個指針(分別指向左右子樹),而skiplist每個節(jié)點包含的指針數(shù)目平均為1/(1-p),具體取決于參數(shù)p的大小。如果像Redis里的實現(xiàn)一樣,取p=1/4,那么平均每個節(jié)點包含1.33個指針,比平衡樹更有優(yōu)勢。

5 查找單個key,skiplist和平衡樹的時間復雜度都為O(log n),大體相當;

而哈希表在保持較低的哈希值沖突概率的前提下,查找時間復雜度接近O(1),性能更高一些。

所以我們平常使用的各種Map或dictionary結構,大都是基于哈希表實現(xiàn)的。

從算法實現(xiàn)難度上來比較,skiplist比平衡樹要簡單得多。

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

對于每一種數(shù)據(jù)類型來說,底層的支持可能是多種數(shù)據(jù)結構,什么時候使用哪種數(shù)據(jù)結構,這就涉及到了編碼轉(zhuǎn)化的問題。

那我們就來看看,不同的數(shù)據(jù)類型是如何進行編碼轉(zhuǎn)化的:

  • String:存儲數(shù)字的話,采用int類型的編碼,如果是非數(shù)字的話,采用 raw 編碼;
  • List:字符串長度及元素個數(shù)小于一定范圍使用 ziplist 編碼,任意條件不滿足,則轉(zhuǎn)化為 linkedlist 編碼;
  • Hash:hash 對象保存的鍵值對內(nèi)的鍵和值字符串長度小于一定值及鍵值對;
  • Set:保存元素為整數(shù)及元素個數(shù)小于一定范圍使用 intset 編碼,任意條件不滿足,則使用 hashtable 編碼;
  • Zset:zset 對象中保存的元素個數(shù)小于及成員長度小于一定值使用 ziplist 編碼,任意條件不滿足,則使用 skiplist 編碼。

五、合適的線程模型

1. I/O多路復用模型

2. 避免上下文切換

3. 單線程模型

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Redis調(diào)用Lua腳本及使用場景快速掌握

    Redis調(diào)用Lua腳本及使用場景快速掌握

    Redis?是一種非常流行的內(nèi)存數(shù)據(jù)庫,常用于數(shù)據(jù)緩存與高頻數(shù)據(jù)存儲。大多數(shù)開發(fā)人員可能聽說過redis可以運行?Lua?腳本,但是可能不知道redis在什么情況下需要使用到Lua腳本
    2022-03-03
  • 基于Redis實現(xiàn)基本搶紅包算法詳解

    基于Redis實現(xiàn)基本搶紅包算法詳解

    [key, value]的緩存數(shù)據(jù)庫, Redis官方性能描述非常高, 所以面對高并發(fā)場景, 使用Redis來克服高并發(fā)壓力是一個不錯的手段, 本文主要基于Redis來實現(xiàn)基本的搶紅包系統(tǒng)設計,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Redis的五種基本類型和業(yè)務場景和使用方式

    Redis的五種基本類型和業(yè)務場景和使用方式

    Redis是一種高性能的鍵值存儲數(shù)據(jù)庫,支持多種數(shù)據(jù)結構如字符串、列表、集合、哈希表和有序集合等,它提供豐富的API和持久化功能,適用于緩存、消息隊列、排行榜等多種場景,Redis能夠?qū)崿F(xiàn)高速讀寫操作,尤其適合需要快速響應的應用
    2024-10-10
  • redis使用跳躍表而不是樹的原因解析

    redis使用跳躍表而不是樹的原因解析

    Redis中支持五種數(shù)據(jù)類型中有序集合Sorted Set的底層數(shù)據(jù)結構使用的跳躍表,為何不使用其他的如平衡二叉樹、b+樹等數(shù)據(jù)結構呢?這篇文章主要介紹了redis使用跳躍表而不是樹的原因解析,需要的朋友可以參考下
    2024-02-02
  • redis開啟和禁用登陸密碼校驗的方法

    redis開啟和禁用登陸密碼校驗的方法

    今天小編就為大家分享一篇redis開啟和禁用登陸密碼校驗的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Redis模仿發(fā)送手機驗證碼功能

    Redis模仿發(fā)送手機驗證碼功能

    這篇文章主要介紹了Redis模仿手機驗證碼發(fā)送功能,通過示例代碼給大家講解通過用戶輸入手機號以及驗證碼進行校驗,代碼簡單易懂,需要的朋友可以參考下
    2021-09-09
  • 通過實例解析布隆過濾器工作原理及實例

    通過實例解析布隆過濾器工作原理及實例

    這篇文章主要介紹了通過實例解析布隆過濾器工作原理及實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • 關于Redis持久化的深入探究

    關于Redis持久化的深入探究

    Redis持久化是將內(nèi)存中的數(shù)據(jù)保存到磁盤,以防止數(shù)據(jù)丟失。Redis提供了兩種持久化方式:RDB和AOF,本文將給大家詳解介紹Redis持久化,感興趣的同學可以跟著小編一起來學習
    2023-05-05
  • 阿里云服務器安裝配置redis的方法并且加入到開機啟動(推薦)

    阿里云服務器安裝配置redis的方法并且加入到開機啟動(推薦)

    這篇文章主要介紹了阿里云服務器安裝配置redis并且加入到開機啟動,需要的朋友可以參考下
    2017-12-12
  • 一篇文章讓你明白Redis主從同步

    一篇文章讓你明白Redis主從同步

    今天小編就為大家分享一篇關于一篇文章讓你明白Redis主從同步,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02

最新評論