当前位置: 首页 > article >正文

【Redis】键值对数据库实现

目录

  • 1、背景
  • 2、五种基本数据类型对应底层实现
  • 3、redis数据结构

1、背景

redis是一个(key-value)键值对数据库,其中value可以是五大基本数据类型:string、list、hash、set、zset,这五大基本数据类型对应着不同的底层结构,接下来就来讲解一下redis如何存储这些数据类型的。

2、五种基本数据类型对应底层实现

redis数据结构旧版本(≤3.0)底层实现新版本(≥3.2+)底层实现说明
string简单动态字符串(SDS)简单动态字符串(SDS)SDS是二进制安全的动态字符串,支持高效追加和预分配
list双向链表(LinkedList)或压缩列表(Ziplist)快速列表(Quicklist)新版本统一用Quicklist(双向链表 + Ziplist的混合结构),平衡内存和访问效率
hash压缩列表(Ziplist)或哈希表(Hashtable)Ziplist或Hashtable,优化阈值新版本调整了Ziplist转hashtable的阈值(如hash-max-ziplist-entries等配置)
set整数集合(Intset)或哈希表(Hashtable)Intset或Hashable,优化阈值新版本优化了Intset的升级策略(如元素类型超出int16时自动转Hashtable)
zset压缩列表(Ziplist)或跳跃表(SkipList)+ 哈希表Ziplist或SkipList + Hashtable新版本调整了Ziplist转SkipList的阈值(如zset-max-ziplist-entries)

关键变化说明如下:
1、List的优化

旧版本:大列表用LinkedList(内存碎片多),小列表用Ziplist(节省内存但修改效率低)。
新版本:统一用Quicklist(双向链表节点内嵌Ziplist),兼顾内存和操作效率。

2、Hash/Set/ZSet的阈值调整

新版本通过配置参数优化了Ziplist和Intset的转换条件,减少内存浪费。

3、String保持不变

始终使用SDS,但新版本可能优化了内存分配策略(如惰性释放)。

3、redis数据结构

redis数据结构如下(6.2.18版本),所有键值对都存储在其中:

typedef struct redisDb {dict *dict; //存储当前数据库的所有键值对dict *expires; //存储所有设置了过期时间的键及过期时间戳dict *blocking_keys; //记录因阻塞操作(如BLPOP)被阻塞的客户端及其监听的键dict *ready_keys; //暂存已收到数据且准备解除阻塞的键(如LPUSH触发的BLPOP唤醒)dict *watched_keys; //实现事务的WATCH机制(乐观锁),记录被监视的键及关联的客户端int id; //当前数据库的编号(如0-15,默认16个库)long long avg_ttl; //统计当前数据库键的平均TTL(毫秒),用于INFO命令展示unsigned long expires_cursor; //记录渐进式过期检查的游标(避免长时间阻塞)list *defrag_later; //存储待内存碎片整理的键名列表(逐步整理,避免阻塞主线程)
} redisDb;

核心存储结构为dict *dict,dict结构体组成为:

typedef struct dict {dictType *type; //定义字典操作的函数指针(如哈函数、键比较函数)void *privdata; //存储字典的私有数据,传递给type中的函数dictht ht[2]; //存储实际数据的哈希表,ht[0]是主哈希,ht[1]仅在rehash时使用long rehashidx; //标记rehash的进度(-1表示为进行rehash,≥0表示当前rehash的桶索引)int16_t pauserehash; //控制rehash的暂停状态(>0暂停,=0正常,<0表示错误)
} dict;

核心存储结构为两个哈希表dictht ht[2],哈希表dictht的结构为:

typedef struct dictht {dictEntry **table; //存储实际键值对数据的哈希桶数组,每个元素是链表头指针(解决哈希冲突)unsigned long size; //哈希表的大小(桶的总数量)unsigned long sizemask; //哈希掩码,用于计算键的索引unsigned long used; //当前哈希表中已使用的节点数量(所有链表的节点总数)
} dictht;

核心存储结构dictEntry **table里存放了哈希表数组,dictEntry 结构如下:

typedef struct dictEntry {void *key; //存储键的指针(实际指向redis的字符串对象)union {void *val; //指向redis对象的指针(如string、list、hash等复杂类型)uint64_t u64; //直接存储整数值(避免额外内存分配)int64_t s64; //直接存储有符号整数值(如时间戳)double d; //直接存储浮点数值} v;struct dictEntry *next; //指向下一个dictEntry节点(形成链表,解决哈希冲突)
} dictEntry;

