【Redis】Redis的五种数据结构

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis】Redis的五种数据结构

字符串

字符串类型分别使用 REDIS_ENCODING_INT 和 REDIS_ENCODING_RAW 两种编码:


REDIS_ENCODING_INT 使用 long 类型来保存 long 类型值。

REDIS_ENCODING_RAW 则使用 sdshdr 结构来保存 sds (也即是 char* )、 long long 、

double 和 long double 类型值。

换句话来说, 在 Redis 中, 只有能表示为 long 类型的值, 才会以整数的形式保存, 其他类型的整数、小数和字符串, 都是用 sdshdr 结构来保存。

[外链图片转存失败(img-XhnK28s8-1567048898164)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-bb7ecaf3be8e729365b5a9241cdcb04aa5a709d1.svg)]

新创建的字符串默认使用 REDIS_ENCODING_RAW 编码, 在将字符串作为键或者值保存进数据库时, 程序会尝试将字符串转为 REDIS_ENCODING_INT 编码


哈希表

REDIS_HASH (哈希表)是 HSET 、 HLEN 等命令的操作对象, 它使用 REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_HT 两种编码方式:


[外链图片转存失败(img-MKi6CDzh-1567048898168)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-145365a458984496cfecacd67b29f5d42c39a401.svg)]


创建空白哈希表时, 程序默认使用 REDIS_ENCODING_ZIPLIST 编码, 当以下任何一个条件被满足时, 程序将编码从 REDIS_ENCODING_ZIPLIST 切换为 REDIS_ENCODING_HT :

哈希表中某个键或某个值的长度大于 server.hash_max_ziplist_value (默认值为 64 )。

压缩列表中的节点数量大于 server.hash_max_ziplist_entries (默认值为 512 )


列表

REDIS_LIST (列表)是 LPUSH 、 LRANGE 等命令的操作对象, 它使用 REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_LINKEDLIST 这两种方式编码:

[外链图片转存失败(img-gytpHpeq-1567048898172)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-9d1b937227cf948b8a9bfb3137570475e5407d2c.svg)]


创建新列表时 Redis 默认使用 REDIS_ENCODING_ZIPLIST 编码, 当以下任意一个条件被满足时, 列表会被转换成 REDIS_ENCODING_LINKEDLIST 编码:


试图往列表新添加一个字符串值,且这个字符串的长度超过 server.list_max_ziplist_value (默认值为 64 )。

ziplist 包含的节点超过 server.list_max_ziplist_entries (默认值为 512 )。

列表的阻塞原语BLPOP 、 BRPOP 和 BRPOPLPUSH

阻塞原语并不是一定会造成客户端阻塞:


只有当这些命令被用于空列表时, 它们才会阻塞客户端。

如果被处理的列表不为空的话, 它们就执行无阻塞版本的 LPOP 、 RPOP 或 RPOPLPUSH 命令。

[外链图片转存失败(img-Nfnb66pX-1567048898175)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-657d8e78e1f1357fdff05173a259334670b87f85.svg)]

阻塞

当一个阻塞原语的处理目标为空键时, 执行该阻塞原语的客户端就会被阻塞。


阻塞一个客户端需要执行以下步骤:


将客户端的状态设为“正在阻塞”,并记录阻塞这个客户端的各个键,以及阻塞的最长时限(timeout)等数据。

将客户端的信息记录到 server.db[i]->blocking_keys 中(其中 i 为客户端所使用的数据库号码)。

继续维持客户端和服务器之间的网络连接,但不再向客户端传送任何信息,造成客户端阻塞。

[外链图片转存失败(img-7Srz5418-1567048898186)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-72233dd6a912518ff6874fdad4e20356091a6063.svg)]

当客户端被阻塞之后,脱离阻塞状态有以下三种方法:


被动脱离:有其他客户端为造成阻塞的键推入了新元素。

主动脱离:到达执行阻塞原语时设定的最大阻塞时间。

强制脱离:客户端强制终止和服务器的连接,或者服务器停机。

脱离阻塞状态

通过将新元素推入造成客户端阻塞的某个键中, 可以让相应的客户端从阻塞状态中脱离出来 (取消阻塞的客户端数量取决于推入元素的数量)。


LPUSH 、 RPUSH 和 LINSERT 这三个添加新元素到列表的命令, 在底层都由一个 pushGenericCommand 的函数实现, 这个函数的运作流程如下图:

[外链图片转存失败(img-TbnHSUQy-1567048898188)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-be4975476661a3e683475377d30b659d70bee64c.svg)]

当向一个空键推入新元素时, pushGenericCommand 函数执行以下两件事:


检查这个键是否存在于前面提到的 server.db[i]->blocking_keys 字典里, 如果是的话,

那么说明有至少一个客户端因为这个 key 而被阻塞,程序会为这个键创建一个 redis.h/readyList 结构, 并将它添加到

server.ready_keys 链表中。

将给定的值添加到列表键中。

列表


集合

REDIS_SET (集合)是 SADD 、 SRANDMEMBER 等命令的操作对象, 它使用 REDIS_ENCODING_INTSET 和 REDIS_ENCODING_HT 两种方式编码:

[外链图片转存失败(img-5ykAMOkm-1567048898193)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-2f54a5b62b3507f0e6d579358e426c78b0dfbd5c.svg)]


第一个添加到集合的元素, 决定了创建集合时所使用的编码:


如果第一个元素可以表示为 long long 类型值(也即是,它是一个整数), 那么集合的初始编码为

