• Redis数据类型


    Redis是基于内存K-V数据库,然而内存资源又是非常宝贵的,所以使用最合适的存储结构,做到尽量节省内存资源,又对性能的影响不大,成为一个至关重要的问题。

     

    redisObject数据结构:

    typedef struct redisObject {
        unsigned type:4;
        unsigned encoding:4;
        unsigned lru:REDIS_LRU_BITS; /* lru time (relative to     server.lruclock) */
        int refcount;
        void *ptr;
    } robj;
    type:占用4个bit位,记录了对象的类型 
    STRING=0
    LIST=1
    SET=2
    ZSET=3
    HASH=4
    encoding:记录了对象所使用的编码,也就是说对象使用了什么数据结构作为对象底层实现
    #define OBJ_ENCODING_RAW 0        /* Raw representation */
    #define OBJ_ENCODING_INT 1        /* Encoded as integer */
    #define OBJ_ENCODING_HT 2         /* Encoded as hash table */
    #define OBJ_ENCODING_ZIPMAP 3     /* Encoded as zipmap */ // 已废弃
    #define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
    #define OBJ_ENCODING_ZIPLIST 5    /* Encoded as ziplist */
    #define OBJ_ENCODING_INTSET 6     /* Encoded as intset */
    #define OBJ_ENCODING_SKIPLIST 7   /* Encoded as skiplist */
    #define OBJ_ENCODING_EMBSTR 8     /* Embedded sds string encoding */
    #define OBJ_ENCODING_QUICKLIST 9  /* Encoded as linked list of ziplists */
    lru:表示当内存超限时采用LRU算法清除内存中的对象。

    refcount:表示对象的引用计数。ptr:指针指向对象底层的数据结构,这个数据对象有encoding决定


    sdshdr数据结构:
    typedef char *sds;
    struct sdshdr {
        int len;
        int free;
        char buf[];
    };

    len:表示缓存中已经占用的空间长度

    free:表示buf中可剩余的空间长度,当free为0的时候,表示buf中没有剩余的缓冲空间

    buf:数据空间数组

    使用sds字符串的好处

    1.获取字符串的长度,时间复杂度为o(1)
    2.减少内存空间分配次数,redis的sds会进行空间的预分配,
    3.使用惰性空间释放,当字符串的长度缩短的时候,不会立即free空间,而是使用free将字段数量记录下来,等待后续的使用。
    4.使用C字符串可能因为忘记分配内存空间,字符串长度增大时造成内存溢出,对于SDS,由于len和free的存在,对于修改字符串使用空间预分配和队形空间释放两种策略,降低了内存溢出的可能
    5.二级制安全,SDS的API使用二进制的方式来处理buf里面的元素,并且以len属性表示的长度判断字符串是否结束。






    String类型:

    String对象的编码可以是int,raw,embstr,
    如果一个对象保存的是整数,并且这个数可以被long识别,那么这个对象的编码则设置为int

        如果保存长度小于44字节,这个对象编码使用的是embstr编码

    如果保存长度大于44字节,这个对象编码使用的是raw编码

    embstr编码是用来保存短字符串的一种编码方式,这种编码和raw编码一样,都使用redisObject结构和sdshdr结构来标识字符串对象。

    raw编码会调用两次内存分配函数来创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间,空间中一次包含redisObject和sdshdr两个结构。

     

     

     

    List类型:

     在版本3.2之前,当链表数量比较小的时候,使用的是ziplist实现,长度比较大或数量比较多的时候,使用linkedlist来实现。

     但是在版本3.2之后,可能考虑到彼此转换很麻烦,可能导致内存碎片,重新分配内存区域可能涉及大量数据拷贝,重新引入了一个 quicklist 的数据结构,列表的底层都由quicklist实现。

     

    quicklistNode 数据结构
    typedef struct quicklistNode {
        struct quicklistNode *prev;  // 指向上一个ziplist节点
        struct quicklistNode *next;  // 指向下一个ziplist节点
        unsigned char *zl;           // 数据指针,如果没有被压缩,就指向ziplist结构,反之指向quicklistLZF结构 
        unsigned int sz;             // 表示指向ziplist结构的总长度(内存占用长度)
        unsigned int count : 16;     // 表示ziplist中的数据项个数
        unsigned int encoding : 2;   // 编码方式,1--ziplist,2--quicklistLZF
        unsigned int container : 2;  // 预留字段,存放数据的方式,1--NONE,2--ziplist
        unsigned int recompress : 1; // 解压标记,当查看一个被压缩的数据时,需要暂时解压,标记此参数为1,之后再重新进行压缩
        unsigned int attempted_compress : 1; // 测试相关
        unsigned int extra : 10; // 扩展字段,暂时没用
    } quicklistNode;

    具体结构解析待完善

    Hash类型:
    hash的编码可以是 ziplist或hashTable
    编码转换:当元素的个数小于512个的时候,并且每个元素的长度小于64字节的时候,hash使用的是 ziplist

    超过这个限制的话,则使用的是hashtable

    hashTable的哈希表使用的是字典数据结构,hash对象中的每个对象使用一个字典键值对。

    但是先对于简单的字典数据结构,使用压缩链表就可以满足,可以集中存储,节约空间。

    Set类型:

    set集合对象的编码可以是intset或者是hashtable

    编码转换条件:所有元素都是整数,并且元素的个数超过512个,使用的是intset,不符合条件的话,使用的是hashtable

     intset编码的集合对象使用整数集合作为底层实现

     hashtable使用字典作为底层实现

     

     Zset类型:

    有序集合使用的编码可以是 ziplist或者 skiplist

    转换编码条件:当元素的数量小于128,并且所有元素的长度小于64字节,则使用ziplist,不符合的话使用的是跳表

    ziplist,每个集合元素使用两个紧挨在一起的压缩列表节点来保存。集合元素按分数从小到大排

    跳表结构

    typedef struct zset{    
         zskiplist *zsl;   //跳跃表   
         dict *dice;        //字典    
    } zset;

     一个zset结构同时包含一个字典和一个跳跃表,

    字典的键保存元素的值,字典的值则保存元素的分值;跳跃表节点的 object 属性保存元素的成员,跳跃表节点的 score 属性保存元素的分值。

    总结五大数据结构的应用场景:

    String:二进制安全,可以用来存放图片,视频,另外redis基于内存的高性能读写,可以用来保存秒杀场景中商品库存分布式锁,同时由于具有过期时间机制,可以用来设置短信验证码过期校验

    hash:KV结构,可以做单点登陆用户信息的存放

    list:可以实现简单的消息队列推送,有序列表

    set:由于底层是基于字典实现,查询速度十分快,由于其存放不可重复的数据,可以做平台用户名是否重复,利用api对交集、并集、差集等对支持操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

    zset :有序的集合,可以做范围查找(redis geo的底层是基于zset),排行榜应用

     

















     

  • 相关阅读:
    SQL Server中的执行引擎入门
    SQL Server复制入门(一)复制简介
    Django 代码片断收集(持续更新)
    今天思路有点乱,随便记一点关于 xmlrpc 的
    PIL 学习笔记(1)
    Django newforms
    在 Django 的 View 中利用 function decorator 可实现一定程度的代码重用
    今天在 Linux 上顺利编译 PIL 1.1.6 成功
    用 PIL 写了个简单的缩略图生成程序
    [转贴] 中药内外合治急慢性鼻窦炎
  • 原文地址:https://www.cnblogs.com/Jemb/p/11576827.html
Copyright © 2020-2023  润新知