探索Redis内部数据结构

Redis支持多种数据结构,每种数据结构都有其特定的用途。下面对Redis支持的主要数据结构进行详细阐述:

一、字符串(String)

字符串是Redis最基本的数据结构,可以存储一个字符串或者二进制数据,例如图片、序

列化对象等。Redis中的字符串是动态字符串,内部结构实现类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。字符串的最大长度是512M。

字符串是Redis中最基本的数据结构之一,它的底层数据结构被称为简单动态字符串(Simple Dynamic String,SDS)。SDS使用了预分配空间和惰性空间释放等技术,可以在实现高效字符串操作的同时,减少内存的碎片化。

SDS的结构如下所示:

struct sdshdr {
    int len;             // 已使用空间的长度
    int free;            // 可用空间的长度
    char buf[];          // 字节数组
};
+---------+------+------+------+------+------+------+------+------+------+
|  Header | 'R'  | 'e'  | 'd'  | 'i'  | 's'  | '\0' | '3'  | '.'  | '0'  |
+---------+------+------+------+------+------+------+------+------+------+
|  len=6  |   'r'    |   'd'    |    'b'   |    ':'   | '0'    |  '\0'  |  '\0'  |
+---------+------+------+------+------+------+------+------+------+------+
|   free=0  |    R   |    e   |     d  |     i   |     s   |     -    |     1   |      -
+---------+------+------+------+------+------+------+------+------+------+

其中,len表示字符串已经使用的长度,free表示还有多少空间可以用来添加新的字符。buf则是存储字符串的字节数组。

SDS使用了一些技巧来提高性能。例如,在进行字符串扩容时,它会尝试预分配比实际需要更多的空间,以减少内存重分配的次数。此外,SDS还会尽可能地复用已分配的空间,以减少内存碎片。

应用场景:

Redis中的字符串是最基本的数据类型,可以存储任何形式的文本数据,如JSON、HTML、XML、二进制图片等等。字符串在Redis中也是最常用的数据类型之一,常用于缓存数据、计数器、排行榜、存储用户信息等场景。

基本操作:

1、设置字符串:使用SET命令可以将一个字符串设置到Redis中。

SET key value

其中,key表示字符串的键名,value表示字符串的值。

2、获取字符串:使用GET命令可以从Redis中获取一个字符串。

GET key

其中,key表示字符串的键名,返回值为对应的字符串。

3、修改字符串:使用SET命令可以修改Redis中已有的字符串。

SET key value

其中,key表示字符串的键名,value表示新的字符串值。

4、删除字符串:使用DEL命令可以从Redis中删除一个字符串。

DEL key

其中,key表示字符串的键名。

5、获取字符串长度:使用STRLEN命令可以获取一个字符串的长度。

STRLEN key

其中,key表示字符串的键名,返回值为对应字符串的长度。

6、自增或自减操作:使用INCR或DECR命令可以对一个存储整数的字符串进行自增或自减操作。

INCR key
DECR key

其中,key表示字符串的键名,返回值为自增或自减后的值。

7、批量设置字符串:使用MSET命令可以同时设置多个字符串。

MSET key1 value1 key2 value2 ...

其中,key表示字符串的键名,value表示字符串的值,可以设置多个键值对。

8、批量获取字符串:使用MGET命令可以同时获取多个字符串。

MGET key1 key2 ...

其中,key表示字符串的键名,可以获取多个键对应的值。

字符串是Redis中最基本的数据类型,除了上述基本操作,还可以使用各种其他命令对字符串进行操作,例如追加字符串、设置过期时间等。可以根据具体的使用场景和需求,结合Redis提供的命令进行灵活使用。

二、列表(List)

列表是一个双向链表,可以支持在头部和尾部进行插入和删除操作。列表可以用来实现栈和队

列等数据结构。Redis的列表数据结构采用了双向链表实现,每个节点包含一个指向前驱节点和后继节点的指针,以及一个字符串类型的值。同时,列表还包含了一个指向头节点和尾节点的指针,以便快速地进行元素的添加、删除等操作。以下是Redis列表数据结构的结构图:

