6、Redis系统-数据结构-01-String

Redis 数据结构简介

前言

Redis 是一个高性能的内存数据库,其关键在于其数据结构的设计。Redis 数据结构是指底层实现 Redis 键值对中值的数据类型的方式。它包括了以下几种主要对象:

  1. String(字符串)对象:最基本的数据类型,可以存储任意类型的数据,包括字符串、整数、浮点数等。
  2. List(列表)对象:一个链表,可以按顺序存储多个字符串,支持从两端进行操作。
  3. Hash(哈希)对象:用于存储键值对集合,类似于一个小型的键值对数据库。
  4. Set(集合)对象:一个无序集合,自动去重,支持集合操作如交集、并集等。
  5. Zset(有序集合)对象:类似于 Set,但每个元素都会关联一个权重(score),元素按权重排序。

        随着 Redis 版本的更新,这些数据类型的底层数据结构也有所不同,如双向链表、压缩列表、哈希表、跳表、整数集合、quicklist 和 listpack 等。这些数据结构的选择使得 Redis 在处理数据的增删查改操作时能够高效地运行。

        研究 Redis 的底层数据结构有助于我们深入理解 Redis 的工作原理,优化性能,确保数据的安全性,扩展系统的能力,并更好地排查和解决问题。这对于使用和管理 Redis 数据库以及构建高效可靠的应用程序都是非常有价值的。本文将详细介绍 Redis 的底层数据结构。

一、SDS(Simple Dynamic String,简单动态字符串)

1、SDS的必要性
  1. C 语言字符串的限制

    • 字符数组表示:在 C 语言中,字符串是以字符数组(char*)的形式表示,以\0字符作为结尾标记。
    • 长度计算复杂度高:字符串长度的获取需要遍历整个字符数组,时间复杂度为 O(N)。
    • 无法保存二进制数据:由于\0字符标记字符串结束,字符串中不能包含\0字符,因此无法保存二进制数据。
    • 安全性问题:C 语言标准库中的字符串操作函数如 strcat 存在缓冲区溢出等安全性问题,因为它们不检查缓冲区大小是否足够。
  2. Redis 的需求

    • 高效操作:需要高效获取字符串长度和修改字符串的能力。
    • 二进制安全:需要能够存储和操作二进制数据。
    • 安全性:需要安全的字符串操作,避免缓冲区溢出等问题。

为了克服 C 语言字符串的不足,Redis 采用了 SDS 作为其字符串数据类型的底层数据结构。

2、SDS的数据结构

SDS 的数据结构如下:

struct sdshdr {int len;       // 记录了字符串的长度int free;      // 分配给字符数组的剩余空间长度char buf[];    // 字符数组,用来保存实际数据
};

结构中的每个成员变量分别介绍如下:

  • len:记录了字符串长度。这样在获取字符串长度时,只需要返回这个成员变量值即可,时间复杂度为 O(1)。
  • alloc:分配给字符数组的剩余空间长度。在修改字符串时,可以通过 alloc - len 计算出剩余的空间大小,用于判断是否需要扩展空间。
  • buf[]:字符数组,用来保存实际数据。不仅可以保存字符串,也可以保存二进制数据。

总的来说,Redis 的 SDS 结构在原本字符数组之上,增加了三个元数据:lenfreeflags,用来解决 C 语言字符串的缺陷。

3、SDS的优势
  1. O(1) 复杂度获取字符串长度

    • C 语言的 strlen 函数需要遍历字符串,时间复杂度为 O(N)。
    • SDS 通过 len 成员变量直接返回字符串长度,时间复杂度为 O(1)。
  2. 二进制安全

    • SDS 不需要 \0 字符标识字符串结尾,而是通过 len 成员变量记录长度,可以存储包含 \0 的数据。
    • 为了兼容部分 C 语言标准库函数,SDS 字符串结尾仍会加上 \0 字符。
    • SDS 的 API 处理数据时以二进制方式处理,程序不会对数据做任何限制,保证数据的原样读取和写入。
  3. 避免缓冲区溢出

    • C 语言字符串操作函数如 strcat 把缓冲区大小是否满足操作需求的检查交给开发者,存在缓冲区溢出的风险。
    • SDS 通过 alloc 和 len 成员变量,在进行字符串修改时由程序内部判断缓冲区大小是否足够。
    • 当缓冲区大小不够用时,Redis 会自动扩展 SDS 的空间大小,满足修改所需的空间。

    SDS 的扩容规则如下:

    • 如果所需的 SDS 长度小于 1 MB,扩容按翻倍进行,即 2 倍的 newlen
    • 如果所需的 SDS 长度超过 1 MB,扩容长度为 newlen + 1MB
  4. 节省空间

    • SDS 设计了 5 种类型的结构体(sdshdr5sdshdr8sdshdr16sdshdr32sdshdr64),根据 len 和 alloc 成员变量的数据类型不同来适应不同大小字符串的存储需求。
    • 不同的数据类型限制了字符数组长度和分配空间大小的上限,从而有效地节省内存空间。
