Redisobject 對(duì)象
對(duì)象分為鍵對(duì)象和值對(duì)象
鍵對(duì)象一般是string類型
值對(duì)象可以是string,list,set,zset,hash
q:redisobj的結(jié)構(gòu)
typedef struct redisObject {
//類型
unsigned type:4;
//編碼
unsigned encoding:4;
//指向底層實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)的指針
void *ptr;
//引用計(jì)數(shù),垃圾回收的時(shí)候使用
int refcount;
//最近被使用的時(shí)間,內(nèi)存淘汰的時(shí)候用
unsigned lru;
} robj;
q:數(shù)據(jù)類型,編碼和數(shù)據(jù)結(jié)構(gòu)之間的對(duì)應(yīng) 關(guān)系?
Redis對(duì)象和數(shù)據(jù)結(jié)構(gòu)的關(guān)系
鍵總是一個(gè)字符串對(duì)象
而值可以是五種中的一種
type 命令 得到的結(jié)果就是值的類型
可以用object encoding命令查看編碼
list數(shù)據(jù)類型的編碼由linkedlist和ziplist編碼合并成了quicklist編碼
q: 通用數(shù)據(jù)類型命令
keys * //查看當(dāng)前庫所有key (匹配:keys *1)
exists key //判斷某個(gè)key是否存在,如果鍵存在則返回1,不存在則返回0:
type key //查看你的key是什么類型
del key //刪除指定的key數(shù)據(jù),del是一個(gè)通用命令,無論值是什么數(shù)據(jù)結(jié)構(gòu)類型,del命令都可以將其 刪除,返回結(jié)果為成功刪除鍵的個(gè)數(shù),假設(shè)刪除一個(gè)不存在的鍵,就會(huì)返回 0
unlink key //根據(jù)value選擇非阻塞刪除,僅將keys從keyspace元數(shù)據(jù)中刪除,真正的刪除會(huì)在后續(xù)異步操作。
expire key 10 //10秒鐘:為給定的key設(shè)置過期時(shí)間
ttl key //查看還有多少秒過期,-1表示永不過期,-2表示已過期
select number //命令切換數(shù)據(jù)庫
dbsize //查看當(dāng)前數(shù)據(jù)庫的key的數(shù)量
flushdb //清空當(dāng)前庫
flushall //通殺全部庫
命令在執(zhí)行前都會(huì)判斷 參數(shù)是否是自己可以接收,否則會(huì)返回錯(cuò)誤
數(shù)據(jù)類型
string 字符串
q: 特點(diǎn)
其value是字符串,不過根據(jù)字符串的格式不同,又可以分為3類:
-
string:普通字符串
-
int:整數(shù)類型,可以做自增、自減操作
-
float:浮點(diǎn)類型,可以做自增、自減操作
q: 適用場(chǎng)景?
String 的常見應(yīng)用場(chǎng)景如下:
- 常規(guī)數(shù)據(jù)(比如 session、token、序列化后的對(duì)象、圖片的路徑)的緩存;
- 計(jì)數(shù)比如用戶單位時(shí)間的請(qǐng)求數(shù)(簡單限流可以用到)、頁面單位時(shí)間的訪問數(shù);
- 分布式鎖(利用
SETNX key value
命令可以實(shí)現(xiàn)一個(gè)最簡易的分布式鎖);
q:常用命令?
set <key> <value> //添加鍵值對(duì)
*NX:當(dāng)數(shù)據(jù)庫中key不存在時(shí),可以將key-value添加數(shù)據(jù)庫
*XX:當(dāng)數(shù)據(jù)庫中key存在時(shí),可以將key-value添加數(shù)據(jù)庫,與NX參數(shù)互斥
*EX:key的超時(shí)秒數(shù)
*PX:key的超時(shí)毫秒數(shù),與EX互斥
get <key> //查詢對(duì)應(yīng)鍵值
append <key> <value> //將給定的<value> 追加到原值的末尾,返回長度
strlen <key> //獲得值的長度
setnx <key> <value> //只有在 key 不存在時(shí) 設(shè)置 key 的值
incr <key> //將 key 中儲(chǔ)存的數(shù)字值增1 只能對(duì)數(shù)字值操作,如果為空,新增值為1
decr <key> //將 key 中儲(chǔ)存的數(shù)字值減1 只能對(duì)數(shù)字值操作,如果為空,新增值為-1
incrby / decrby <key> <步長> //將 key 中儲(chǔ)存的數(shù)字值增減。自定義步長。
mset <key1><value1><key2><value2> ..... //同時(shí)設(shè)置一個(gè)或多個(gè) key-value對(duì)
mget <key1><key2><key3> ..... //同時(shí)獲取一個(gè)或多個(gè) value
msetnx <key1><value1><key2><value2> ..... //同時(shí)設(shè)置一個(gè)或多個(gè) key-value 對(duì),當(dāng)且僅當(dāng)所有給定 key 都不存在。 原子性,有一個(gè)失敗則都失敗
getrange <key><起始位置><結(jié)束位置> //得值的范圍,類似java中的substring,前包,后包
setrange <key><起始位置><value> //用 <value> 覆寫<key>所儲(chǔ)存的字符串值,從<起始位置>開始(索引從0開始)。
setex <key><過期時(shí)間><value> //設(shè)置鍵值的同時(shí),設(shè)置過期時(shí)間,單位秒。
getset <key><value> //以新?lián)Q舊,設(shè)置了新值同時(shí)獲得舊值。
q:底層編碼方式和數(shù)據(jù)結(jié)構(gòu)?
- 當(dāng)存儲(chǔ)的是long 數(shù)字的時(shí)候,使用int編碼,prt直接存儲(chǔ)數(shù)字
不包括浮點(diǎn)數(shù)
- 當(dāng)存儲(chǔ)的字符串小于44個(gè)字節(jié)的時(shí)候,使用embstr編碼,字符串和redisobject存儲(chǔ)在一起
- 當(dāng)存儲(chǔ)的字符串大于44個(gè)字節(jié)的時(shí)候,使用raw編碼,prt存儲(chǔ)的是sds的地址指針
set 集合
q: 特點(diǎn)
-
無序
-
元素不可重復(fù)
-
查找快
-
支持交集、并集、差集等功能
q: 適用場(chǎng)景?
應(yīng)用場(chǎng)景:
- 需要存放的數(shù)據(jù)不能重復(fù)的場(chǎng)景
- 不可重復(fù)下單
- 點(diǎn)贊
- 需要獲取多個(gè)數(shù)據(jù)源交集、并集和差集的場(chǎng)景
- 共同好友(交集)、共同粉絲(交集)、共同關(guān)注(交集)、好友推薦(差集)、音樂推薦(差集)、訂閱號(hào)推薦(差集+交集) 等場(chǎng)景。
- 需要隨機(jī)獲取數(shù)據(jù)源中的元素的場(chǎng)景
- 抽獎(jiǎng)系統(tǒng)、隨機(jī)點(diǎn)名等場(chǎng)景。
- 相關(guān)命令:
SPOP
(隨機(jī)獲取集合中的元素并移除,適合不允許重復(fù)中獎(jiǎng)的場(chǎng)景)、SRANDMEMBER
(隨機(jī)獲取集合中的元素,適合允許重復(fù)中獎(jiǎng)的場(chǎng)景)。
q:常用命令?
sadd <key><value1><value2> ..... //將一個(gè)或多個(gè) member 元素加入到集合 key 中,已經(jīng)存在的 member 元素將被忽略
smembers <key> //取出該集合的所有值。
sismember <key><value> //判斷集合<key>是否為含有該<value>值,有1,沒有0
scard<key> //返回該集合的元素個(gè)數(shù)。
srem <key><value1><value2> .... //刪除集合中的某個(gè)元素。
spop <key> //隨機(jī)從該集合中吐出一個(gè)值。
srandmember <key><n> //隨機(jī)從該集合中取出n個(gè)值。不會(huì)從集合中刪除 。
smove <source><destination>value //把集合中一個(gè)值從一個(gè)集合移動(dòng)到另一個(gè)集合
sinter <key1><key2> //返回兩個(gè)集合的交集元素。
sunion <key1><key2> //返回兩個(gè)集合的并集元素。
sdiff <key1><key2> //返回兩個(gè)集合的差集元素(key1中的,不包含key2中的)
q:底層編碼方式和數(shù)據(jù)結(jié)構(gòu)?
- 當(dāng)存儲(chǔ)的所有數(shù)據(jù)都是整數(shù),元素?cái)?shù)量不超過set-max-intset-entries時(shí),Set會(huì)采用IntSet編碼,以節(jié)省內(nèi)存,底層數(shù)據(jù)結(jié)構(gòu)是intset
- 當(dāng)存儲(chǔ)的所有數(shù)據(jù)不都是整數(shù),或元素?cái)?shù)量超過set-max-intset-entries時(shí),set采用hashtable編碼,底層是Dict中的key用來存儲(chǔ)元素,value統(tǒng)一為null。
hash 哈希
q: 特點(diǎn)
hash也叫散列, 是一個(gè)鍵值對(duì)集合。
q: 適用場(chǎng)景?
hash特別適合用于存儲(chǔ)對(duì)象。
q:常用命令?
hset <key><field><value> <field2><value2> //給<key>集合中的 <field>鍵賦值<value>
hget <key1><field> //從<key1>集合<field>取出 value
hmset <key1><field1><value1><field2><value2>... //批量設(shè)置hash的值,hmset被棄用,可以用hset做到
hexists<key1><field> //查看哈希表 key 中,給定域 field 是否存在。
hkeys <key> //列出該hash集合的所有field
hvals <key> //列出該hash集合的所有value
hincrby <key><field><increment> //為哈希表 key 中的域 field 的值加上增量 1 -1
hsetnx <key><field><value> //將哈希表 key 中的域 field 的值設(shè)置為 value ,當(dāng)且僅當(dāng)域 field 不存在 .
q:底層編碼方式和數(shù)據(jù)結(jié)構(gòu)?
-
Hash結(jié)構(gòu)默認(rèn)采用ZipList編碼,用以節(jié)省內(nèi)存。 ZipList中相鄰的兩個(gè)entry 分別保存field和value;底層數(shù)據(jù)結(jié)構(gòu)式ziplist
-
當(dāng)數(shù)據(jù)量較大時(shí),Hash結(jié)構(gòu)會(huì)轉(zhuǎn)為hashtable編碼,底層數(shù)據(jù)結(jié)構(gòu)是Dict,觸發(fā)條件有兩個(gè):
- ZipList中的元素?cái)?shù)量超過了hash-max-ziplist-entries(默認(rèn)512)
- ZipList中的任意entry大小超過了hash-max-ziplist-value(默認(rèn)64字節(jié))
節(jié)點(diǎn)過多,或單個(gè)節(jié)點(diǎn)過大
zset/sorted set 有序集合
q: 特點(diǎn)
- 無重復(fù)
- 有序
每個(gè)成員都關(guān)聯(lián)了一個(gè)評(píng)分(score),這個(gè)評(píng)分(score)被用來按照從最低分到最高分的方式排序集合中的成員。
集合的成員是唯一的,但是評(píng)分可以是重復(fù)了 。
q: 適用場(chǎng)景?
適合范圍或者排序的應(yīng)用場(chǎng)景:
- 排行榜
q:常用命令?
zadd <key><score1><value1><score2><value2>… //將一個(gè)或多個(gè) member 元素及其 score 值加入到有序集 key 當(dāng)中。
zrange <key><start><stop> [WITHSCORES] //返回有序集 key 中,下標(biāo)在<start><stop>之間的元素,帶WITHSCORES,可以讓分?jǐn)?shù)一起和值返回到結(jié)果集。
zrangebyscore key minmax [withscores] [limit offset count] //返回有序集 key 中,所有 score 值介于 min 和 max 之間(包括等于 min 或 max )的成員。有序集成員按 score 值遞增(從小到大)次序排列。
zrevrangebyscore key maxmin [withscores] [limit offset count] //同上,改為從大到小排列。
zincrby <key><increment><value> // 為元素的score加上增量
zrem <key><value> //刪除該集合下,指定值的元素
zcount <key><min><max> //統(tǒng)計(jì)該集合,分?jǐn)?shù)區(qū)間內(nèi)的元素個(gè)數(shù)
zrank <key><value> //返回該值在集合中的排名,從0開始。
q:底層編碼方式和數(shù)據(jù)結(jié)構(gòu)?
- 當(dāng)滿足下面條件時(shí),采用ziplist編碼,底層數(shù)據(jù)結(jié)構(gòu)是ziplist
- 元素?cái)?shù)量小于zset_max_ziplist_entries,默認(rèn)值128
- 每個(gè)元素都小于zset_max_ziplist_value字節(jié),默認(rèn)值64
ziplist本身沒有排序功能,而且沒有鍵值對(duì)的概念,因此需要有zset通過編碼實(shí)現(xiàn):
- ZipList是連續(xù)內(nèi)存,因此score和element是緊挨在一起的兩個(gè)entry, element在前,score在后
- score越小越接近隊(duì)首,score越大越接近隊(duì)尾,按照score值升序排列
- 否則采用zset編碼,底層是zset數(shù)據(jù)結(jié)構(gòu),zset的數(shù)據(jù)結(jié)構(gòu)又指向skiplist和dict
- SkipList:可以排序,并且可以同時(shí)存儲(chǔ)score和ele值(member)
- Dict:可以鍵值存儲(chǔ),并且可以根據(jù)key找value,實(shí)現(xiàn)O(1)的查找
二者實(shí)際上共用對(duì)象,不會(huì)造成內(nèi)存的浪費(fèi)
list 列表
q: 特點(diǎn)
雙向鏈表結(jié)構(gòu)。既可以支持正向檢索和也可以支持反向檢索。
特征也與LinkedList類似:
- 單鍵多值
- 有序
- 元素可以重復(fù)
- 插入和刪除快
- 查詢速度一般
q: 適用場(chǎng)景?
應(yīng)用場(chǎng)景:
- 常用來存儲(chǔ)一個(gè)有序數(shù)據(jù),例如:朋友圈點(diǎn)贊列表,評(píng)論列表等。
- 可以用來做消息隊(duì)列,只是功能過于簡單且存在很多缺陷,不建議這樣做。
q:常用命令?
lpush/rpush <key><value1><value2><value3> //.... 從左邊/右邊插入一個(gè)或多個(gè)值。lpush是頭插法
lpop/rpop <key> //從左邊/右邊吐出一個(gè)值。值在鍵在,值光鍵亡。
rpoplpush <key1><key2>從<key1> //列表右邊吐出一個(gè)值,插到<key2>列表左邊。
lrange <key><start><stop> //按照索引下標(biāo)獲得元素(從左到右)
lrange <key> 0 -1 //0左邊第一個(gè),-1右邊第一個(gè),(0 -1表示獲取所有)
lindex <key><index> //按照索引下標(biāo)獲得元素(從左到右)
llen <key> //獲得列表長度
linsert <key> before/after <value><newvalue> //在<value>的前面、后面插入<newvalue>插入值
lrem <key><n><value> //從左邊刪除n個(gè)value(從左到右)
lset<key><index><value> //將列表key下標(biāo)為index的值替換成value
q:底層編碼方式和數(shù)據(jù)結(jié)構(gòu)?
- List的編碼方式是quicklist,底層數(shù)據(jù)結(jié)構(gòu)為快速鏈表quickList,quicklist的節(jié)點(diǎn)又指向了ziplist
Redis 3.2 之前,List 底層實(shí)現(xiàn)是 LinkedList 或者 ZipList。 Redis 3.2 之后,引入了 LinkedList 和 ZipList 的結(jié)合 QuickList,List 的底層實(shí)現(xiàn)變?yōu)?QuickList。
文章來源地址http://www.zghlxwxcb.cn/news/detail-652164.html
首先在列表元素較少的情況下會(huì)使用一塊連續(xù)的內(nèi)存存儲(chǔ),這個(gè)結(jié)構(gòu)是ziplist,也即是壓縮列表。(它將所有的元素緊挨著一起存儲(chǔ),分配的是一塊連續(xù)的內(nèi)存。)
當(dāng)數(shù)據(jù)量比較多的時(shí)候才會(huì)改成quicklist。
因?yàn)槠胀ǖ逆湵硇枰母郊又羔樋臻g太大,會(huì)比較浪費(fèi)空間。比如這個(gè)列表里存的只是int類型的數(shù)據(jù),結(jié)構(gòu)上還需要兩個(gè)額外的指針prev和next。
Redis將鏈表和ziplist結(jié)合起來組成了quicklist。也就是將多個(gè)ziplist使用雙向指針串起來使用。這樣既滿足了快速的插入刪除性能,又不會(huì)出現(xiàn)太大的空間冗余。
數(shù)據(jù)結(jié)構(gòu)
sds 簡單動(dòng)態(tài)字符串
q:sds的結(jié)構(gòu)
sds的結(jié)構(gòu)
struct sdshdr {
//記錄buf數(shù)組中已使用字節(jié)的數(shù)量
//等于SDS所保存字符串的長度
int len;
//記錄buf數(shù)組中未使用字節(jié)的數(shù)量
int free;
//字節(jié)數(shù)組,用于保存字符串
char buf[];
};
q: sds和c字符串的區(qū)別
相同點(diǎn):
- 都是用char數(shù)組來記錄字符,最后都有一個(gè)
\0
來代表字符串結(jié)束
sds最后也用
\0
代表結(jié)束,是為了重用c語言字符串的一些函數(shù),例如printf打印,而不用重寫所有的函數(shù)
不同點(diǎn)
肯定是c語言字符串存在一定的缺陷,redis才會(huì)重寫,那么這些既是redis和c語言字符串的不同點(diǎn),也是redis sds的優(yōu)點(diǎn)
- 常數(shù)級(jí)別獲取字符串長度,sds獲取字符串長度的時(shí)間復(fù)雜度是O(1),c語言是O(n),通過len的冗余存儲(chǔ)來實(shí)現(xiàn)
- 杜絕緩沖區(qū)溢出,字符串在拼接之前可以做內(nèi)存檢查,確??臻g充足,否則進(jìn)行擴(kuò)充;不會(huì)像c語言一樣造成內(nèi)存溢出
- 減少修改字符串時(shí)帶來的內(nèi)存重分配次數(shù),預(yù)分配空間free,來減少內(nèi)存重分配的次數(shù),可以提升性能
-
二進(jìn)制安全,c語言字符串通過
\0
空字符來標(biāo)志字符串結(jié)束,因此不能包含空字符;而sds通過len來表示字符串結(jié)束,可以包含空字符,可以存儲(chǔ)圖片等二進(jìn)制信息,因此是二進(jìn)制安全的
q: 容量擴(kuò)充機(jī)制?
如圖中所示,內(nèi)部為當(dāng)前字符串實(shí)際分配的空間capacity一般要高于實(shí)際字符串長度len。
- 當(dāng)字符串長度小于1M時(shí),擴(kuò)容都是加倍現(xiàn)有的空間
- 如果超過1M,擴(kuò)容時(shí)一次只會(huì)多擴(kuò)1M的空間。需要注意的是字符串最大長度為512M。
intset 正數(shù)集合
q: intset的結(jié)構(gòu)
typedef struct intset {
//編碼方式
uint32_t encoding;
//集合包含的元素?cái)?shù)量
uint32_t length;
//保存元素的數(shù)組
int8_t contents[];
} intset;
- 數(shù)組升序排列
- 沒有重復(fù)
q: 如何升級(jí)?
當(dāng)新元素很大的時(shí)候,集合要升級(jí)成更大的編碼方式
升級(jí)整數(shù)集合并添加新元素共分為三步進(jìn)行:
1)根據(jù)新元素的類型,擴(kuò)展整數(shù)集合底層數(shù)組的空間大小,并為新元素分配空間。
2)將底層數(shù)組現(xiàn)有的所有元素都轉(zhuǎn)換成與新元素相同的類型,并將類型轉(zhuǎn)換后的元素放置到正確的位上,而且在放置元素的過程中,需要繼續(xù)維持底層數(shù)組的有序性質(zhì)不變。
3)將新元素添加到底層數(shù)組里面。
?升級(jí)操作為整數(shù)集合帶來了操作上的靈活性,并且盡可能地節(jié)約了內(nèi)存。
?整數(shù)集合只支持升級(jí)操作,不支持降級(jí)操作。
dictht 哈希表
typedef struct dictht {
//哈希表數(shù)組
dictEntry **table;
//哈希表大小
unsigned long size;
//哈希表大小掩碼,用于計(jì)算索引值
//總是等于size-1
unsigned long sizemask;
//該哈希表已有節(jié)點(diǎn)的數(shù)量
unsigned long used;
} dictht;
哈希表結(jié)點(diǎn)
typedef struct dictEntry {
//鍵
void *key;
//值
union{
void *val;
uint64_tu64;
int64_ts64;
} v;
//指向下個(gè)哈希表節(jié)點(diǎn),形成鏈表
struct dictEntry *next;
} dictEntry;
q:如何解決哈希沖突?
用拉鏈法的頭插法解決哈希沖突
dict 字典
typedef struct dict {
//類型特定函數(shù)
dictType *type;
//私有數(shù)據(jù)
void *privdata;
//哈希表
dictht ht[2];
// rehash索引
//當(dāng)rehash不在進(jìn)行時(shí),值為-1
in trehashidx; /* rehashing not in progress if rehashidx == -1 */
} dict;
ht有兩個(gè),一般只使用第一個(gè),第二個(gè)哈希表只在rehash的時(shí)候用
插入數(shù)據(jù)的時(shí)候,先計(jì)算哈希值,再計(jì)算索引值,再插入到指定位置
q : 如何rehash?
隨著操作的不斷執(zhí)行,哈希表保存的鍵值對(duì)會(huì)逐漸地增多或者減少,為了讓哈希表的負(fù)載因子(load factor)維持在一個(gè)合理的范圍之內(nèi),當(dāng)哈希表保存的鍵值對(duì)數(shù)量太多或者太少時(shí),程序需要對(duì)哈希表的大小進(jìn)行相應(yīng)的擴(kuò)展或者收縮。
擴(kuò)展和收縮哈希表的工作可以通過執(zhí)行rehash(重新散列)操作來完成,Redis對(duì)字典的哈希表執(zhí)行rehash的步驟如下:
1)為字典的ht[1]哈希表分配空間,這個(gè)哈希表的空間大小取決于要執(zhí)行的操作,以及ht[0]當(dāng)前包含的鍵值對(duì)數(shù)量(也即是ht[0].used屬性的值):
?如果執(zhí)行的是擴(kuò)展操作,那么ht[1]的大小為第一個(gè)大于等于ht[0].used*2的2 n(2的n次方冪);
?如果執(zhí)行的是收縮操作,那么ht[1]的大小為第一個(gè)大于等于ht[0].used的2 n。
2)將保存在ht[0]中的所有鍵值對(duì)rehash到ht[1]上面:rehash指的是重新計(jì)算鍵的哈希值和索引值,然后將鍵值對(duì)放置到ht[1]哈希表的指定位置上。
3)當(dāng)ht[0]包含的所有鍵值對(duì)都遷移到了ht[1]之后(ht[0]變?yōu)榭毡恚尫舎t[0],將ht[1]設(shè)置為ht[0],并在ht[1]新創(chuàng)建一個(gè)空白哈希表,為下一次rehash做準(zhǔn)備。
為ht[1]分配空間,復(fù)制ht[0]的數(shù)據(jù)到ht[1],釋放ht[0],把ht[1]設(shè)為ht[0],ht[1]創(chuàng)建一個(gè)空哈希表
q:什么時(shí)候rehash
哈希表的擴(kuò)展與收縮
哈希表的擴(kuò)展與收縮當(dāng)以下條件中的任意一個(gè)被滿足時(shí),程序會(huì)自動(dòng)開始對(duì)哈希表執(zhí)行擴(kuò)展操作:
1)服務(wù)器目前沒有在執(zhí)行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表的負(fù)載因子大于等于1。
2)服務(wù)器目前正在執(zhí)行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表的負(fù)載因子大于等于5。
為什么rehash是漸進(jìn)式?
如果ht[0]的數(shù)據(jù)非常多,那么把數(shù)據(jù)全部轉(zhuǎn)移到ht[1]將會(huì)非常耗費(fèi)時(shí)間,因此這個(gè)過程是分多次,漸進(jìn)式完成的
rehashidx記錄了正在轉(zhuǎn)移的索引下標(biāo),當(dāng)轉(zhuǎn)移完成,會(huì)置為-1
因?yàn)樵谶M(jìn)行漸進(jìn)式rehash的過程中,字典會(huì)同時(shí)使用ht[0]和ht[1]兩個(gè)哈希表,所以在漸進(jìn)式rehash進(jìn)行期間,字典的刪除(delete)、查找(find)、更新(update)等操作會(huì)在兩個(gè)哈希表上進(jìn)行。例如,要在字典里面查找一個(gè)鍵的話,程序會(huì)先在ht[0]里面進(jìn)行查找,如果沒找到的話,就會(huì)繼續(xù)到ht[1]里面進(jìn)行查找,諸如此類。
另外,在漸進(jìn)式rehash執(zhí)行期間,新添加到字典的鍵值對(duì)一律會(huì)被保存到ht[1]里面,而ht[0]則不再進(jìn)行任何添加操作,這一措施保證了ht[0]包含的鍵值對(duì)數(shù)量會(huì)只減不增,并隨著rehash操作的執(zhí)行而最終變成空表。
ziplist 壓縮列表
q: ziplist的結(jié)構(gòu)?
每個(gè)壓縮列表節(jié)點(diǎn)可以保存一個(gè)字節(jié)數(shù)組或者一個(gè)整數(shù)值
q: ziplist過大的時(shí)候有什么缺點(diǎn)?
當(dāng)ziplist變得很?的時(shí)候,它有如下幾個(gè)缺點(diǎn):
- 每次插?或修改引發(fā)的realloc操作會(huì)有更?的概率造成內(nèi)存拷貝,從而降低性能。
- ?旦發(fā)生內(nèi)存拷貝,內(nèi)存拷貝的成本也相應(yīng)增加,因?yàn)橐截惛?的?塊數(shù)據(jù)。
- 當(dāng)ziplist數(shù)據(jù)項(xiàng)過多的時(shí)候,在它上?查找指定的數(shù)據(jù)項(xiàng)就會(huì)性能變得很低,因?yàn)閦iplist上的查找需要進(jìn)行遍歷。
skiplist 跳表
skiplist是多層級(jí)不同跨度的鏈表
q: skiplist的結(jié)構(gòu)?
zsikpList
typedef struct zskiplist {
//表頭節(jié)點(diǎn)和表尾節(jié)點(diǎn)
structz skiplistNode *header, *tail;
//表中節(jié)點(diǎn)的數(shù)量
unsigned long length;
//表中層數(shù)最大的節(jié)點(diǎn)的層數(shù)
int level;
} zskiplist;
zskipListNode
typedef struct zskiplistNode {
//層
struct zskiplistLevel {
//前進(jìn)指針
struct zskiplistNode *forward;
//跨度
unsigned int span;
} level[];
//后退指針
struct zskiplistNode *backward;
//分值
double score;
//成員對(duì)象
robj *obj;
} zskiplistNode;
每個(gè)結(jié)點(diǎn)的成員對(duì)象是唯一的,但是分值可以相同,分值相同就按照成員對(duì)象由小到大排序,整個(gè)鏈表都是按照分值由小到大排序
q: skiplist如何遍歷?
遍歷:
首先遍歷高層級(jí)跨度大的指針,如果過大,就遍歷下一層級(jí)
zset
q:zset的結(jié)構(gòu)?
typedef struct zset {
zskiplist *zsl;
dict *dict;
} zset;
- SkipList:可以排序,并且可以同時(shí)存儲(chǔ)score和ele值(member)
- Dict:可以鍵值存儲(chǔ),并且可以根據(jù)key找value,實(shí)現(xiàn)O(1)的查找
二者實(shí)際上共用對(duì)象,不會(huì)造成內(nèi)存的浪費(fèi)
quicklist 快表
q:quicklist的結(jié)構(gòu)
quicklist 實(shí)際上是 zipList 和 linkedList 的混合體,它將 linkedList 按段切分,每一段使用 zipList 來緊湊存儲(chǔ),多個(gè) zipList 之間使用雙向指針串接起來。文章來源:http://www.zghlxwxcb.cn/news/detail-652164.html
typedef struct quicklist {
quicklistNode *head;
quicklistNode *tail;
unsigned long count; /* total count of all entries in all ziplists */
unsigned long len;
} quicklist;
typedef struct quicklistNode {
struct quicklistNode *prev; //上一個(gè)node節(jié)點(diǎn)
struct quicklistNode *next; //下一個(gè)node
unsigned char *zl; //保存的數(shù)據(jù) 壓縮前ziplist 壓縮后壓縮的數(shù)據(jù)
unsigned int sz; /* ziplist size in bytes */
unsigned int count : 16; /* count of items in ziplist */
} quicklistNode;
到了這里,關(guān)于Redis對(duì)象和五種常用數(shù)據(jù)類型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!