接上一篇

Redis 哈希表的本质:数组里存的是什么

Redis 哈希表的核心——dictEntry 结构体,是真正承载我们存储的键值对数据的那个结构。

它的定义非常简洁,但设计得很巧妙。以下是其 C 语言代码(在 Redis 源码 src/dict.h 中):

typedef struct dictEntry {void *key; // 键union {    // 值(是一个联合体)void *val;uint64_t u64;int64_t s64;double d;} v;struct dictEntry *next; // 指向下一个哈希表节点,形成链表
} dictEntry;

让我们逐字段分解它的样子和作用:


1. void *key (键)

  • 类型void *,一个指向任意类型的指针。
  • 作用: 存储键(Key)。
  • 细节: Redis 中的键绝大多数情况下都是 SDS (Simple Dynamic String) 类型。所以,这里通常指向一个 SDS 字符串的结构体。使用 void * 使得字典的实现非常通用,理论上可以存储任何类型的键,但 Redis 自身主要用字符串作为键。

2. union v (值 - 联合体)

这是最精妙的部分。v 是一个联合体(union)。联合体的特点是所有成员共享同一块内存空间,空间大小由最大的成员决定。这意味着,在任何一个时刻,这个字段只能存储其中一种类型的值。

  • void *val:

    • 这是最常用的成员。它是一个指针,指向 Redis 中表示的“值”对象。
    • Redis 中的所有数据类型(字符串、列表、哈希、集合、有序集合等)在底层都是用 redisObject 结构体(robj)来表示的。这个 val 指针就指向一个 robj
    • 通过 robj,Redis 才能知道这个值是什么类型(type)、用什么编码(encoding),以及如何操作它。
  • uint64_t u64:

    • 存储一个 64 位无符号整数
    • 应用场景: 当哈希表被用于一些 Redis 的内部功能时,可以直接存储整数,避免额外的指针开销(既省内存,又免去了一次指针寻址,速度更快)。例如,用于记录数据库的过期时间戳。
  • int64_t s64:

    • 存储一个 64 位有符号整数
    • 应用场景: 同上,用于存储整数值。
  • double d:

    • 存储一个 双精度浮点数
    • 应用场景: 用于直接存储浮点数值。

使用联合体的好处:

  • 节省内存:一块内存,多种用途。如果不用联合体,就需要为每种可能的值类型都定义一个字段,会浪费大量空间。
  • 高效:对于整数和浮点数,可以直接内联存储,省去了创建 robj 对象和指针引用的开销,性能更高。

3. struct dictEntry *next (下一个节点指针)

  • 类型: 指向另一个 dictEntry 结构体的指针。
  • 作用用于解决哈希冲突,形成链表(拉链法)。
  • 细节: 当两个或多个键通过哈希函数计算出的数组索引(桶位置)相同时,就会发生哈希冲突。这些发生冲突的键值对会通过 next 指针连接成一个单向链表,挂在数组的同一个桶上。查找时,如果找到的桶里有多个节点,就需要遍历这个链表,用 key 来进行精确匹配。

一个具体的例子

假设我们执行命令 SET mykey "Hello",这个键值对在全局哈希表中就会由一个 dictEntry 来表示:

  1. key 指针:指向一个 SDS 结构,里面存储着字符串 "mykey"
  2. v.val 指针:指向一个 redisObject (robj)。
    • 这个 robjtypeOBJ_STRING
    • 它的 ptr 指针又指向一个 SDS 结构,里面存储着字符串 "Hello"
  3. next 指针:假设 "mykey" 没有发生哈希冲突,那么这个指针就是 NULL

内存结构简化图示:

dictEntry
+-------------------+     +-------------------------+
| key (void*)    ---|---->| SDS: "mykey"            |
+-------------------+     +-------------------------+
| v (union)        |     +-------------------------+
|   val (void*) ---|---->| redisObject (robj)      |
|   u64           |      |   type: OBJ_STRING      |
|   s64           |      |   encoding: ...         |
|   d             |      |   ptr (void*) -------+  |
+-------------------+     +-------------------------+ |
| next (NULL)      |                              |
+-------------------+                              |vSDS: "Hello"

总结

dictEntry 结构体是 Redis 所有键值数据的最终载体,它的设计体现了 Redis 对性能内存效率的极致追求:

  1. 通用性:使用 void* 键和联合体 v,使其能够灵活存储各种数据。
  2. 高效性:通过联合体内联存储整数和浮点数,减少内存分配和指针跳转。
  3. 解决冲突:通过 next 指针实现拉链法,简单可靠。

理解 dictEntry 是理解 Redis 如何高效管理海量数据的关键一步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/94020.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94020.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/94020.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jsqlparser + Freemarker + Vue3 数据透视报表设计方案

1. 目标与前置条件目标:基于 JSQLParser FreeMarker Vue3 构建一套“可配置的数据透视报表”能力,实现从任意基础 SQL/视图出发,按维度/指标灵活聚合、筛选、排序、分页、导出,并支持钻取、联动、TopN、同比环比等常见分析操作。…

SpringBoot3 Ruoyi芋道管理后台vben5.0

