首頁 > 資料庫 > Redis > 主體

Redis資料結構類型實例程式碼分析

WBOY
發布: 2023-06-01 14:16:13
轉載
898 人瀏覽過

intset

當set集合儲存的是整數時,encoding為intset型別(小整數集合)

typedef struct intset {
    int32 encoding;
    int32 length;
    int contents[];
}
登入後複製
encoding
欄位

#描述說明

決定整數位寬是16位元、32位元還是64位元

枚舉表示

length元素個數contents#intset依照從小到大的順序儲存元素。儲存元素時,根據整數大小決定是否要將encoding升級,找到要插入元素的位置,如果不是最後一位,會將所在位置之後的元素後移一位,最後插入元素。如果插入的元素不為整數,則儲存形式將變成hash結構。 ziplist如果在設定檔中滿足下列條件,即hash和zset的編碼類型會為ziplist(壓縮清單)。 zlbytes# ziplist所佔位元組數zltail_offset最後一個元素距離壓縮清單起始位置的偏移量用於快速定位到最後一個節點,然後倒數遍歷zllength
整數數組,儲存元素值
hash-max-ziplist-entries 512 # 当hash元素个数小于512时
hash-max-ziplist-value 64 # 当hash键或值长度小于64时
zset-max-ziplist-entries 128 # 当zset元素个数小于128时
zset-max-ziplist-value 64 # 当zset值小于64时
登入後複製
typedef struct ziplist {
    int32 zlbytes;
    int32 zltail_offset;
    int16 zllength;
    T[] entries;
    int8 zlend;
}
typedef struct entry {
    int<var> prevlen;
    int<var> encoding;
    byte[] content;
}
登入後複製
欄位描述#說明

元素個數壓縮元素#zlend##」標誌壓縮清單的結束##說明prevlen
entries
恆為FF
#欄位描述
前一個entry的位元組長度######第一個entry恆為0,位元組長度動態變化,當字串長度小於254時,用一個字節,否則用五個字節############encoding#######編碼類型######編碼類型根據元素內容動態變化,極為複雜,本篇不作詳細描述,具體可搜尋ziplist編碼類型############content######元素內容,可選#################### ########

下图是一个ziplist的demo

Redis資料結構類型實例程式碼分析

  • 第1-4字节,zlbytes为25,说明该压缩列表共占用25个字节

  • 第5-8字节,zltail_offset为22,说明最后一个元素从22开始

  • 第9-10字节,zllength为3,说明共有3个元素

  • 第11-16字节,第一个entry: 其中prevlen=0,因为它前面没有数据项;encoding=4,表示后面4byte按照字符串存储,数据的值为name

  • 第17-21字节,第二个entry: 其中prevlen=6,表示前一个entry共占用6byte;encoding=3,表示后面3byte按照字符串存储,数据的值为why

  • 第22-24字节,第三个entry: 其中prevlen=5,表示前一个entry共占用5byte;encoding=0xFE,表示后面1byte存储整数,数据的值为14

  • 第25字节,zlend为FF,标志压缩列表的结束

当用ziplist存储hash结构时,将key与value分别当作一个entry存储。

可见压缩列表存储非常的紧凑,当某一个entry长度变为254时,下一个entry的prevlen将从1个字节扩展到5个字节,这就是级联更新

quicklist

quicklist(快速列表)用于存储list集合,它是ziplist与linkedlist的混合体,linkedlist与双向列表结构类似

quicklist内部默认单个ziplist长度为8K,超过这个长度,就会另起一个node,可在配置文件中配置。

# -2表示8k,枚举类型可在配置文件中查看
list-max-ziplist-size -2
登入後複製

quicklist默认的压缩深度为0,也就是不压缩。如果压缩深度为1,那么就是首尾不压缩,如果压缩深度为2,那么就是首2个、尾2个不压缩,可在配置文件中配置。

list-compress-depth 0
登入後複製

skiplist

zset使用dict存储value与score的映射,另一方面还需要按照score提供排序功能,于是就有了skiplist(跳跃列表)

先看skiplist的一个demo

Redis資料結構類型實例程式碼分析

typedef struct zsl {
    zslnode* header;
    zslnode* tail;
    int maxLevel;
}
登入後複製
typedef struct zslnode {
    sds value;
    double score;
    zslforward*[] forwards;
    zslnode* backward;
}
登入後複製
typedef struct zslforward {
    zslnode* item;
    int span;
}
登入後複製
字段描述说明
header指向跳跃列表的头指针value固定为NULL,score固定为0,backward为null
tail指向跳跃列表的尾指针
maxLevel当前跳跃表最大层数最大为64
value用于存储字符串类型的数据
score用于存储分值
backward回退节点图中的←箭头
forwards前进节点图中的→箭头,每一层对应一个
span跨度,存储一个节点跳到下一个节点中间跳过了多少节点如score1指向score5,则span值为4,这是排名的实现原理

最小分值的backward固定null,对于每一个新插入的节点,会调用一个随机算法,来给它分配一个合理的层数

level1的概率为1-0.25=0.75,实际为100%,因为跳跃列表的最小层数为1

level2的概率为0.75*0.25=0.1875level3的概率为0.1875*0.25=0.0468 ......

leveln的概率为(1-0.25)*Math.pow(0.25,n-1)

总结

Redis作为单线程内存服务,在响应、数据结构上作出了很多的优化,值得我们学习

对象类型编码类型
stringint、raw、embstr
listquicklist
hashdict、ziplist
setintset、dict
zsetziplist、skiplist+dict

HyperLogLog

HyperLogLog的原理为伯努利试验,即丢硬币,根据连续出现反面的次数X,推算出一共丢了2的X次方次硬币,当X很大时,推算出来的总数与实际总数误差就很接近了。具体可查询其他文章。

pfadd

element经过hash算法之后是一个64位的固定值

低14位为桶

查找高50位第一个为1的位数,如果大于当前桶的位数,就将其设置为当前桶的位数

假设hash值是 :{此处省略45位}01100 00000000000101

  • 低14位的二进制转为10进制,值为5(regnum),即我们把数据放在第5个桶

  • 高50位第一个1的位置是3,即count值为3

  • registers[5]取出历史值oldcount

  • 如果count > oldcount,则更新 registers[5] = count

  • 如果count <= oldcount,则不做任何处理

HyperLogLog用了16384个桶,每个桶占用6bit,因此说一个HyperLogLog所占用内存是12K。

调和平均数:

假设我的工资为10_000,马云的工资为1_000_000,那我和马云的平均工资为505_000,我肯定是不认同的。。。

如果使用调和平均数,则为2/(1/10_000+1/1_000_000)=19_801

同理,桶位数的平均数为:n/(1/桶1位数+1/桶2位数+...+1/桶n位数)

桶的平均个数为:Math.pow(2,桶位数的平均数)

总数量:const*桶总数n*桶的平均个数,其中constant为不定值,与桶个数有关,假设m为桶个数,取对数

pfcount

p=log2m
switch (p) {
   case 4:
       constant = 0.673 * m * m;
   case 5:
       constant = 0.697 * m * m;
   case 6:
       constant = 0.709 * m * m;
   default:
       constant = (0.7213 / (1 + 1.079 / m)) * m * m;
}
登入後複製

以上是Redis資料結構類型實例程式碼分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!