缓存:Redis的存储和数据结构

介绍Redis的存储结构对象、数据类型、寻key流程

Redis的存储结构

RedisDB:代表一个数据库对象;存储了当前库下所有数据;

typedef struct redisDb{ 

    // 键空间:存储了当前库的所有的键值对
    dict *dict; 
    // 过期字典:存储了设置了过期时间的key及其过期时间
    dict *expires; 
    //... 
} redisDb;

Hash Table:DB内的键空间;

typedef struct dict{
    // 指向对哈希表操作的函数
    dictType *type;

    // 私有数据
    void *privdata;

    // ht[1]指向真正的哈希表结构,ht[2]用于备用扩容,指向正在扩容的哈希表
    dictEntry **ht_table[2];

    // rehash标志位,标识是否在rehash:如果不在rehash,此值为-1;
    // 当rehash开始,用trehashidx来记录索引
    int trehashidx;
}
// 实际存储Redis的键值对
struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    // 同一个桶下的下一个key
    struct dictEntry *next; 
    void *metadata[]; 
};

RedisObject:是Redis所有数据类型的抽象基类,每一个Redis键值对都是一个RedisObject;

typedef struct redisObject{ 
    //类型 STRING、LIST、SET、HASH、ZSET
    unsigned type:4; 
    //编码 RAW、INT、EMBSTR
    unsigned encoding:4; 
    //指向底层数据结构的指针 
    void *ptr; 
    //引用计数 RedisObject 被多个键所共享时,引用计数会增加
    int refcount; 
    //记录最后一次被程序访问的时间戳,用于实现 LRU 缓存淘汰策略 
    unsigned lru:22; 
}robj

Redis Datastructure and Command

Loading Mermaid Chart...

1. string

String data structure in Redis is a simple key-value pair. It can be used to store integer, text string and Json string.

底层为c语言可变长的动态字符数组(char数组),容量最大512MB;

  • 时间复杂度O(1):直接根据len,通过索引获取字符串;
  • 杜绝缓冲区溢出,动态扩容预分配内存;
  • 二进制安全,按长度读取,而非c语言的字符串按照结束标识("\0")判断;(可能被存储的特殊字符误判)
struct __attribute__ ((__packed__)) hisdshdr8 {
  uint8_t len; /* buf已使用长度 */
  uint8_t alloc; /* buf总大小 */
  unsigned char flags; /* 标识当前的sds类型:5、8、16、32、64 */
  char buf[];    /* 存储字符数组 */
};

Commnad:

  • SET
    /
    GET
    : used to set / retrieve a key-value pair. If the value does not exsit,
    nil
    is returnd.
  • MSET
    /
    MGET
    : set / get multiple key-value pair in one operation in the order they are requested. If the value does not exsit,
    nil
    is returnd for that key's position.
  • INCR
    /
    DECR
    : increment / decrement the value of a key that stores an integer.

2. Hash

A hash data structure in Redis is a collection of key-value pairs. It is like a dictionary or a map in programming languages. It is useful for storing objects with multiple fields.

  • 相比于string类型不需要存储于json中的符号,存储相同的内容,占用空间更少;
  • 可以单独操作每个字段,比较灵活;
  • 哈希冲突使用链地址法解决;
  • 扩容采用渐进式rehash;
    • 传统扩容:一次性拷贝数据到重新分配的内存,这样会在数据量比较大时,消耗大量CPU资源、造成响应延迟、阻塞等情况;
    • 渐进式Rehash:逐步被动的迁移数据,在迁移完成后释放原有内存;
  • 适用场景:对象、实体缓存;

Command:

  • HSET
    /
    HGET
    :
    HSET
     is used to set a field-value pair inside a hash.
    HGET
    retrieves the value of a specific field in a hash.
  • HMSET
    /
    HMGET
    : allows you to set multiple field-value pair and retrieves values of multiple fields.
  • HDEL
    : used to delete one or more fields from a hash.

3. List

A list data structure in Redis is an ordered collection of strings. It can be used to store a sequence of values. The elements in a list are ordered, and you can access them by index.

  • list是一个双向链表,支持正反向查找、索引查找、左右pop等;
  • 支持阻塞pop,当列表为空,pop阻塞;可以充当阻塞队列使用(Redis5.0之后使用stream作为消息队列);
  • 支持索引查找、范围查询、支持重复的元素;
  • 适用场景:消息队列、存储列表;

Command:

  • LPUSH
    /
    RPUSH
    : allow you push one or more elements to the left / right of a list.
  • LPOP
    /
    RPOP
    : allow you pop one or more elements from the left / right of a list.
  • LRANGE
    : retrieves a range of elements from a list.

4. Set

A set in Redis is an unordered collection of unique strings. It is used to store a group of distinct values. It can store

user Ids
,
tags
which the order of elements in a set does not matter, and duplicate elements are not allowed.

  • 无序、唯一、自动去重;
  • 适用于:标签、关键字等唯一性场景;
  • 使用场景:点赞、关注列表、粉丝列表、抽奖;

Command:

  • SADD
    /
    SMEMBERS
    :
    SADD
    adds one or more members to a set. and
    SMEMBERS
    can retrieve all the elements of a set.
  • SREM
    : removes member from a set.
    SREM myset "member1"
  • SISMEMBER
    : checks if a given value is a member of a set.

5. Zset(Sorted Set)

A sorted set in Redis is a collection of unique members, each associated with a score. The members are stored based on their scores in ascending or descending order. It is useful for ranking systems.

  • 排序集合,自动去重,在set的基础上增加
    score
    权重进行排序;
  • 应用:排行榜、点赞、延迟队列;

Command:

  • ZADD
    : adds one or more members with their scores to a sorted set.
    ZADD myzset 1 "member"
    adds "member" with a score of 1 to
    myzset
    .
  • ZRANGE
    : retrieves a range of members from a zset by scores.
    ZRANGE 0-30
    returns all the elements of the zset.
  • ZREM
    : removes one or more members from a zset.
  • ZRANK
    / : get the rank of a member.
    ZRANK myzset "member1"
     returns the position of 
    "member1"
     in the 
    myzset
     sorted set.
  • ZREVRANK
    : get the descending order of score.

Common Commnad

  • EXISTS key [key1, key2]
    : checks if one or more keys exist.
  • DEL key [key1, key2]
    : deletes one or more keys.

Redis的key寻址

  1. 集群状态下,先使用hash slot算法找到key存放的节点;
    • hash槽的总大小是固定的16384;
    • 根据key的落点,可以找到key所在的集群节点;
  2. 客户端向此节点发起查询请求;
  3. 对key进行hash取模,找到对应的值;