Redis基础数据结构

1. Redis简述

Redis是一种缓存组件,缓存一般可以分为两种,一种是应用内缓存,如Map以及EHCache(java三方库),另外一种是缓存组件,比如Memache,Redis,Mongodb;Redis它的全称是remote dictionary server(远程字典服务器),以字典的形式存储数据,并可以在其他应用中以TCP协议读写字典中 的数据

2. 数据类型

string/list/hash/set/sorted-set常用的数据类型,具体数据类型解释以及对应常用命令等参考redis 数据类型详解 以及 redis适用场景场合

Redis 命令参考

本文主要讲解内容为数据结构,具体如下

A. String(字符串类型)

String类型通过int、SDS(simple dynamic string)作为存储结构;其中int用来存放整型数据,sds用来存放字节/字符串/浮点型数据。在Redis源码库中的sds.h中可以查看到数据结构定义如下:

typedef char *sds;

具体分别定义了5中sdshdr类型,sdshdr5/sdshdr8/sdshdr16/sdshdr32/sdshdr64(8表示字符串最大长度2^8-1),不同的类型可以存储不同大小的数据,如sds.h中sdshdr8定义如下:

struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used 表示当前sds的长度*/
    uint8_t alloc; /* excluding the header and null terminator 分配的内存大小*/
    unsigned char flags; /* 3 lsb of type, 5 unused bits 当前sdshdr类型*/
    char buf[]; /* sds实际存放位置 */
};

其中sdshdr8为默认结构,在sds.c中 sdsnewlen(创建一个sds数据) 具体代码定义了其默认实现

B. List(列表类型)

List内部是使用双向链表实现,在redis3.2之前,list类型的value是用linkedlist或者ziplist实现,在list元素格式和单个元素长度较小的时候使用ziplist来实现以便减少内存占用;3.2之后引入quicklist的结构来存储list。

quicklist也是一个双向链表,它是有linkedlist和ziplist结合组成的数据结构,在linkedlist每个节点上都是一个ziplist,在源码文件quicklist.c第一行注释中就可以看到【quicklist.c - A doubly linked list of ziplists】

具体的数据结构图如下(源码参考quicklist.h):

具体ziplist实现和结构不做解释,我也不清楚。如果想了解的可以参考Redis之ziplist数据结构

C. Hash

Hash提供两种结构来存储,一种是hashtable、另一种是前面的ziplist,数据量小的时候用ziplist(1. 哈希对象保存的所有键值对的键和值的字符串长度都小于64字节;2. 哈希对象保存的键值对数量小于512个)。在redis中,哈希表分为三层,源码地址dict.h

dictEntry

管理一个key-value,同时保留相邻元素的指针,用来维护哈希表的内部链;

typedef struct dictEntry {
    void *key;
    union {    // value有多种类型,value用了union来存储
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next; ;// 下一个节点的地址,用来处理hash碰撞(类似于java中的hashmap)
} dictEntry;

dictht

实现一个hash表会使用一个table存放dictEntry的地址,一般情况下通过hash(key)%len得到的值就是table的 索引,这个值决定了我们要将此dictEntry节点放入table的哪个索引里,这个table实际上就是我们说的hash表。

typedef struct dictht {
    dictEntry **table; // dictEntry*数组,Hash表 
    unsigned long size; // Hash表总大小
    unsigned long sizemask; //掩码,计算在table中索引的掩码, 值是size-1
    unsigned long used; // 当前dictht有多少个dictEntry节点
} dictht;

dict

dictht实际上就是hash表的核心,但是只有一个dictht还不够,比如rehash、遍历hash等操作,所以redis定义了 一个叫dict的结构以支持字典的各种操作,当dictht需要扩容/缩容时,用来管理dictht的迁移

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];  /* 两个hash表,rehash时使用 */
    long rehashidx; /* rehash的索引, -1表示没有进行rehash */
    unsigned long iterators; /* number of iterators currently running */
} dict;

hash数据结构图

D. Set(集合)

set 是无序集合,每个元素都是不同的,也就是不能有重复数据。最大可以包含(2 的 32 次方-1)个元素。set 的是通过 hash table 实现的, 所以添加,删除,查找的复杂度都是 O(1)。

Set在的底层数据结构以intset或者hashtable来存储。当set中只包含整数型的元素时,采用intset来存储,否则采用hashtable存储,但是对于set来说,该hashtable的value值用于为NULL。通过key来存储元素

E. Sorted-Set(有序集合)

在集合类型(Set)的基础上,有序集合类型为集合中的每个元素都关联了一个分数,这使得我们获得分数最高(或最低)的前N个元素,获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是他们的分数却可以相同

sorted-set是以一种跳跃表表的形式进行实现,内部是ziplist或者skiplist+hashtable实现。最核心的结构就是skiplist(跳跃表)。具体实现解释和图标可以参考Redis SortedSet实现原理

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值