typedef struct listNode {
    //前置节点
    struct listNode *prev;
    //后置节点
    struct listNode *next;
    //节点的值
    void *value;
} listNode;

在Redis的列表数据结构中,链表节点有两种类型:普通节点和quicklist节点。普通节点用于保存小于64字节的字符串值,而quicklist节点则用于保存大于等于64字节的字符串值或者多个小字符串值。quicklist节点实际上是一个由多个小型ziplist构成的列表,这样能够减少空间的浪费。

应用场景:

  • 作为队列使用:列表数据结构支持在列表的两端进行元素的添加和删除操作,因此可以将其作为队列使用。在生产者消费者模型中,生产者将任务添加到队列中,而消费者则从队列中获取任务进行处理,从而实现任务的异步处理。
  • 作为栈使用:与队列相似,列表数据结构同样支持在列表两端进行元素的添加和删除操作,因此可以将其作为栈使用。在Web开发中,可以利用Redis的列表数据结构保存用户的浏览历史记录,并且能够快速地获取最近浏览的历史记录。
  • 保存关系型数据:在NoSQL数据库中,列表数据结构可以用来保存关系型数据。例如,在社交网络中,可以将关注列表和粉丝列表使用列表数据结构进行存储,从而快速地实现社交网络中的关注、粉丝等功能。

常用操作:

1、LPush(左侧插入元素):将一个或多个元素插入到列表的左侧,如果列表不存在,则创建一个新的列表。

lpush key value1 [value2 ... valuen]

 

2、RPush(右侧插入元素):将一个或多个元素插入到列表的右侧,如果列表不存在,则创建一个新的列表。

rpush key value1 [value2 ... valuen]

3、LPop(左侧删除元素):删除并返回列表左侧的第一个元素。

lpop key

4、RPop(右侧删除元素):删除并返回列表右侧的第一个元素。

rpop key

5、LIndex(获取元素):获取列表中索引位置为index的元素,索引从0开始,负数表示从列表末尾开始计算。

lindex key index

6、LRange(获取范围元素):获取列表中索引位置从start到end的元素,start和end都是0-based,负数表示从列表末尾开始计算。

lrange key start end

7、LLen(获取列表长度):获取列表中元素的数量。

llen key

8、LRem(删除指定数量的元素):从列表中删除与value相等的元素,count表示删除的个数,如果为0表示删除所有匹配的元素,如果为负数表示从列表末尾开始计算。

lrem key count value

9、LTrim(修剪列表):只保留列表中从start到end之间的元素,其余的元素都将被删除,start和end都是0-based,负数表示从列表末尾开始计算。

ltrim key start end

上述操作是Redis列表中的基本操作,还有一些高级操作比如BLPop、BRPop、BRPopLPush等可以满足更多特定的需求。

三、集合(Set)

Set 集合是一个无序的、不允许重复元素的集合,它的底层数据结构使用了「哈希表(Hash Table)」和「跳跃表(Skip List)」的结合体,也就是所谓的「哈希表+跳跃表」。

在 Redis 中,集合类型有两种实现方式:

intset
hashtable

其中,intset 只能存储整型数据,而 hashtable 可以存储任意类型的数据。但是,由于 intset 存储的是连续的整数,因此在存储数值较小、数量较少的集合时,intset 的性能会更好。

对于使用 hashtable 存储的集合来说,其底层数据结构是由一个哈希表和多个链表(或者跳跃表)组成的。其中,哈希表用于存储集合中的元素,链表或跳跃表用于解决哈希冲突。

在 Redis 4.0 之前,Set 集合使用的是哈希表来存储元素,但是在 Redis 4.0 之后,为了提高 Set 集合的查询性能,引入了跳跃表,用于优化有序集合和集合的有序操作。