4、SDS 数据结构的实现

以下是 SDS 的实现示例,包括创建、释放、拼接和复制操作:

  1. 创建 SDS

    sds sdsnew(const char *init) {size_t initlen = (init == NULL) ? 0 : strlen(init);sds s = sdsnewlen(init, initlen);return s;
    }
    
  2. 释放 SDS

    void sdsfree(sds s) {if (s == NULL) return;zfree((char*)s - sizeof(struct sdshdr));
    }
    
  3. 拼接字符串

    sds sdscat(sds s, const char *t) {return sdscatlen(s, t, strlen(t));
    }
    
  4. 复制字符串

    sds sdscpy(sds s, const char *t) {return sdscpylen(s, t, strlen(t));
    }
    
  5. 获取 SDS 长度

    size_t sdslen(const sds s) {struct sdshdr *sh = (void*) (s - (sizeof(struct sdshdr)));return sh->len;
    }
    
  6. 清空 SDS

    void sdsclear(sds s) {struct sdshdr *sh = (void*) (s - (sizeof(struct sdshdr)));sh->free += sh->len;sh->len = 0;s[0] = '\0';
    }
    
5、整数类型存储优化

在 Redis 中,如果字符串内容可以表示为数字类型,通常可以优化存储为 long 类型或整数集合(intset)。这是因为整数类型的存储和操作通常比字符串更高效。

  1. 使用整数类型存储数字字符串

    • Redis 的字符串对象可以存储整数类型的值。如果字符串可以被解析为整数,Redis 会将其转换为整数类型进行存储。例如,执行 SET key "12345" 时,Redis 会将其存储为整数编码(INT),而不是字符串编码。
  2. 整数集合(intset)

    • 整数集合是一种紧凑的有序集合,适用于存储小范围的整数集合。它的内部结构如下:
    typedef struct intset {uint32_t encoding; // 编码类型(int16, int32, int64)uint32_t length;   // 集合中元素的个数int8_t contents[]; // 元素数组
    } intset;
    
结论

通过上述解析,我们可以更好地理解 SDS 的设计思想和实现原理,从而在实际开发中更好地利用 SDS 提供的优势。在 Redis 中,字符串可以表示为数字类型时,会自动转换为整数类型进行存储,以提高存储和操作效率。此外,Redis 提供了整数集合(intset)数据结构,用于高效存储一组整数。了解这些优化策略

,可以帮助我们在实际应用中更好地利用 Redis 的性能和功能。

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

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

相关文章

[C++][CMake][流程控制]详细讲解

目录 1.条件判断1.基本表达式2.逻辑判断3.比较4.文件操作5.其他 2.循环1.foreach2.while 1.条件判断 在进行条件判断的时候,如果有多个条件,那么可以写多个elseif,最后一个条件可以使用else,但是开始和结束是必须要成对出现的&am…

WordPress常见问题及简要说明

1. 如何安装WordPress? 简要说明:WordPress是一个流行的内容管理系统,可以帮助用户快速搭建网站。安装WordPress需要以下几个步骤:下载WordPress安装包、上传到服务器、创建数据库、配置数据库信息、完成安装。 2. 如何创建一个新的WordPr…

掌握电量脉搏:WebKit 电池状态(Battery Status API)支持全解析

掌握电量脉搏:WebKit 电池状态(Battery Status API)支持全解析 随着移动设备的广泛使用,Web 应用对设备的电池状态信息的需求日益增长。Battery Status API 提供了一种方式,允许 Web 应用访问设备的电池信息&#xff…

【反悔贪心 反悔堆】1642. 可以到达的最远建筑

本文涉及知识点 反悔贪心 反悔堆 LeetCode1642. 可以到达的最远建筑 给你一个整数数组 heights ,表示建筑物的高度。另有一些砖块 bricks 和梯子 ladders 。 你从建筑物 0 开始旅程,不断向后面的建筑物移动,期间可能会用到砖块或梯子。 当…

Spring Boot中的全局异常处理

Spring Boot中的全局异常处理 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何在Spring Boot应用中实现全局异常处理,这是保证应用…

VSCode, 请在windows下使用git bash终端

用vscode在windows下调测代码,运行时默认打开的终端是windows的cmd,很不受我待见。毕竟习惯了linux,习惯了windows下的git bash风格。怎么办? search,search,research。 先确保windows上安装了git bash。…

