Redis数据结构

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
简介:

dict

字典(dict)是redis里最核心的数据结构,正如其全称Remote Dictionary Service所说,redis其实就是一个字典服务,字典以key、value的形式呈现给用户,key是简单的字符串,而value可以是各种数据结构,比如字符串(string)、链表(list)、集合(set)、排序集合(zset)、哈希表(hash)等。

redis里dict的实现也比较简单,通过链表来解决哈希冲突,值得一提的是dict的动态扩展能力,当dict里元素不断增加时,其会扩大哈希桶数,然后对现有元素进行rehash,重新分布到对应的桶上,但dict的rehash并不是一次性完成的,这样会导致当dict里元素较多时,rehash耗时较长,导致服务阻塞。

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

dict创建时,会初始化ht[0],插入和访问都通过ht[0]来完成,当需要rehash时,创建一个新的dict ht[1],并以桶为单位将ht[0]里的元素逐步迁移到新的ht[1]上(迁移会在访问dict时触发,也可以配置redis主动在后台周期性的迁移)。所以当访问dict时,如果正在进行rehash,就必须先后查询ht[0], ht[1],因为被访问的元素可能已经迁到新的ht[1]上;当所有的元素都迁移到ht[1]后,用ht[1]代替ht[0],并释放掉原来的ht[0]。

dict是通用的数据结构,采用void*来存储任意类型的对象,由于需求多变,比如有的场景需要在插入元素时重新分配内存,而有的场景直接存储指针,有的场景需要定制对象比较的方式,redis为解决这个问题,定义了一系列的接口,用户可以根据需求在创建dict时指定。

typedef struct dictType {
    unsigned int (*hashFunction)(const void *key);      // key的hash方法
    void *(*keyDup)(void *privdata, const void *key);   // 插入元素时,复制key对象的方法
    void *(*valDup)(void *privdata, const void *obj);   // 插入元素时,复制value对象的方法
    int (*keyCompare)(void *privdata, const void *key1, const void *key2); // key比较的方法
    void (*keyDestructor)(void *privdata, void *key);   // 删除元素时,释放key的方法
    void (*valDestructor)(void *privdata, void *obj);   // 删除元素时,释放value的方法
} dictType;

string

redis所有的key都是string类型,redis的是基于c string的一个封装,在字符串的头部存储了长度信息(strlen的复杂度为O(1)),并且支持动态扩展等特性。

struct sdshdr {
    unsigned int len;
    unsigned int free;
    char buf[];
};

typedef char *sds;

redis的sds类型其实就是char*,redis创建一个string时,返回的是buf的指针,通过这个指针,就可以计算出sdshdr的位置,来访问到len、free等字段。

list

redis的list实现是一个双向链表,与dict类似,list也可以定制对象对比、析构等方法;list在头结点会存储链表的长度,使得获取list长度的复杂度为O(1);头结点还存储了list头部、尾部节点的指针,使得可以从两个方向遍历list。

typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

typedef struct list {
    listNode *head;
    listNode *tail;
    void *(*dup)(void *ptr);  // 复制链表节点value的方法
    void (*free)(void *ptr);  // 释放链表节点value的方法
    int (*match)(void *ptr, void *key); // 链表节点对比方法
    unsigned long len;
} list;

ziplist

双向链表的的最大问题在于头尾指针的开销,64bit OS上,每个节点有16bytes的额外开销,为了节省内存,当list里的元素较少并且大小较小时,redis采用ziplist的格式来实现链表。

ziplist实际上是二进制的形式组织链表,"二进制数据"的存储链表头部,记录总长度,头尾的位置等信息,然后每个节点除了存储节点内容外,还记录自身的长度,以及上一个节点的长度,这样通过遍历"二进制数据"就能访问到ziplist里所有的元素。另外,ziplist节点的长度、以及上一个节点的长度通过变长整数编码,进一步节省内存。

set

set代表一个集合(元素不重复),集合在redis里实现为字典(字典的value为NULL);如果set里所有的元素都是整数时,redis会以intset的形式存储,intset是一个排序的整形数组,为节省内存,当intset里元素值在[INT16_MIN, INT16_MAX]之间时,每个数组元素占2个字节;当inset里元素值都在[INT32_MIN, INT32_MAX]之间时,每个数组元素占4个字节;否则每个元素占8个字节。

zset

zset是排序集合,与set不同的时,zset里每个元素有一个score(double类型),作为排序的标准;redis里zset默认通过一个dict和一个ziplist来实现,dict用于维护set元素到score的映射关系,所有的元素都追加到一个skiplist来保证其排序。当zset里元素较少并且大小较小时,zset也可以ziplist的形式存储,zset的元素以及对应的score会作为ziplist的两个连续节点存储。

hash

redis的hash是维护filed==>value的映射表,hash的默认实现也是dict,以通过field快速找到value;当hahs里元素较少并且大小较小时,hash也以ziplist的形式存储以节省内存。

相关文章
|
3月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
240 6
|
2月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
261 86
|
4月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
2月前
|
存储 消息中间件 NoSQL
Redis数据结构:别小看这5把“瑞士军刀”,用好了性能飙升!
Redis提供5种基础数据结构及多种高级结构,如String、Hash、List、Set、ZSet,底层通过SDS、跳表等实现高效操作。灵活运用可解决缓存、计数、消息队列、排行榜等问题,结合Bitmap、HyperLogLog、GEO更可应对签到、UV统计、地理位置等场景,是高性能应用的核心利器。
|
2月前
|
存储 缓存 NoSQL
Redis基础命令与数据结构概览
Redis是一个功能强大的键值存储系统,提供了丰富的数据结构以及相应的操作命令来满足现代应用程序对于高速读写和灵活数据处理的需求。通过掌握这些基础命令,开发者能够高效地对Redis进行操作,实现数据存储和管理的高性能方案。
111 12
|
2月前
|
存储 消息中间件 NoSQL
【Redis】常用数据结构之List篇:从常用命令到典型使用场景
本文将系统探讨 Redis List 的核心特性、完整命令体系、底层存储实现以及典型实践场景,为读者构建从理论到应用的完整认知框架,助力开发者在实际业务中高效运用这一数据结构解决问题。
|
2月前
|
存储 缓存 NoSQL
【Redis】 常用数据结构之String篇:从SET/GET到INCR的超全教程
无论是需要快速缓存用户信息,还是实现高并发场景下的精准计数,深入理解String的特性与最佳实践,都是提升Redis使用效率的关键。接下来,让我们从基础命令开始,逐步揭开String数据结构的神秘面纱。
|
6月前
|
存储 NoSQL 算法
Redis设计与实现——数据结构与对象
Redis 是一个高性能的键值存储系统,其数据结构设计精妙且高效。主要包括以下几种核心数据结构:SDS、链表、字典、跳跃表、整数集合、压缩列表。此外,Redis 对象通过类型和编码方式动态转换,优化内存使用,并支持引用计数、共享对象和淘汰策略(如 LRU/LFU)。这些特性共同确保 Redis 在性能与灵活性之间的平衡。
|
存储 消息中间件 NoSQL
Redis 数据结构与对象
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求和数据特点来选择合适的数据结构,并合理地设计数据模型,以充分发挥 Redis 的优势。
244 64
|
存储 NoSQL 算法
「Redis」数据结构与对象
Redis数据结构与对象介绍
144 0

相关产品

  • 云数据库 Tair(兼容 Redis)