在 Redis 中,哈希表是一种常用的数据结构,它由一个数组和一些链表(或跳跃表)组成。数组中的每个元素都指向一个链表(或跳跃表),而链表(或跳跃表)则用于解决哈希冲突。当向哈希表中添加元素时,根据元素的哈希值,将元素添加到数组中的相应位置。

在 Set 集合中,每个元素的值作为键存储在哈希表中,而哈希表中的值则都被设置为 NULL。由于哈希表不允许重复键值,因此 Set 集合可以去重。

另外,在 Redis 4.0 中,引入了跳跃表用于优化有序集合和集合的有序操作。跳跃表是一种有序数据结构,它可以快速地进行插入、删除和查找操作,时间复杂度为 O(log n)。在 Set 集合中,跳跃表主要用于优化一些有序操作,例如求交集、并集、差集等操作。

使用场景

  1. 去重:Set能够存储唯一值,因此常用于去重场景。例如统计网站的UV(Unique Visitor)数量,可以将每个用户的IP地址存储在Set中,然后通过Set的元素数量来统计UV。
  2. 集合运算:Set支持并、交、差等集合运算操作,常用于实现共同关注、好友推荐等功能。例如,假设有两个用户A和B,他们的关注列表分别为Set A和Set B,那么A和B共同关注的用户可以通过Set A和Set B的交集来计算。
  3. 排序:Set支持按照元素的大小排序,因此可以将一些带权重的数据存储在Set中,例如用户的积分,然后按照积分大小对用户进行排序。

常用操作

1、添加元素

使用SADD命令向Set中添加元素,如果添加的元素已经存在,则不会重复添加。

SADD key member [member ...]

示例:

127.0.0.1:6379> SADD myset "hello"
(integer) 1
127.0.0.1:6379> SADD myset "world"
(integer) 1
127.0.0.1:6379> SADD myset "hello"
(integer) 0

 

2、获取元素

使用SMEMBERS命令获取Set中的所有元素,返回一个包含所有元素的列表。

SMEMBERS key

示例:

127.0.0.1:6379> SADD myset "hello"
(integer) 1
127.0.0.1:6379> SADD myset "world"
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "world"

 

3、判断元素是否存在

使用SISMEMBER命令判断元素是否存在于Set中,如果存在返回1,否则返回0。

SISMEMBER key member

示例:

127.0.0.1:6379> SADD myset "hello"
(integer) 1
127.0.0.1:6379> SISMEMBER myset "hello"
(integer) 1
127.0.0.1:6379> SISMEMBER myset "world"
(integer) 0

 

4、获取集合中元素的数量

使用SCARD命令获取Set中元素的数量。

SCARD key

示例:

127.0.0.1:6379> SADD myset "hello"
(integer) 1
127.0.0.1:6379> SADD myset "world"
(integer) 1
127.0.0.1:6379> SCARD myset
(integer) 2

 

5、集合运算

使用SUNION、SINTER、SDIFF命令对Set进行集合运算,分别表示并集、交集、差集。

SUNION key [key ...]
SINTER key [key ...]
SDIFF key [key ...]

示例:

127.0.0.1:6379> SADD set1 "hello"
(integer) 1
127.0.0.1:6379> SADD set1 "world"
(integer) 1
127.0.0.1:6379> SADD set2 "world"
(integer) 1
127.0.0.1:6379> SADD set2 "redis"
(integer) 1
127.0

四、散列(Hash)

在 Redis 中,散列(Hash)是一种特殊的键值对集合,它们是一个字符串类型的 field 和 value 的映射表。Hash 类型非常适合存储对象。比如,一个用户对象可以用一个 Hash 类型来表示,Hash 的 field 可以是用户对象的属性,value 则是属性的值。

Redis 中的 Hash 底层数据结构是一个叫做 ziplist 的双向链表或者 hashtable。ziplist 是一个紧凑的双向链表,可以在内存中快速地进行插入、删除、更新等操作。而 hashtable 是一种基于拉链法的哈希表,可以在内存中快速地进行查找操作。

