首頁  >  文章  >  資料庫  >  Redis資料類型學習之聊聊String原理

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

青灯夜游
青灯夜游轉載
2022-01-29 08:00:382208瀏覽

這篇文章帶大家了解一下Redis資料類型中的String,聊聊String資料類型的儲存原理,希望對大家有幫助!

Redis資料類型學習之聊聊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(單浮點型) 

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

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

##四、不同的編碼類型

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

五、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自訂了一個簡單動態字串的資料結構來儲存字串數。 原始碼實作:多種資料結構,分別表示可以儲存不同長度的字串。

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轉成embstr3、embstr字元超過44字節,轉成raw 
  • 八、SDS資料結構的優點
1、

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

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

int

儲存8個位元組長整形long ,2^63-1Embstr 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'代表判斷結束。 ###二進位資料儲存不安全###,不能儲存圖片,影片等。 ###

十、关于内存预分配特性

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

通过源码分析,扩容策略是字符串在长度小于 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原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除