您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    能够是目前最详细的Redis内存模型及运用解读(6)
    时间:2018-08-09 08:10 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    能够是目前最详细的Redis内存模型及运用解读

    4、集合

    (1)概略

    集合(set)与列表相似,都是用来保存多个字符串,但集合与列表有两点不同:集合中的元素是无序的,因此不能经过索引来操作元素;集合中的元素不能有重复。

    一个集合中最多可以存储2^32-1个元素;除了支持常规的增删改查,Redis还支持多个集合取交集、并集、差集。

    (2)外部编码

    集合的外部编码可以是整数集合(intset)或哈希表(hashtable)。

    哈希表前面曾经讲过,这里略过不提;需求留意的是,集合在运用哈希表时,值全部被置为null。

    整数集合的结构定义如下:

    typedef struct intset{ 

        uint32_t encoding; 

        uint32_t length; 

        int8_t contents[]; 

    } intset; 

    其中,encoding代表contents中存储内容的类型,虽然contents(存储集合中的元素)是int8_t类型,但实践上其存储的值是int16_t、int32_t或int64_t,详细的类型便是由encoding决议的;length表示元素个数。

    整数集适宜用于集合一切元素都是整数且集合元素数量较小的时分,与哈希表相比,整数集合的优势在于集中存储,节省空间;同时,虽然关于元素的操作复杂度也由O(n)变为了O(1),但由于集合数量较少,因此操作的时间并没有清楚优势。

    (3)编码转换

    只要同时满足下面两个条件时,集合才会运用整数集合:

    集合中元素数量小于512个;

    集合中一切元素都是整数值。

    假设有一个条件不满足,则运用哈希表;且编码只能够由整数集合转化为哈希表,反方向则不能够。

    下图展现了集合编码转换的特点:

    能够是目前最详细的Redis内存模型及运用解读

    5、有序集合

    (1)概略

    有序集合与集合一样,元素都不能重复;但与集合不同的是,有序集合中的元素是有顺序的。与列表运用索引下标作为排序依据不同,有序集合为每个元素设置一个分数(score)作为排序依据。

    (2)外部编码

    有序集合的外部编码可以是紧缩列表(ziplist)或腾跃表(skiplist)。ziplist在列表和哈希中都有运用,前面曾经讲过,这里略过不提。

    腾跃表是一种有序数据结构,经过在每个节点中维持多个指向其他节点的指针,从而到达快速拜访节点的目的。除了腾跃表,完成有序数据结构的另一种典型完成是平衡树;大少数状况下,腾跃表的效率可以战争衡树媲美,且腾跃表完成比平衡树复杂很多,因此redis中选用腾跃表替代平衡树。

    腾跃表支持平均O(logN)、最坏O(N)的复杂点停止节点查找,并支持顺序操作。Redis的腾跃表完成由zskiplist和zskiplistNode两个结构组成:前者用于保存腾跃表信息(如头结点、尾节点、长度等),后者用于表示腾跃表节点。详细结构相比照较复杂,略。

    (3)编码转换

    只要同时满足下面两个条件时,才会运用紧缩列表:

    有序集合中元素数量小于128个;

    有序集合中一切成员长度都不足64字节。

    假设有一个条件不满足,则运用腾跃表;且编码只能够由紧缩列表转化为腾跃表,反方向则不能够。

    下图展现了有序集合编码转换的特点:

    能够是目前最详细的Redis内存模型及运用解读

    五、运用举例

    了解Redis的内存模型之后,下面经过几个例子阐明其运用。

    1、预算Redis内存运用量

    要预算redis中的数据占据的内存大小,需求对redis的内存模型有比较片面的了解,包括前面引见的hashtable、sds、redisobject、各种对象类型的编码方式等。

    下面以最复杂的字符串类型来停止阐明。

    假定有90000个键值对,每个key的长度是7个字节,每个value的长度也是7个字节(且key和value都不是整数);下面来预算这90000个键值对所占用的空间。在预算占据空间之前,首先可以判定字符串类型运用的编码方式:embstr。

    90000个键值对占据的内存空间主要可以分为两部分:一部分是90000个dictEntry占据的空间;一部分是键值对所需求的bucket空间。

    每个dictEntry占据的空间包括:

    1) 一个dictEntry,24字节,jemalloc会分配32字节的内存块

    2) 一个key,7字节,所以SDS(key)需求7+9=16个字节,jemalloc会分配16字节的内存块

    3) 一个redisObject,16字节,jemalloc会分配16字节的内存块

    4) 一个value,7字节,所以SDS(value)需求7+9=16个字节,jemalloc会分配16字节的内存块

    5) 综上,一个dictEntry需求32+16+16+16=80个字节。

    bucket空间:bucket数组的大小为大于90000的最小的2^n,是131072;每个bucket元素为8字节(由于64位系统中指针大小为8字节)。

    因此,可以预算出这90000个键值对占据的内存大小为:90000*80 + 131072*8 = 8248576。

    下面写个顺序在redis中验证一下:

    public class RedisTest { 

     

    public static Jedis jedis = new Jedis("localhost", 6379); 

     

    public static void main(String[] args) throws Exception{ 

    Long m1 = Long.valueOf(getMemory()); 

    insertData(); 

    Long m2 = Long.valueOf(getMemory()); 

    System.out.println(m2 - m1); 

     

    public static void insertData(){ 

    for(int i = 10000; i < 100000; i++){ 

    (责任编辑:admin)