REDIS_ENCODING_INTSET 。

否则,集合的初始编码为 REDIS_ENCODING_HT 。

集合编码的切换

如果一个集合使用 REDIS_ENCODING_INTSET 编码, 那么当以下任何一个条件被满足时, 这个集合会被转换成 REDIS_ENCODING_HT 编码:


intset 保存的整数值个数超过 server.set_max_intset_entries (默认值为 512 )。

试图往集合里添加一个新元素,并且这个元素不能被表示为 long long 类型(也即是,它不是一个整数)。

集合类型为什么选择intset结构作为其中之一的底层实现方式?

intset底层实现方式是数组,这个数组以有序、无重复的方式保存集合元素,并且根据新添加的整数元素类型来进行自动升级,例如从int16_t升级到int32_t; 它具有灵活性+节省内存的优点;

在集合类型只有整数元素并且元素不是很大的时候选择intset是比较好的一个选择;


字典编码的集合

当使用 REDIS_ENCODING_HT 编码时, 集合将元素保存到字典的键里面, 而字典的值则统一设为 NULL 。


作为例子, 以下图片展示了一个以 REDIS_ENCODING_HT 编码表示的集合, 集合的成员为 elem1 、 elem2 和 elem3 :

[外链图片转存失败(img-gVLWNUdF-1567048898198)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-3b62c50ed475dc6c91adbb8079f0e0104f644931.svg)]


有序集

REDIS_ZSET (有序集)是 ZADD 、 ZCOUNT 等命令的操作对象, 它使用 REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_SKIPLIST 两种方式编码:

[外链图片转存失败(img-Ua7tWSuy-1567048898206)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-4d10098056ec25ed0e239f64bbcac524bce31bc8.svg)]


编码的选择¶

在通过 ZADD 命令添加第一个元素到空 key 时, 程序通过检查输入的第一个元素来决定该创建什么编码的有序集。


如果第一个元素符合以下条件的话, 就创建一个 REDIS_ENCODING_ZIPLIST 编码的有序集:


服务器属性 server.zset_max_ziplist_entries 的值大于 0 (默认为 128 )。

元素的 member 长度小于服务器属性 server.zset_max_ziplist_value 的值(默认为 64 )。

否则,程序就创建一个 REDIS_ENCODING_SKIPLIST 编码的有序集。

有序集合编码的转换

对于一个 REDIS_ENCODING_ZIPLIST 编码的有序集, 只要满足以下任一条件, 就将它转换为 REDIS_ENCODING_SKIPLIST 编码:


ziplist 所保存的元素数量超过服务器属性 server.zset_max_ziplist_entries 的值(默认值为 128 )

新添加元素的 member 的长度大于服务器属性 server.zset_max_ziplist_value 的值(默认值为 64 )


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
存储 消息中间件 缓存
Redis 5 种基础数据结构?
Redis的五种基础数据结构——字符串、哈希、列表、集合和有序集合——提供了丰富的功能来满足各种应用需求。理解并灵活运用这些数据结构,可以极大地提高应用程序的性能和可扩展性。
32 2
|
2月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
45 5
|
2月前
|
存储 消息中间件 NoSQL
Redis数据结构:List类型全面解析
Redis数据结构——List类型全面解析:存储多个有序的字符串,列表中每个字符串成为元素 Eelement,最多可以存储 2^32-1 个元素。可对列表两端插入(push)和弹出(pop)、获取指定范围的元素列表等,常见命令。 底层数据结构:3.2版本之前,底层采用**压缩链表ZipList**和**双向链表LinkedList**;3.2版本之后,底层数据结构为**快速链表QuickList** 列表是一种比较灵活的数据结构,可以充当栈、队列、阻塞队列,在实际开发中有很多应用场景。
|
3月前
|
存储 消息中间件 NoSQL
Redis 数据结构与对象
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求和数据特点来选择合适的数据结构,并合理地设计数据模型,以充分发挥 Redis 的优势。
62 8
|
3月前
|
存储 NoSQL Java
介绍下Redis 的基础数据结构
本文介绍了Redis的基础数据结构,包括动态字符串(SDS)、链表和字典。SDS是Redis自实现的动态字符串,避免了C语言字符串的不足;链表实现了双向链表,提供了高效的操作;字典则类似于Java的HashMap,采用数组加链表的方式存储数据,并支持渐进式rehash,确保高并发下的性能。
介绍下Redis 的基础数据结构
|
2月前
|
存储 NoSQL 关系型数据库
Redis的ZSet底层数据结构,ZSet类型全面解析
Redis的ZSet底层数据结构,ZSet类型全面解析;应用场景、底层结构、常用命令;压缩列表ZipList、跳表SkipList;B+树与跳表对比,MySQL为什么使用B+树;ZSet为什么用跳表,而不是B+树、红黑树、二叉树
|
2月前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
存储 NoSQL 算法
「Redis」数据结构与对象
Redis数据结构与对象介绍
|
NoSQL 算法 Java
Redis进阶 - 数据结构:对象机制详解,一文深入底层分析
我们在前文已经阐述了Redis 5种基础数据类型详解,分别是字符串(string)、列表(list)、哈希(hash)、集合(set)、有序集合(zset),以及5.0版本中Redis Stream结构详解;那么这些基础类型的底层是如何实现的呢?Redis的每种对象其实都由对象结构(redisObject) 与 对应编码的数据结构组合而成, 本文主要介绍对象结构(redisObject) 部分。
Redis进阶 - 数据结构:对象机制详解,一文深入底层分析