当 Hash 中的键值对数量较少且每个键值对的键和值都比较短时,Redis 会使用 ziplist 作为底层数据结构。ziplist 的优点是占用的空间比 hashtable 小,缺点是查询和更新速度较慢。

当 Hash 中的键值对数量较多或者键和值比较长时,Redis 会使用 hashtable 作为底层数据结构。hashtable 的优点是查询和更新速度较快,缺点是占用的空间比 ziplist 大。

在 Redis 中,可以使用 HSET 命令往散列中添加键值对,使用 HGET 命令获取散列中指定键的值,使用 HGETALL 命令获取散列中所有键值对的键和值等。由于 Hash 的底层数据结构的特殊性,这些操作的时间复杂度为 O(1)。

常用操作

1、设置散列键值对:使用命令 HSET 可以向散列中添加一个键值对,如果键已经存在,则会将其值覆盖。

HSET key field value

2、获取散列键值对:使用命令 HGET 可以获取散列中指定键的值。

HGET key field

3、获取散列所有键值对:使用命令 HGETALL 可以获取散列中所有的键值对。

HGETALL key

4、删除散列键值对:使用命令 HDEL 可以删除散列中的一个或多个键值对。

HDEL key field [field ...]

5、获取散列所有键或所有值:使用命令 HKEYS 或 HVALS 可以获取散列中所有的键或所有的值。

HKEYS key
HVALS key

使用场景

  1. 用户信息存储:可以使用散列类型来存储用户的个人信息,每个用户对应一个散列,其中键是字段名,值是字段值。
  2. 商品信息存储:可以使用散列类型来存储商品的相关信息,每个商品对应一个散列,其中键是属性名,值是属性值。
  3. 计数器:可以使用散列类型来实现计数器功能,其中键是计数器的名称,值是计数器的值。
  4. 缓存:可以使用散列类型来实现缓存功能,将需要缓存的数据存储在散列中,使用键作为缓存的标识,值作为缓存的内容。

五、有序集合(Sorted Set)

Redis 中有序集合(Sorted Set)的底层数据结构是跳跃表(Skip List)和哈希表(Hash Table)的组合。

在 Redis 中,每个有序集合都对应了一个跳跃表和一个哈希表。其中,跳跃表用来维护有序集合的元素顺序,而哈希表则用来存储元素的值和它们在跳跃表中的位置。

跳跃表是一种随机化数据结构,可以用来实现有序集合和字典等数据结构。跳跃表通过对链表进行随机化扩展,使得其查找、插入和删除操作的时间复杂度都能够达到 O(log n),并且相比于平衡树等其他数据结构,跳跃表的实现简单,运行效率高。

具体来说,跳跃表由多个层级组成,每个层级包含一个链表。链表中的每个节点都包含一个元素值和一个指向下一层节点的指针,以及一个指向相同层级的下一个节点的指针。对于每个节点,其在每个层级的高度都是随机决定的,并且越高层的节点数越少。这样就能够保证跳跃表中的元素顺序是有序的,并且查询、插入和删除操作的时间复杂度都为 O(log n)。

在 Redis 的有序集合中,每个元素都包含一个值和一个分数(Score),分数用来对元素进行排序。Redis 的有序集合支持多个元素具有相同分数的情况,因此每个元素的值都必须是唯一的,但分数可以重复。

常用操作

1、添加元素

可以使用 ZADD 命令添加元素到有序集合中,并指定每个元素的分数,如果元素已经存在,则更新分数。

ZADD key score1 member1 [score2 member2]

例如:

ZADD myzset 10 "redis"

这将在名为 myzset 的有序集合中添加一个值为 "redis",分数为 10 的元素。

2、获取元素

可以使用 ZRANGE 命令获取指定范围内的元素,可以按照分数从小到大排序或从大到小排序。

ZRANGE key start stop [WITHSCORES]

例如:

ZRANGE myzset 0 -1 WITHSCORES