MATLAB 2024b 更新了些什么?

MATLAB 2024b版本已经推出了预览版,本期介绍一些MATLAB部分的主要的更新内容。 帮助浏览器被移除 在此前的版本,当我们从MATLAB中访问帮助文档时,默认会通过MATLAB的帮助浏览器(Help browser)。 2024b版本开始&…

【Unity数据交互】如何Unity中读取Ecxel中的数据

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 专栏交流🧧&…

医院挂号系统小程序的设计

管理员账户功能包括:系统首页,个人中心,患者管理,医生管理,专家信息管理,科室管理,预约信息管理,系统管理 微信端账号功能包括:系统首页,专家信息&#xff0…

数据结构算法-排序(一)-冒泡排序

什么是冒泡排序 冒泡排序:在原数组中通过相邻两项元素的比较,交换而完成的排序算法。 算法核心 数组中相邻两项比较、交换。 算法复杂度 时间复杂度 实现一次排序找到最大值需要遍历 n-1次(n为数组长度) 需要这样的排序 n-1次。 需要 (n-1) * (n-1) —…

Java事务(Transaction)

Java事务(Transaction)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列组成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务的引入主要是为了解决并发操作数据…

Unity中遇到“Input Button unload_long_back_btn is not setup”问题

当你在Unity中遇到“Input Button unload_long_back_btn is not setup”这个问题时,需要按照以下步骤进行处理: 1. 检查按钮名称 确保你在代码中使用的按钮名称(unload_long_back_btn)与Unity输入管理器中的配置完全匹配。 2. …

[AIGC] ClickHouse分布式表与本地表的区别及如何查询所有本地表记录

在大规模数据处理和分析场景中,ClickHouse是一种高性能的列式数据库管理系统。ClickHouse支持分布式表和本地表两种表类型,本文将介绍这两种表类型的区别,并探讨如何建表以查询所有本地表的记录。 文章目录 一、ClickHouse分布式表与本地表的…

【Linux进阶】文件系统7——文件系统简单操作

1.磁盘与目录的容量 现在我们知道磁盘的整体数据是在超级区块中,但是每个文件的容量则在inode 当中记载。 那在命令行模式下面该如何显示这几个数据?下面就让我们来谈一谈这两个命令: df:列出文件系统的整体磁盘使用量&#xf…

Poker Game, Run Fast

Poker Game, Run Fast 扑克&#xff1a;跑得快 分门别类&#xff1a; 单张从小到大默认 A < 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K 跑得快&#xff1a;单张从小到大 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 &…

javaweb个人主页设计(html+css+js)

目录 1 前言和要求 1.1 前言 1.2 设计要求 2 预览 2.1 主页页面 2.2 个人简介 2.3 个人爱好 2.4 个人成绩有代码&#xff0c;但是图片已省略&#xff0c;可以根据自己情况添加 2.5 收藏夹 3 代码实现 3.1 主页 3.2 个人简介 3.3 个人爱好 3.4 个人成绩&#xff…

大数据处理利器:Apache Spark编程基础与实战

"大数据处理利器&#xff1a;Apache Spark编程基础与实战" 是一个涵盖了Apache Spark这一强大大数据处理框架的深入学习和实践指南。Apache Spark是一个快速、通用、可扩展的大数据处理引擎&#xff0c;它提供了高级别的API用于大规模数据处理和分析。下面&#xff0…

求职成功率的算法,与葫芦娃救爷爷的算法,有哪些相同与不同

1 本节概述 通过在B站百刷葫芦娃这部儿时剧&#xff0c;我觉得可以从中梳理出一些算法&#xff0c;甚至可以用于求职这个场景。所以&#xff0c;大家可以随便问我葫芦娃的一些剧情和感悟&#xff0c;我都可以做一些回答。 2 葫芦娃救爷爷有哪些算法可言&#xff1f; 我们知道…

身体(body)的觉醒

佛&#xff0c;是一个梵文的汉语音译词&#xff0c;指觉醒者。 何谓觉醒&#xff1f;什么的觉醒&#xff1f;其实很简单&#xff0c;就是身体的觉醒。 佛的另一个名字&#xff0c;叫菩提&#xff0c;佛就是菩提&#xff0c;菩提老祖&#xff0c;就是佛祖。 body&#xff0c;即…

微服务: 初识 Spring Cloud

什么是微服务? 微服务就像把一个大公司拆成很多小部门&#xff0c;每个部门各自负责一块业务。这样一来&#xff0c;每个部门都可以独立工作&#xff0c;即使一个部门出了问题&#xff0c;也不会影响整个公司运作。 什么是Spring Cloud? Spring Cloud 是一套工具包&#x…