void *key和void *val分别指向了实际的键对象和值对象robj,robj结构如下:

typedef struct redisObject {unsigned type:4; //标识redis对象的类型(如string、list、hash等)unsigned encoding:4; //表示底层实现的编码方式unsigned lru:LRU_BITS; //记录对象的访问时间或频率(用于内存淘汰策略)int refcount; //引用计数(实现内存回收垃圾回收机制)void *ptr; //指向实际存储数据的底层结构(如SDS、ziplist、dict等)
} robj;

void *ptr存储真正的数据,unsigned type:4为reids数据类型,其定义如下:

#define OBJ_STRING 0    /* String object. */
#define OBJ_LIST 1      /* List object. */
#define OBJ_SET 2       /* Set object. */
#define OBJ_ZSET 3      /* Sorted set object. */
#define OBJ_HASH 4      /* Hash object. */

相关文章:

【Redis】键值对数据库实现

目录 1、背景2、五种基本数据类型对应底层实现3、redis数据结构 1、背景 redis是一个&#xff08;key-value&#xff09;键值对数据库&#xff0c;其中value可以是五大基本数据类型&#xff1a;string、list、hash、set、zset&#xff0c;这五大基本数据类型对应着不同的底层结…...

什么是 NoSQL 数据库?它与关系型数据库 (RDBMS) 的主要区别是什么?

我们来详细分析一下 NoSQL 数据库与关系型数据库 (RDBMS) 的主要区别。 什么是 NoSQL 数据库&#xff1f; NoSQL (通常指 “Not Only SQL” 而不仅仅是 “No SQL”) 是一类数据库管理系统的总称。它们的设计目标是解决传统关系型数据库 (RDBMS) 在某些场景下的局限性&#xf…...

网址为 http://xxx:xxxx/的网页可能暂时无法连接,或者它已永久性地移动到了新网址

这是由于浏览器默认的非安全端口所导致的&#xff0c;所谓非安全端口&#xff0c;就是浏览器出于安全问题&#xff0c;会禁止一些网络浏览向外的端口。 避免使用6000,6666这样的端口 6000-7000有很多都不行&#xff0c;所以尽量避免使用这个区间 还有在云服务器中&#xff0c…...

《智能网联汽车 自动驾驶功能场地试验方法及要求》 GB/T 41798-2022——解读

目录 1. 适用范围与核心目标 2. 试验核心要求 2.1 试验场地与环境 2.2 试验设备与数据采集 2.3 试验车辆要求 3. 试验过程与通过条件 4. 关键试验场景与方法 4.1 交通信号识别及响应 4.2 基础设施与障碍物识别 4.3 行人及非机动车场景 4.4 紧急避险与风险策略 5. 特…...

鸿蒙跨平台开发教程之Uniapp布局基础

前两天的文章内容对uniapp开发鸿蒙应用做了一些详细的介绍&#xff0c;包括配置开发环境和项目结构目录解读&#xff0c;今天我们正式开始写代码。 入门新的开发语言往往从Hello World开始&#xff0c;Uniapp的初始化项目中已经写好了一个简单的demo&#xff0c;这里就不再赘述…...

uniapp使用npm下载

uniapp的项目在使用HBuilder X创建时是不会有node_modules文件夹的&#xff0c;如下图所示&#xff1a; 但是uni-app不管基于哪个框架&#xff0c;它内部一定是有node.js的&#xff0c;否则没有办法去实现框架层面的一些东西&#xff0c;只是说它略微有点差异。具体差异表现在…...

uni-app微信小程序登录流程详解

文章目录 uni-app微信小程序登录流程实战详解微信小程序登录流程概述1. 获取登录凭证&#xff08;code&#xff09;2. 发送登录请求3. 保存登录态4. 登录状态管理5. 应用登录状态请求拦截器中添加 token自动登录页面路由守卫 使用 Vuex 集中管理登录状态登录组件示例登录流程最…...

【C++游戏引擎开发】第34篇:C++实现反射

一、反射系统概述 1.1 反射的核心概念 1.1.1 运行时自省能力 反射允许程序在运行时动态获取和操作自身的类型信息。这种能力突破了静态类型语言的限制,使得开发者可以: 检查对象类型及其成员结构动态创建未在编译期确定的类型实例实现类型无关的通用操作接口1.1.2 元数据驱…...