这将返回 myzset 中的所有元素以及它们的分数。

 

3、获取元素数量

可以使用 ZCARD 命令获取有序集合中元素的数量。

ZCARD key

例如:

ZCARD myzset

 

4、获取元素排名

可以使用 ZRANK 命令获取指定元素在有序集合中的排名,排名从 0 开始,按照分数从小到大排序。

ZRANK key member

例如:

ZRANK myzset "redis"

 

5、获取元素分数

可以使用 ZSCORE 命令获取指定元素在有序集合中的分数。

ZSCORE key member

例如:

ZSCORE myzset "redis"

使用场景

1、排行榜

可以使用有序集合存储用户的得分和排名,使用 ZADD 命令添加用户得分,使用 ZREVRANGE 命令按照分数从高到低获取排行榜。

2、计数器

可以使用有序集合存储计数器的值,使用 ZINCRBY 命令增加计数器的值,使用 ZSCORE 命令获取计数器的值。

3、排序

可以使用有序集合存储需要排序的数据,使用 ZADD 命令添加数据,使用 ZRANGE 命令按照分数从小到大排序获取数据。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HID协议学习

HID协议学习 0. 文档资料 USB_HID协议中文版_USB接口HID设备_AUJsRmB9kg.pdf HID报告描述符精细说明_mgCxM8_ci9.pdf hut1_22_U3cvnwn_ZZ.pdf 1. 基本概念 HID协议是一种基于USB的通讯协议,用于在计算机和输入设备之间进行数据传输。HID协议定义了标准的数据格…

如何实现在线书签内容替换

书签广泛应用于企业的各种办公自动化业务场景中。例如:在范式合同模板中将甲乙方书签自动替换成具体的公司名称;在红头文件模板中将红头标题书签替换成具体的行政指令;在各种协议模板中将协议日期书签替换为当前日期;等等。 在这…

【Elacticsearch】 原理/数据结构/面试经典问题整理

对Elacticsearch 原理/数据结构/面试经典问题整理的文章; 映射 | Elasticsearch: 权威指南 | Elastic Elacticsearch介绍 Elasticsearch,这里简称ES。ES是一个开源的高可用高扩展的分布式全文搜索与分析引擎,可以提供PB级近实时的数据存储和检索能力&am…

《离散数学》:集合、关系和函数

〇、前言 这章将会对集合、以及集合之上的关系、以及两个集合之间的映射情况做一个细致的讨论。集合作为数学和其他领域中的基础概念,具有广泛的应用和重要的地位。它为数学建立了基本的体系和推理方法,为各个领域的研究和应用提供了一种统一的描述和分…

基于web漏洞扫描及分析系统设计_kaic

基于web漏洞扫描及分析系统设计 摘 要 随着信息技术的发展和网络应用在我国的普及,针对我国境内信息系统的恶意网络攻击也越来越多,并且随着黑客攻击技术的不断地更新,网络犯罪行为变得越来越难以应对,用户日常访问的网站是否安全…

Mysql主从复制及读写分离

🍓 简介:java系列技术分享(👉持续更新中…🔥) 🍓 初衷:一起学习、一起进步、坚持不懈 🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏 🍓 希望这篇文章对你有所帮助,欢…

LaTeX插入参考文献

接着上一篇,用EndNote组织参考文献,然后再导入到LeTex中感觉不太好用,然后就学习了一下BibTeX来管理参考文献,发现还可以,这里记录一下,方便以后查阅。 LaTeX插入参考文献 thebibliographyBibTeX参考资料 t…

前端 sentry 接入钉钉机器人

sentry 接入钉钉机器人 打开钉钉,添加机器人 此时会得到Webhook地址,记录一下,以后会用到 sentry 端设置 看看这里有木有钉钉插件,有的话开启插件,并配置这里我说一下没有的情况下,我们何如设置 这里需要填写webhook url 这个的url 需要是一个公网的地址,不可以是本地…

使用Unity开发一个独立的区块链

