龙空技术网

Redis 6 数据结构详解

NEDHOME 30

前言:

当前看官们对“redis 6”大致比较关注,各位老铁们都想要了解一些“redis 6”的相关资讯。那么小编也在网上搜集了一些关于“redis 6””的相关文章,希望兄弟们能喜欢,兄弟们一起来学习一下吧!

介绍

Redis 是一个开源的高性能 key-value 数据库,支持多种数据结构,包括字符串、哈希表、列表、集合和有序集合。本文将详细介绍 Redis 6 中的各种数据结构,包括它们的使用方法、优缺点以及底层源码分析。

字符串

字符串是 Redis 中最基本的数据结构,它可以存储任意类型的数据,包括二进制数据。在 Redis 中,字符串的最大长度为 512MB。

使用方法

字符串的常用命令包括:

SET key value:设置键值对。GET key:获取键对应的值。INCR key:将键对应的值加 1。DECR key:将键对应的值减 1。APPEND key value:将值追加到键对应的值的末尾。MSET key1 value1 key2 value2 ...:同时设置多个键值对。MGET key1 key2 ...:同时获取多个键对应的值。

例如,以下命令将设置一个键值对,然后获取该键对应的值:

> SET mykey "hello"OK> GET mykey"hello"
底层源码分析

字符串的底层实现是 redisObject 结构体,它包含了一个 sds 结构体指针,sds 是 Redis 自己实现的动态字符串,比 C 语言中的字符串更加高效。以下是 redisObject 结构体的定义:

typedef struct redisObject {    unsigned type:4;    unsigned encoding:4;    unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */    int refcount;    void *ptr;} robj;

其中,ptr 指向的即为 sds 结构体。

字符串的编码方式有多种,包括 REDIS_ENCODING_RAW、REDIS_ENCODING_INT 和 REDIS_ENCODING_EMBSTR。其中,REDIS_ENCODING_RAW 表示字符串的值存储在 sds 结构体中,REDIS_ENCODING_INT 表示字符串的值为整数,而 REDIS_ENCODING_EMBSTR 表示字符串的值存储在 redisObject 结构体中,用于存储长度小于等于 44 字节的字符串。

字符串的底层源码比较简单,主要是 sds 结构体的实现,这里不再赘述。

哈希表

哈希表是 Redis 中用于存储键值对的数据结构,它类似于 C 语言中的结构体。在 Redis 中,哈希表的键和值都是字符串类型。

使用方法

哈希表的常用命令包括:

HSET key field value:设置哈希表中的一个字段。HGET key field:获取哈希表中的一个字段的值。HDEL key field1 field2 ...:删除哈希表中的一个或多个字段。HGETALL key:获取哈希表中所有字段和对应的值。HMSET key field1 value1 field2 value2 ...:同时设置多个字段和对应的值。HMGET key field1 field2 ...:同时获取多个字段的值。

例如,以下命令将设置一个哈希表,然后获取该哈希表中的一个字段的值:

> HSET myhash field1 "hello"1> HGET myhash field1"hello"
底层源码分析

哈希表的底层实现是 dict 结构体,它包含了一个数组和一个链表。数组用于存储哈希表的槽位,链表用于解决哈希冲突。以下是 dict 结构体的定义:

typedef struct dict {    dictType *type;    void *privdata;    dictht ht[2];    long rehashidx; /* rehashing not in progress if rehashidx == -1 */    unsigned long iterators; /* number of iterators currently running */} dict;

其中,ht[0] 和 ht[1] 分别表示哈希表的两个哈希表,用于在哈希表扩容时使用。rehashidx 表示当前哈希表是否正在进行扩容操作。iterators 表示当前正在遍历哈希表的迭代器数量。

哈希表的底层源码比较复杂,包括哈希函数、哈希冲突解决方法等,这里不再赘述。

列表

列表是 Redis 中用于存储有序元素集合的数据结构,它可以在列表的头部或尾部添加、删除元素。在 Redis 中,列表的元素可以是字符串、哈希表、列表、集合和有序集合。

使用方法

列表的常用命令包括:

LPUSH key value1 value2 ...:将一个或多个值插入到列表头部。RPUSH key value1 value2 ...:将一个或多个值插入到列表尾部。LPOP key:删除并返回列表的头部元素。RPOP key:删除并返回列表的尾部元素。LINDEX key index:获取列表中指定位置的元素。LLEN key:获取列表的长度。LRANGE key start stop:获取列表中指定范围内的元素。

例如,以下命令将创建一个列表,然后在列表头部插入一个值,最后获取列表的长度:

> LPUSH mylist "world"1> LLEN mylist1
底层源码分析

列表的底层实现是 ziplist 和 linkedlist 两种方式。ziplist 是 Redis 自己实现的压缩列表,用于存储长度小于等于 64 字节的字符串。linkedlist 则是双向链表,用于存储长度大于 64 字节的字符串。

以下是 ziplist 结构体的定义:

typedef struct ziplist {    unsigned char *zl;    unsigned int len;    unsigned int bytes;    unsigned int tail;    unsigned int in_malloc:1;    unsigned int compressed:1;} ziplist;