C# 的异步任务中, 如何暂停, 继续,停止任务

namespace taskTest {using System;using System.Threading;using System.Threading.Tasks;public class MyService{private Task? workTask;private readonly SemaphoreSlim semaphore new SemaphoreSlim(0, 1); // 初始为 0&#xff0c;Start() 启动时手动放行private read…...

langchain4j中使用milvus向量数据库做RAG增加索引

安装milvus向量数据库 官方网址 https://milvus.io/zh 使用docker安装milvus mkdir -p /data/docker/milvus cd /data/docker/milvus wget https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh#在docker中启动milvus sh standalone_emb…...

MySQL SQL Mode及其说明

以下是MySQL中所有支持的SQL Mode及其说明&#xff0c;综合了多个来源的信息并进行了分类整理&#xff1a; 一、严格模式相关 STRICT_TRANS_TABLES 对事务型存储引擎&#xff08;如InnoDB&#xff09;启用严格数据校验。若插入非法值&#xff08;如类型不符、超出范围等&#…...

Web前端最新导航

前言 本文列出了很多与前端有关的常见网站、博客、工具等&#xff0c;整体来看比较权威。有些东西已经过时了&#xff0c;我就不列出来了。学是一方面&#xff0c;也是最主要的方面&#xff1b;但还有一个作用&#xff0c;比如&#xff0c;“这个前端框架你都不知道啊”、“这个…...

2025年AI工程师认证深度解析:AAIA认证体系全景指南与实战策略

一、IAAAI认证体系演进与价值定位 1.1 国际人工智能认证发展现状 全球人工智能认证市场呈现显著分化态势。据Gartner 2025Q1报告显示&#xff0c;北美市场以IEEE/ACM双认证体系为主导&#xff08;市占率38%&#xff09;&#xff0c;欧盟区推行AI Act合规认证&#xff08;强制…...

CentOS 和 RHEL

CentOS 和 RHEL&#xff08;Red Hat Enterprise Linux&#xff09;关系非常紧密&#xff0c;简而言之&#xff1a; CentOS 最初是 RHEL 的免费、开源克隆版&#xff0c;几乎与 RHEL 二进制兼容。 CentOS 原是 RHEL 的“免费双胞胎”&#xff0c;但已被放弃&#xff0c;现在推荐…...

flask开启https服务支持

目录 一、背景 二、开启https支持 三、自签名 1、安装openssl 2、验证安装 3、自签名 四、编写代码 五、访问https接口 一、背景 最近在做自动化业务&#xff0c;需要兼容现在主流的框架开发的前端页面&#xff0c;于是到github找到了几个项目&#xff0c;clone下来项目并…...

统计服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息

文章目录 一、背景二、说明三、页面四、代码 前端 MonitorServiceProcessPage.vueMonitorServiceProcessTable.vueMonitorServiceProcessTableButton.vueaddMonitorTask.vueproductOperation.vueshowMonitorTask.vueMonitorSystemLog.vueMonitorTask.vueMonitorTaskLog.vueReal…...

【SGL】Scatter-Gather List内存传输技术

文章目录 1. What is SGL&#xff1f;2. sgl内存传输的原理2.1 核心思想2.2 sgl数据结构2.3 摘链和挂链 3. 零拷贝技术3.1 问题背景3.2 零拷贝的核心思想及实现方式 4. sgl在存储行业的应用 1. What is SGL&#xff1f; sgl&#xff08;Scatter-Gather List&#xff09;内存传…...

-MAC桢-

MAC桢和IP的关系&#xff1a; 主机A想跨网络和B通信需要IP地址进行路由选择&#xff0c;但一个局域网&#xff0c;比如路由器进行路由选择之前&#xff0c;首先要将数据包发送给路由器B&#xff0c;也就是局域网通信也就是同一个网段的主机进行通信&#xff0c;所以必须通过mac…...

安装:Kali2025+Docker

安装:Kali2025Docker Kali2025安装 直接官网下载WMware版本 https://www.kali.org/get-kali/#kali-virtual-machines 直接打开运行 初始用户密码 kali/kali sudo -i 命令切换到root 更换镜像 切换到其他可用的 Kali Linux 镜像源可能会解决问题,可以使用国内的镜像源&…...

Linux云计算训练营笔记day04[Rocky Linux中的命令:mv、cp、grep(^$)、tar、重定向>和>>]

mv 移动(剪切) 源数据会消失 格式: mv 源文件 目标路径 touch /opt/a.txt 创建文件 mv /opt/a.txt /root 移动文件&#xff0c;没有改名 mkdir gongli 创建目录 mv gongli /opt/ 移动目录&#xff0c;没有改名 mv /opt/gongli tedu 移动目录&#xff0c;改名了 …...

AbMole Olaparib:打破常规,用PARP抑制重塑肿瘤研究

在当今的生物医学研究领域&#xff0c;Olaparib&#xff08;AZD2281&#xff0c;AbMole&#xff0c;M1664&#xff09;作为一种重要的PARP&#xff08;聚腺苷二磷酸核糖聚合酶&#xff09;抑制剂&#xff0c;受到了广泛关注。Olaparib可干扰 DNA 单链断裂的修复&#xff0c;从而…...

RPC、gRPC和HTTP的区别

RPC 只是一种屏蔽远程过程调用的设计&#xff0c;它与HTTP不是对立的&#xff0c;两者不是一个层面的概念。 RPC底层通信可以使用TCP实现&#xff08;如Thrift&#xff09;&#xff0c;也可以使用HTTP实现&#xff08;如gRPC&#xff09;&#xff0c;其本身并无限制。 1. 概念…...

Windows重置网络,刷新缓存

同时按键盘上的【Windows】键和【S】键&#xff0c;弹出搜索框&#xff0c;输入 命令提示符 在“最佳匹配”下的【命令提示符】上右键&#xff0c;点击【以管理员身份运行】 1弹出一个窗口&#xff0c;在光标闪烁的位置&#xff0c;直接输入【netsh winsock reset】&#xff0…...

Ref是什么

在 React 中&#xff0c;ref 是一种用于访问 DOM 元素或组件实例的机制。它允许你在组件中直接操作 DOM 元素&#xff0c;或者访问子组件的实例。ref 的使用场景非常广泛&#xff0c;包括表单操作、焦点控制、动画等。以下是关于 ref 的详细讲解以及在项目中的常见使用场景。 …...

OpenHarmony平台驱动开发(十),MMC

OpenHarmony平台驱动开发&#xff08;十&#xff09; MMC 概述 功能简介 MMC&#xff08;MultiMedia Card&#xff09;即多媒体卡&#xff0c;是一种用于固态非易失性存储的小体积大容量的快闪存储卡。 MMC后续泛指一个接口协定&#xff08;一种卡式&#xff09;&#xff0…...

解决IDEA无法运行git的问题

之前git一直没有问题&#xff0c;今天打开就提示我安装git&#xff0c;自然用git去提交新项目也会遇到问题。 我出现问题的原因是&#xff1a;git路径缺失 文件->设置->git 发现git的路径为空&#xff0c;按照实际位置填写即可...

HTTP 响应状态码总结

一、引言 HTTP 响应状态码是超文本传输协议&#xff08;HTTP&#xff09;中服务器对客户端&#xff08;通常是 Web 浏览器&#xff09;请求的响应指示。这些状态码是三位数字代码&#xff0c;用于告知客户端请求的结果&#xff0c;包括请求是否成功。响应被分为五个类别&#…...

Java求职面试:Spring Boot与微服务的幽默探讨

Java求职者面试&#xff1a;技术与幽默的碰撞 场景概述 在某互联网大厂的面试现场&#xff0c;面试官严肃认真&#xff0c;程序员则是一个搞笑的水货角色。面试者名叫张伟&#xff0c;年龄28岁&#xff0c;硕士学历&#xff0c;拥有5年的Java开发经验。以下是面试的详细过程。…...

lua脚本+Redission实现分布式锁

实现分布式锁最简单的一种方式&#xff1a;基于Redis 不论是本地锁还是分布式锁&#xff0c;核心都在于“互斥”。 在 Redis 中&#xff0c; SETNX 命令是可以帮助我们实现互斥。SETNX 即 set if not exists (对应 Java 中的 setIfAbsent 方法)&#xff0c;如果 key 不存在的…...

JVM之jcmd命令详解

jcmd 是 Oracle JDK&#xff08;Java Development Kit&#xff09;自 JDK 7 起引入的一个强大的诊断工具&#xff0c;用于与正在运行的 JVM&#xff08;Java Virtual Machine&#xff09;实例进行交互。它允许用户执行各种诊断命令&#xff0c;比如线程堆栈分析、堆转储、GC 信…...