Arouse Blockchain [Unity独立区块链] ❗️千万别被误导,上图内容虽然都在项目中可寻,但与目前区块链的业务代码关联不大,仅供宣传作用(总得放些图看着好看)。之所以有以上内容是项目有个目标功能是希望每个用户在区块链上都有一个独一无二的…

View UI Plus (iview)表格单选实现教程

View UI Plus 是 View Design 设计体系中基于 Vue.js 3 的一套 UI 组件库,主要用于企业级中后台系统 View UI,即原先的 iView,从 2019 年 10 月起正式更名为 View UI,并使用全新的 Logo View UI Plus 实现表格单选,这…

首次使用云服务器搭建网站(二)

书接上文,我们已经完成了服务器的租赁,宝塔面板的下载与安装。 接下来我们将正式开始网站搭建。 一、网站创建 点击网站、添加站点 输入网站域名、数据库选择MySQL数据库,选择utf8,数据库账号密码会自动生成。无论你要创建什么样…

互联网行业-镭速文件传输系统方案

互联网行业是一个快速变化和高度竞争的行业,这一行业需要传输大量的数据、代码和文件。在互联网企业的生产和运营过程中,需要传输各种敏感和大型的文件,例如业务报告、数据分析、软件代码等。这些文件需要在不同的部门、不同的地点之间高效地…

用敏捷工具Leangoo领歌做敏捷需求管理

传统的瀑布工作模式使用详细的需求说明书来表达需求,需求人员负责做需求调研,根据调研情况编制详细的需求说明书,进行需求评审,评审之后签字确认交给研发团队设计开发。在这样的环境下,需求文档是信息传递的主体&#…

小雉系统U盘安装包制作

​ 本文原地址: http://www.feitianzhi.com/boke/index.php/archives/57/ 概述 小雉系统可从线上系统制作安装包到U盘,制作的安装包可用于新系统的安装; 小雉系统只提供升级包,对应的安装包均是客户在应用升级包后按本文或http://www.f…

vite预渲染 vite-plugin-prerender 大坑记录

本文部分配置转自:vite预渲染怎么实现_猿耳盗铃的博客-CSDN博客 懒得重新写,贴下版本和自己踩的各种坑吧 以下为版本,本文只给vite vue3的建议,不一定适用,因为正常情况能build成功,我昨天中午之前一直没…

招商基金资深架构师教你如何搭建统一监控平台

随着数字化进程的加速和业务的高速发展,系统的复杂程度日益升级,为确保业务系统的连续性和稳定性,越来越多的企业想要建设统一的监控平台,但却不知道从哪里开始着手。比如: 有些企业会直接将监控系统页面集成到统一监…

Jmeter实现Dubbo接口测试

目录 前言: 一、准备 二、编写我们的测试工程 三、Jmeter来测试这个工程 前言: JMeter可以用来测试Dubbo接口的性能和负载。Dubbo是阿里巴巴的高性能RPC框架,常用于分布式服务的调用。为了测试Dubbo接口,需要使用JMeter提供的…

为什么说2023年最难招聘的岗位是高性能计算工程师?

随着毕业季的临近,高校毕业生将进入就业关键阶段。据统计,2023届全国高校毕业生预计达到1158万人,同比增加82万人,再创新高。尽管有千万的大学毕业生,但是企业反馈依然很难招聘到合适的高性能计算工程师。 这主要归因于…

「OceanBase 4.1 体验」OceanBase:解读领先的分布式数据库系统,功能与体验全解析

文章目录 前言一、关于 【OceanBase 4.1】征文活动(可跳过)二、OceanBase 产品了解2.1 初识 OceanBase2.2 什么是 OceanBase2.3 OceanBase 相关链接2.4 OceanBase 与传统数据库对比有何特别之处2.5 OceanBase 相关概念以及术语2.5.1 OceanBase 基本概念2…

【Docker】什么是Docker,它用来干什么

作者简介: 辭七七,目前大一,正在学习C/C,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖&#x1f…