Redis資料型別學習之聊聊String原理

2022-01-29 10:00:34
本篇文章帶大家瞭解一下Redis資料型別中的String,聊聊String資料型別的儲存原理,希望對大家有所幫助!

Redis是工作中使用比較多的中介軟體,它支援豐富的資料結構,擁有極強的讀寫效能,tps可以達到10w+。

今天這篇文章來分析和總結String型別也是使用最多的一種資料結構之一。本文是基於redis5.0進行分析。【相關推薦:Redis視訊教學

一、基本使用

set key value [EX seconds] [PX milliseconds] [NX|XX]

1、set是語法,key是指定名稱, value是需要儲存的值

2、EX 指定過期的秒時間,PX指定過期的毫秒時間

3、NX:只有key不存在的時候,才設定成功

4、XX:只有key存在的時候,才設定成功

總結:5.0支援set命令指定過期時間和不存在的時候才設定成功,也就是通過一條命令就可以實現分散式鎖加鎖的功能,以前的版本設定key和設定過期時間需要分成兩個命令,原子性保證難度更大。

二、使用場景

1、熱點資料快取,分散式session

2、Setnx 分散式鎖

3、incr 計數器

4、Incr 全域性id

5、Incr 限流

6、bit 操作,點陣圖功能,線上使用者統計 0/1標記

三、支援儲存的資料型別

整型,字元型,float(單浮點型)

四、不同的編碼型別

1.png

2.png

五、String儲存原理

在Redis中,資料儲存在一個RedisObject類中

typedef struct redisObject {    
//這個型別可以是string,也可以是hash,zset等等
unsigned type:4;    
unsigned encoding:4;    
//記錄lru,lfu淘汰演演算法依賴的存取時間和存取頻率    
unsigned lru:LRU_BITS; 
/* LRU time (relative to global lru_clock) or                            * LFU data (least significant 8 bits frequency                            * and most significant 16 bits access time). */
//參照計數器    
int refcount;    
//指向真實資料結構物件    
void *ptr;
} robj;

對於String,Redis自定義了一種簡單動態字串的資料結構來儲存字串數。

原始碼實現:多種資料結構,分別表示可以儲存不同長度的字串。

3.png

len:代表已經使用的長度

alloc:分配的總記憶體大小

flags:代表儲存型別

buf[]:實際的資料

六、三種編碼儲存區別

1、embstr的RedisObject,SDS記憶體在一塊,只要建立時分配一次記憶體,銷燬時釋放一次記憶體,查詢方便

2、raw則RedisObject,SDS記憶體不在一塊,需要建立時分配兩次記憶體,銷燬時釋放兩次記憶體

3、embstr的結構,決定了他需要增加長度時,RedisObject,SDS都需要重新分配記憶體。因此embstr編碼的資料是不能修改的,唯讀的

七、int,embstr編碼什麼時候轉換成raw

1、int型別的資料不再是int型別,轉成raw

2、長度大於2^63-1轉成embstr

3、embstr字元超過44位元組,轉成raw

八、SDS資料結構的優點

1、二進位制安全的 可以儲存圖片 整形,浮點型

2、String 的三種編碼,充分利用記憶體,提高記憶體利用率

  • int 儲存8個位元組長整形 long ,2^63-1
  • Embstr embstr格式的SDS simple Dynamic String 記憶體空間是連續的,唯讀的,只要執行修改就會轉成raw
  • Raw,SDS,儲存大於44個位元組的字串

3、不用擔心記憶體溢位,sds具備自動擴容能力

4、獲取字串長度時間複雜度O(1),儲存了len屬性

5、通過空間預分配惰性空間釋放防止多次分配記憶體

6、判斷是否結束使用len屬性,可以包含'\0',操作字串。

九、為什麼不用c中的字元陣列?

1、需要預先分配記憶體,可能記憶體溢位

2、獲取長度需要遍歷陣列,時間複雜度O(n)

3、字元陣列長度變化,需要記憶體重分配

4、c的字元陣列中,'\0'代表判斷結束。二進位制資料儲存不安全,不能儲存圖片,視訊等。

十、關於記憶體預分配特性

4.png

通過原始碼分析,擴容策略是字串在長度小於 SDS_MAX_PREALLOC 之前,擴容空間採用加倍策略,也就是保留 100% 的冗餘空間。當長度超過 SDS_MAX_PREALLOC 之後,為了避免加倍後的冗餘空間過大而導致浪費,每次擴容只會多分配 SDS_MAX_PREALLOC大小的冗餘空間。

十一、關於惰性空間釋放

惰性空間釋放用於優化 SDS 的字串縮短操作:當 SDS 的 API 需要縮短 SDS 儲存的字串時, 程式並不立即使用記憶體重分配來回收縮短後多出來的位元組, 而是使用 free 屬性將這些位元組的數量記錄起來,並等待將來使用。

//僅僅設定長度,沒有真正清除資料
void sdsclear(sds s) {    
//單純設定長度為0    
sdssetlen(s, 0);    
//第一個字元設定為結束符    
s[0] = '\0';
}

真正的清除空間

sds sdsRemoveFreeSpace(sds s) 
{
struct sdshdr *sh;    
sh = (void*) (s-(sizeof(struct sdshdr)));    
// 進行記憶體重分配,讓 buf 的長度僅僅足夠儲存字串內容 
sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);    
// 空餘空間為 0    
sh->free = 0;    
return sh->buf;
}

以上便是關於string的知識點記錄,string的設計很多地方都非常巧妙,比如不同的結構體儲存不同長度的字串,不同編碼型別儲存不同長度的字串,

空間預分配,空間惰性釋放等,從儲存結構,編碼型別,記憶體分配策略和回收策略,作者都從效能方面做了非常多的考量設計,可想而知這也是redis為什麼效能極高的原因,工作中也要學習這種追求極致效能的優良風格和設計風格。

更多程式設計相關知識,請存取:!!

以上就是Redis資料型別學習之聊聊String原理的詳細內容,更多請關注TW511.COM其它相關文章!