新技术栈(Vue3、Vite6、TypeScript、SpringBoot3/SpringCloud基于Vben5.0最新版本,全面采用Vue3 Vite6 Ant Design Vue TypeScript技术栈,并同时支持SpringBoot3单体架构与SpringCloud微服务架构前端技术栈:Vue3 Vite6 TS A…

K8S - NetworkPolicy的使用

1 前置条件2 控制范围3 隔离类型4 如何识别5 主要字段6 案例演示 前置条件 网络策略通过网络插件来实现。 要使用网络策略,你必须使用支持 NetworkPolicy 的网络解决方案。 创建一个 NetworkPolicy 资源对象而没有控制器来使它生效的话,是没有任何作用的…

Linux:TCP协议

TCP是一个面向连接的、可靠的、基于字节流的传输层协议。文次我们会通过介绍TCP的报头并通过分析各字段的用途来进一步解释其核心特性:可靠传输: 有确认应答、超时重传、确保有序。流量控制和拥塞控制: 动态调节发送速率,防止丢包与拥塞。面向…

uniapp使用map打包app后自定义气泡不显示解决方法customCallout

前言:使用uniapp开发后在小程序可以正常显示,但是运行打包成App后就不显示了,其实这一块对于uniapp框架开发来说,是有系统性的bug,如果你再开发时使用的是vue文件进行,就会出现这个问题。解决方法&#xff…

【typenum】 22 类型级别二进制对数运算(Logarithm2)

一、源码 这段代码实现了一个类型级别的二进制对数运算系统 定义(type_operators.rs) /// A **type operator** for taking the integer binary logarithm of Self. /// /// The integer binary logarighm of n is the largest integer m such /// that …

golang 非error错误分类

1.应用级别,可recover这些 panic 一般是 逻辑或使用不当导致的运行时错误,Go 程序可以用 recover 捕获并继续运行:类型示例描述类型不一致atomic.Value 存不同类型 v.Store(100); v.Store("abc")panic: store of inconsistently ty…

【Ansible】变量与敏感数据管理:Vault加密与Facts采集详解

1. 变量Ansible利用变量存储可重复使用的值,可以简化项目的创建和维护,减少错误数量。1.1 变量名称由字符串组成,必须以字母开头,并且只能含有字母、数字和下划线,和其它编程语言很类似。1.2 常见变量要创建的用户要安…

ROS2下YOLO+Moveit+PCL机械臂自主避障抓取方案

整体运行架构 1.运行相机取像节点 . ./install/setup.bash ros2 launch orbbec_camera gemini_330_series.launch.py depth_registration:true 2.运行根据图像x,y获取z的service 基本操作记录: 创建python包,在src目录下 ros2 pkg create test_python_topic --bu…

快速入门Vue3——初体验

目录 前言 一、搭建环境 1.1、安装Node.js 1.2、安装Vite 二、项目创建 三、运行项目 四、集成Pinia 4.1、Pinia介绍 4.2、Pinia安装 五、集成VueUse 5.1、vueuse简介 5.2、vueuse安装 六、集成Vant 6.1、Vant简介 6.2、Vant安装 前言 本专栏主要介绍如何使用…

深入理解Kubernetes核心:标签与标签选择器实战解析

在管理 Kubernetes 集群时,随着 Pods、Services 等资源数量的增长,如何有效地组织和筛选它们,成为了一个核心问题。Kubernetes 为此提供了一个简单却极其强大的机制:标签(Labels)和标签选择器(L…

哈希和字符串哈希

哈希(Hash) Hash 表 Hash 表又称为散列表,一般由 Hash 函数(散列函数)与链表结构共同实现。与离散化思想类似,当我们要对若干复杂信息进行统计时,可以用 Hash 函数把这些复杂信息映射到一个容…

【Docker基础】Docker-Compose核心配置文件深度解析:从YAML语法到高级配置

目录 前言 1 YAML基础语法解析 1.1 YAML格式简介 1.2 Docker-compose中的YAML语法规则 1.3 YAML数据类型在Compose中的应用 2 docker-compose.yml文件结构剖析 2.1 基本文件结构 2.2 版本声明详解 3 services配置深度解析 3.1 服务定义基础 3.2 镜像与构建配置 3.3…

如何判断是否应该为了一个小功能而引入一个大体积的库

在软件开发中,判断是否应该为了一个看似微小的功能,而引入一个大体积的第三方库,是一项极其重要的、需要进行审慎的“投入产出比”分析的技术决策。这个决策,绝不能,仅仅基于“实现功能的便利性”,而必须&a…

相机定屏问题分析五:【跳帧异常】照片模式1x以上的焦段拍照之后定屏

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 相机定屏问题分析五:【跳帧异常】照片模式1x以上的焦段拍照之后定屏9573412 目录 一、问题背景 二…

Non-stationary Diffusion For Probabilistic Time Series Forecasting论文阅读笔记

Non-stationary Diffusion For Probabilistic Time Series Forecasting 摘要 时间序列数据受到潜在的物理动力学和外部影响,其不确定性通常随时间而变化。现有的去噪扩散概率模型(DDPMs)受到加性噪声模型(ANM)的恒定方…

解决Docker 无法连接到官方镜像仓库

这个错误: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)表示 Docker 无法连接到官方镜像仓库 registry-1.docker…

解决RAGFlow启动时Elasticsearch容器权限错误的技术指南

文章目录 问题现象 根本原因分析 解决方案步骤 1. 定位宿主机数据目录 2. 修复目录权限 3. 验证权限状态 4. 重启服务 5. 检查启动状态 永久解决方案:优化Docker Compose配置 高级故障排除 技术原理 问题现象 在启动RAGFlow项目时,执行 docker logs ragflow-es-01 发现Elast…

【C++高阶六】哈希与哈希表

【C高阶六】哈希与哈希表1.什么是哈希?2.unordered系列容器3.哈希表3.1将key与存储位置建立映射关系3.1.1直接定址法3.1.2除留余数法(产生哈希冲突)3.2解决哈希冲突的方法3.2.1闭散列(开放定址法)3.3.2开散列&#xff…

Vue 3 +Ant Design Vue 父容器样式不影响子级,隔离

公共样式文件 common.scss.zz-ant-status-bar {div {font-size: 12px;padding: 0 8px;} }页面代码<div class"zz-ant-status-bar"><a-row><a-col :span"6" ><a-progress :percent"progress.percent" size"small"…