其中,zl 指向压缩列表的起始地址,len 表示压缩列表中元素的数量,bytes 表示压缩列表占用的字节数,tail 表示压缩列表的尾部偏移量。in_malloc 表示压缩列表是否在内存中分配,compressed 表示压缩列表是否被压缩。

以下是 linkedlist 结构体的定义:

typedef struct listNode {    struct listNode *prev;    struct listNode *next;    void *value;} listNode;typedef struct list {    listNode *head;    listNode *tail;    void *(*dup)(void *ptr);    void (*free)(void *ptr);    int (*match)(void *ptr, void *key);    unsigned long len;} list;

其中,head 和 tail 分别指向链表的头部和尾部节点,dup、free 和 match 分别是用于复制、释放和比较节点值的函数指针。

列表的底层源码比较复杂,包括压缩列表的编码方式、链表的节点结构、节点的添加和删除等,这里不再赘述。

集合

集合是 Redis 中用于存储无序元素集合的数据结构,它可以进行交集、并集、差集等操作。在 Redis 中,集合的元素可以是字符串、哈希表、列表、集合和有序集合。

使用方法

集合的常用命令包括:

SADD key member1 member2 ...:向集合中添加一个或多个元素。SREM key member1 member2 ...:从集合中删除一个或多个元素。SMEMBERS key:获取集合中所有元素。SISMEMBER key member:判断元素是否在集合中。SUNION key1 key2 ...:获取多个集合的并集。SINTER key1 key2 ...:获取多个集合的交集。SDIFF key1 key2 ...:获取多个集合的差集。

例如,以下命令将创建一个集合,然后向集合中添加一个元素,最后获取集合中所有元素:

> SADD myset "hello"1> SMEMBERS myset1) "hello"
底层源码分析

集合的底层实现是 dict 结构体,它实际上是一个哈希表,用于存储集合中的元素。以下是 dict 结构体的定义:

typedef struct dict {    dictType *type;    void *privdata;    dictht ht[2];    long rehashidx; /* rehashing not in progress if rehashidx == -1 */    unsigned long iterators; /* number of iterators currently running */} dict;

其中,ht[0] 和 ht[1] 分别表示哈希表的两个哈希表,用于在哈希表扩容时使用。rehashidx 表示当前哈希表是否正在进行扩容操作。iterators 表示当前正在遍历哈希表的迭代器数量。

集合的底层源码比较简单,主要是哈希表的实现,这里不再赘述。

有序集合

有序集合是 Redis 中用于存储有序元素集合的数据结构,它与集合的区别在于有序集合中的元素可以关联一个分数,用于排序。在 Redis 中,有序集合的元素可以是字符串。

使用方法

有序集合的常用命令包括:

ZADD key score1 member1 score2 member2 ...:向有序集合中添加一个或多个元素。ZREM key member1 member2 ...:从有序集合中删除一个或多个元素。ZRANGE key start stop [WITHSCORES]:获取有序集合中指定范围内的元素。ZSCORE key member:获取有序集合中指定元素的分数。ZINCRBY key increment member:将有序集合中指定元素的分数增加指定值。

例如,以下命令将创建一个有序集合,然后向有序集合中添加一个元素,最后获取有序集合中指定范围内的元素:

> ZADD myzset 1 "hello"1> ZRANGE myzset 0 -1 WITHSCORES1) "hello"2) "1"
底层源码分析

有序集合的底层实现是 ziplist 和 skiplist 两种方式。ziplist 是 Redis 自己实现的压缩列表,用于存储长度小于等于 64 字节的字符串。skiplist 则是跳跃表,用于存储长度大于 64 字节的字符串。

以下是 ziplist 结构体的定义:

typedef struct ziplist {    unsigned char *zl;    unsigned int len;    unsigned int bytes;    unsigned int tail;    unsigned int in_malloc:1;    unsigned int compressed:1;} ziplist;

其中,zl 指向压缩列表的起始地址,len 表示压缩列表中元素的数量,bytes 表示压缩列表占用的字节数,tail 表示压缩列表的尾部偏移量。in_malloc 表示压缩列表是否在内存中分配,compressed 表示压缩列表是否被压缩。

以下是 skiplist 结构体的定义:

typedef struct zskiplistNode {    sds ele;    double score;    struct zskiplistNode *backward;    struct zskiplistLevel {        struct zskiplistNode *forward;        unsigned int span;    } level[];} zskiplistNode;typedef struct zskiplist {    struct zskiplistNode *header, *tail;    unsigned long length;    int level;} zskiplist;

其中,header 和 tail 分别指向跳跃表的头部和尾部节点,length 表示跳跃表中元素的数量,level 表示跳跃表的层数。

有序集合的底层源码比较复杂,包括压缩列表和跳跃表的实现,这里不再赘述。

总结

本文详细介绍了 Redis 6 中的各种数据结构,包括字符串、哈希表、列表、集合和有序集合。同时,我们还分析了它们的使用方法、优缺点以及底层源码实现。

在实际应用中,我们需要根据具体场景选择合适的数据结构,以达到最佳性能。比如,对于需要排序

标签: #redis 6