- 浏览: 141328 次
文章分类
最新评论
阅读本节前需要阅读 Redis 对象系统概览一节。此外,对于各个对象底层中所用到的数据结构,请阅读前面的相关博文笔记,此次不再赘述。
在 Redis 的五种类型的对象中,字符串对象是唯一一种会被其他四种类型对象嵌套的对象。字符串对象的编码可以是 int、raw 或者 embstr。
如果一个字符串对象保存的是整数值,并且该值可以使用 long 型表示,则该对象结构的 ptr 属性里面保存的就是整数值(会将 void* 转换成 long),并同时将其 encoding 属性设置为 int。但如果该整数值超过了 long 型所能表示的数值范围,则使用下面的 embstr 或者 raw 编码方式来表示。
如果字符串对象保存的是一个字符串值,并且其长度大于 32 字节,则字符串对象将使用一个简单动态字符串(SDS)结构来保存,同时将该对象的 encoding 属性设置为 raw。而如果字符串值的长度小于等于 32 字节,则使用的就是 embstr 编码的方式。
embstr 编码和 raw 编码一样,都使用 redisObject 结构和 sdshdr 结构来表示字符串对象,但 raw 编码会调用两次内存分配函数来分别创建这两个结构,而 embstr 编码则是调用一次内存分配函数来分配一块连续的空间,空间中依次包含 redisObject 和 sdshdr 两个结构。因此 embstr 编码的字符串对象在释放内存时也会少调用一次内存释放函数,同时使用连续的内存空间也能让字符串对象更好地利用缓存带来的优势。
此外,可以用 long double 类型表示的浮点数在 Redis 中也是作为字符串值来保存的,Redis 会在操作需要的时候将其转换回浮点数。至于使用的是 embstr 还是 raw 编码方式,同样需要根据将其转换成字符串后的长度而定。
但是一个字符串对象使用的编码方式并非是一成不变的,int 和 embstr 编码的字符串对象在条件满足的情况下,会被转换为 raw 编码的字符串对象。
对于 int 编码的字符串对象来说,当执行了一些命令(如 APPEND),使得该对象保存的不再是整数值时,对象的编码就会从 int 变为 raw。而对于 embstr 编码的字符串对象来说,由于 Redis 没有为之编写任何相应的修改接口,因此 embstr 编码的字符串对象实际上是只读的,对这样的字符串对象执行任何修改命令,都会先将其转换为 raw 编码的后再进行修改,最终的结果都是一个 raw 编码的字符串对象。下面的命令片段说明了这几点。
列表对象的编码可以是 ziplist 或者 linkedlist。ziplist 编码的列表对象使用压缩列表作为底层实现,每个压缩列表节点保存了一个列表元素。linkedlist 编码的列表对象使用双端链表作为底层实现,每个双端链表节点都保存了一个字符串对象,而每个字符串对象都保存了一个列表元素。
当列表对象同时满足以下两个条件时,列表对象使用 ziplist 来编码,否则使用 linkedlist 编码(这两个条件值可以使用 list-max-ziplist-value 和 list-max-ziplist-entries 选项来配置):
(1)列表对象保存的所有字符串元素的长度都小于 64 字节。
(2)列表对象保存的元素数量小于 512 个。
当这两个条件有任何一个不满足时,使用 ziplist 编码的列表对象就会被转换成使用 linkedlist 编码,原本保存在压缩列表里的所有列表元素都会被转移并保存到双端链表里面。下面的代码片段阐明了这一点。
哈希对象的编码可以是 ziplist 或者 hashtable。ziplist 编码的哈希对象使用压缩列表作为底层实现。每当有新的键值对加入时,程序会依次将保存了键和值的压缩表节点推入到压缩表表尾。而 hashtable 编码的哈希对象使用字典作为底层实现,每个键值对都使用一个字典键值对来保存,而每个字典的键和值都是保存在一个字符串对象中。
类似于列表对象,使用 ziplist 编码的哈希对象也需要同时满足以下两个条件(同样可以通过 hash-max-ziplist-value 和 hash-max-ziplist-entries 选项来配置):
(1)哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节。
(2)哈希对象保存的键值对数量小于 512 个。
如果不能同时满足,则原本保存在压缩列表里的所有键值对都会被转移并保存到字典里面,对象的编码也会从 ziplist 变为 hashtable。
集合对象的编码可以是 intset 或者 hashtable。intset 编码的集合对象使用整数集合作为底层实现。hashtable 编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,表示一个集合元素,而字典的值则全部被设置为 NULL。
集合对象同时满足以下两个条件时,才使用 intset 编码,否则使用 hashtable 编码:
(1)集合对象保存的元素都是整数。
(2)集合对象的元素数量不超过 512 个(该值可以使用 set-max-intset-entries 选项修改)。
有序集合对象的编码可以是 ziplist 或者 skiplist。ziplist 编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素按分值从小到大使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个则保存元素的分值。skiplist 编码的有序集合对象使用如下的 zset 结构作为底层实现,一个 zset 结构同时包含一个字典和一个跳跃表:
zset 结构中的 zsl 跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:object 属性保存了元素的成员,score 属性则保存了元素的分值。通过该跳跃表,Redis 可以使用如 ZRANK、ZRANGE 等命令来对有序集合进行范围型操作。
zset 结构中的 dict 字典为有序集合创建了一个从成员到分值的映射,其中的每个键值对都保存了一个集合元素:键保存了元素的成员,值保存了元素的分值。通过该字典,Redis 可以使用如 ZSCORE 等命令在 O(1) 复杂度内查找给定成员的分值。
有序集合每个元素的成员都是一个字符串对象,而每个元素的分值都是一个 double 类型的浮点数。值得一提的是,为了节约内存,zset 结构中的跳跃表和字典其实是通过指针来共享相同元素的成员和分数。
使用 ziplist 编码的有序集合对象需要同时满足以下两个条件:
(1)有序集合的元素数量小于 128 个。
(2)有序集合的所有元素成员的长度都小于 64 字节。
当然,这两个值也可以分别通过 zset-max-ziplist-entries 和 zset-max-ziplist-value 选项来配置。
在 Redis 的五种类型的对象中,字符串对象是唯一一种会被其他四种类型对象嵌套的对象。字符串对象的编码可以是 int、raw 或者 embstr。
如果一个字符串对象保存的是整数值,并且该值可以使用 long 型表示,则该对象结构的 ptr 属性里面保存的就是整数值(会将 void* 转换成 long),并同时将其 encoding 属性设置为 int。但如果该整数值超过了 long 型所能表示的数值范围,则使用下面的 embstr 或者 raw 编码方式来表示。
如果字符串对象保存的是一个字符串值,并且其长度大于 32 字节,则字符串对象将使用一个简单动态字符串(SDS)结构来保存,同时将该对象的 encoding 属性设置为 raw。而如果字符串值的长度小于等于 32 字节,则使用的就是 embstr 编码的方式。
embstr 编码和 raw 编码一样,都使用 redisObject 结构和 sdshdr 结构来表示字符串对象,但 raw 编码会调用两次内存分配函数来分别创建这两个结构,而 embstr 编码则是调用一次内存分配函数来分配一块连续的空间,空间中依次包含 redisObject 和 sdshdr 两个结构。因此 embstr 编码的字符串对象在释放内存时也会少调用一次内存释放函数,同时使用连续的内存空间也能让字符串对象更好地利用缓存带来的优势。
此外,可以用 long double 类型表示的浮点数在 Redis 中也是作为字符串值来保存的,Redis 会在操作需要的时候将其转换回浮点数。至于使用的是 embstr 还是 raw 编码方式,同样需要根据将其转换成字符串后的长度而定。
但是一个字符串对象使用的编码方式并非是一成不变的,int 和 embstr 编码的字符串对象在条件满足的情况下,会被转换为 raw 编码的字符串对象。
对于 int 编码的字符串对象来说,当执行了一些命令(如 APPEND),使得该对象保存的不再是整数值时,对象的编码就会从 int 变为 raw。而对于 embstr 编码的字符串对象来说,由于 Redis 没有为之编写任何相应的修改接口,因此 embstr 编码的字符串对象实际上是只读的,对这样的字符串对象执行任何修改命令,都会先将其转换为 raw 编码的后再进行修改,最终的结果都是一个 raw 编码的字符串对象。下面的命令片段说明了这几点。
redis> SET number 10086 OK redis> OBJECT ENCODING number "int" redis> APPEND number " is a good number" (integer) 23 redis> OBJECT ENCODING number "raw" redis> SET msg "hello world" OK redis> OBJECT ENCODING msg "embstr" redis> APPEND msg " again!" (integer) 18 redis> OBJECT ENCODING msg "raw"
列表对象的编码可以是 ziplist 或者 linkedlist。ziplist 编码的列表对象使用压缩列表作为底层实现,每个压缩列表节点保存了一个列表元素。linkedlist 编码的列表对象使用双端链表作为底层实现,每个双端链表节点都保存了一个字符串对象,而每个字符串对象都保存了一个列表元素。
当列表对象同时满足以下两个条件时,列表对象使用 ziplist 来编码,否则使用 linkedlist 编码(这两个条件值可以使用 list-max-ziplist-value 和 list-max-ziplist-entries 选项来配置):
(1)列表对象保存的所有字符串元素的长度都小于 64 字节。
(2)列表对象保存的元素数量小于 512 个。
当这两个条件有任何一个不满足时,使用 ziplist 编码的列表对象就会被转换成使用 linkedlist 编码,原本保存在压缩列表里的所有列表元素都会被转移并保存到双端链表里面。下面的代码片段阐明了这一点。
# 所有元素的长度都小于 64 字节 redis> RPUSH blah "hello" "world" "again" (integer) 3 redis> OBJECT ENCODING blah "ziplist" # 将一个 65 字节长的元素推入到列表对象中 redis> RPUSH blah "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww" (integer) 4 redis> OBJECT ENCODING blah "linkedlist" # 列表对象包含 512 个元素 redis> EVAL "for i=1, 512 do redis.call('RPUSH', KEYS[1], i)end" 1 "integers" (nil) redis> LLEN integers (integer) 512 redis> OBJECT ENCODING integers "ziplist" # 再向列表对象推入一个新元素,使其元素数量达到 513 个 redis> RPUSH integers 513 (integer) 513 redis> OBJECT ENCODING integers "linkedlist"
哈希对象的编码可以是 ziplist 或者 hashtable。ziplist 编码的哈希对象使用压缩列表作为底层实现。每当有新的键值对加入时,程序会依次将保存了键和值的压缩表节点推入到压缩表表尾。而 hashtable 编码的哈希对象使用字典作为底层实现,每个键值对都使用一个字典键值对来保存,而每个字典的键和值都是保存在一个字符串对象中。
类似于列表对象,使用 ziplist 编码的哈希对象也需要同时满足以下两个条件(同样可以通过 hash-max-ziplist-value 和 hash-max-ziplist-entries 选项来配置):
(1)哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节。
(2)哈希对象保存的键值对数量小于 512 个。
如果不能同时满足,则原本保存在压缩列表里的所有键值对都会被转移并保存到字典里面,对象的编码也会从 ziplist 变为 hashtable。
集合对象的编码可以是 intset 或者 hashtable。intset 编码的集合对象使用整数集合作为底层实现。hashtable 编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,表示一个集合元素,而字典的值则全部被设置为 NULL。
集合对象同时满足以下两个条件时,才使用 intset 编码,否则使用 hashtable 编码:
(1)集合对象保存的元素都是整数。
(2)集合对象的元素数量不超过 512 个(该值可以使用 set-max-intset-entries 选项修改)。
有序集合对象的编码可以是 ziplist 或者 skiplist。ziplist 编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素按分值从小到大使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个则保存元素的分值。skiplist 编码的有序集合对象使用如下的 zset 结构作为底层实现,一个 zset 结构同时包含一个字典和一个跳跃表:
typedef struct zset{ zskiplist *zsl; dict *dict; }zset;
zset 结构中的 zsl 跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:object 属性保存了元素的成员,score 属性则保存了元素的分值。通过该跳跃表,Redis 可以使用如 ZRANK、ZRANGE 等命令来对有序集合进行范围型操作。
zset 结构中的 dict 字典为有序集合创建了一个从成员到分值的映射,其中的每个键值对都保存了一个集合元素:键保存了元素的成员,值保存了元素的分值。通过该字典,Redis 可以使用如 ZSCORE 等命令在 O(1) 复杂度内查找给定成员的分值。
有序集合每个元素的成员都是一个字符串对象,而每个元素的分值都是一个 double 类型的浮点数。值得一提的是,为了节约内存,zset 结构中的跳跃表和字典其实是通过指针来共享相同元素的成员和分数。
使用 ziplist 编码的有序集合对象需要同时满足以下两个条件:
(1)有序集合的元素数量小于 128 个。
(2)有序集合的所有元素成员的长度都小于 64 字节。
当然,这两个值也可以分别通过 zset-max-ziplist-entries 和 zset-max-ziplist-value 选项来配置。
发表评论
-
Lua 脚本
2019-10-07 19:49 667Redis 2.6 版本开始引入对 Lua 脚 ... -
Redis事务的实现
2019-09-22 18:56 467Redis 事务是 ... -
Redis集群之复制、故障转移及消息实现
2019-09-14 21:04 497在Redis集群 ... -
Redis集群实现原理
2019-09-14 12:19 663Redis 集群是 Redis 提供的分布式数 ... -
sentinel 系统介绍
2019-08-04 18:35 500Sentinel(哨兵)是 Redis 的高可 ... -
数据库复制
2019-07-13 22:02 365在连接到一 ... -
redis 客户端实现
2019-06-02 15:06 371Redis 服务器是典型的一对多服务器程序,通 ... -
AOF 持久化
2019-05-12 13:36 414除了前面提到的 RDB 持久化功能外,Redi ... -
RDB 文件结构
2019-04-27 12:10 576在RDB 持久化一节中,我们对 RDB 持久化 ... -
RDB 持久化
2019-04-14 17:20 419RDB 持久化功能可以将 Redis 在某个时 ... -
Redis 数据库通知功能的实现
2019-04-07 11:56 1282Reids 数据库通知功能可以让客户端通过订阅 ... -
数据库实现
2019-03-24 13:58 438Redis 服务器将其所有的数据库都保存在 r ... -
Redis 对象系统概览
2019-01-06 13:10 777前面介绍了 Redis 中用到的所有主要数据结 ... -
整数集合与压缩列表
2018-12-09 21:19 592在 Redis 中,当一 ... -
跳跃表在 Redis 中的应用
2018-08-23 16:30 2023前提申明,因篇幅 ... -
字典实现
2018-08-20 15:49 565字典在 Redis 中的应用相当广泛,如 Redis ... -
redis 字符串和列表实现
2018-08-08 16:41 748Redis 虽说由 C 语言 ...
相关推荐
综上所述,Redis的五种数据类型各有其特点和适用场景。在实际应用中,可以根据具体需求选择最合适的数据类型来存储和操作数据。同时,掌握每种数据类型的实现方式和操作细节对于优化程序性能、提升数据处理效率也是...
Redis数据结构与对象总结 数据结构与对象 简单动态字符串 SDS简介 SDS与C字符串的区别 常数复杂度获取字符串长度 O(n) O(1) 杜绝缓冲区溢出 修改字符串长度时内存重分配 空间预分配:对字符串进行增长操作时...
总结:本教程详细介绍了Redis的五种数据类型在Java中的应用,包括字符串、哈希、列表、集合和有序集合。通过实例代码展示了如何使用Jedis API进行增删查改操作。对于Java开发者来说,掌握这些内容对于提升项目中的...
- Redis 支持五种基本数据类型:字符串(String)、哈希表(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。每种类型的数据在内部都有特定的表示方式。 - 对于字符串,Redis 可以直接存储原始字节...
C#操作Redis的5种基本类型汇总 以下是C#操作Redis的5种基本类型的知识点总结: 一、String类型 * 简介:String是Redis最基本的类型,可以理解成与Memcached一样的类型,一个key对应一个value。String类型是二进制...
Redis是一个开源的使用ANSI C编写的高性能键值对数据库,通常被称为数据结构服务器。它被广泛用于构建高性能的web应用、缓存、消息队列等场景。PHPRedis是Redis的一个PHP扩展模块,提供了丰富的API接口用于与Redis...
"Java在Redis中的对象缓存详解" 通过本篇文章,我们可以了解到Java在Redis中的对象缓存机制。缓存机制是指在应用程序中,通过将频繁访问的数据存储在高速缓存中,以提高应用程序的性能和响应速度。Redis是一个开源...
C# StackExchange.Redis 操作封装类库,分别封装了Redis五大数据结构(String,Hash,List,Set,ZSet)的增删改查的操作方法,支持Async异步操作。支持Redis分库操作。支持信息队列操作。 带有单元测试,为每个...
标题中的“使用redis管理对象缓存,可代替session”指的是在Web应用中,利用Redis作为对象缓存系统来替代传统的HTTP Session。Redis是一款高性能的Key-Value存储系统,它可以用来存储临时性的数据,如用户的Session...
1. **数据类型**:Redis的五大数据类型为字符串、哈希、列表、集合和有序集合,每种类型都有其特定的用途,如字符串适合存储简单的值,哈希用于存储对象,列表可以作为队列或栈,集合用于成员关系,有序集合则带有...
Redis是一种开源、高性能的键值对数据存储系统,常用于缓存、消息队列等场景。WPF是.NET Framework的一部分,用于构建桌面应用程序的用户界面。 **描述分析:** 描述提到"C#简单操作Redis",这意味着我们将使用C#...
Redis是一种高性能的键值对内存数据库,常用于缓存、数据持久化以及实时数据分析等场景。它的全称是Remote Dictionary Server,由Salvatore Sanfilippo创建,最初是为了解决他在Web应用中的数据存储问题。Redis的...
本文将对五种常见的PHP缓存加速器进行分析,包括Memcached、eAccelerator、APC(Alternative PHP Cache)、Xcache以及Redis,以帮助理解它们的特点和适用场景。 首先,Memcached是一个分布式内存对象缓存系统,常...
总结而言,Redis作为一种优秀的NoSQL数据库,它的使用非常广泛。它的特点包括高可用、高性能、支持数据持久化、支持丰富的数据类型和事务操作等。通过本篇文章的学习,希望能够帮助读者快速上手Redis,并能将其有效...
而C++是一种静态类型的、编译式的、通用的、大小写敏感的、不仅支持过程化编程,也支持面向对象编程的程序设计语言。在C++中操作Redis,可以充分利用C++的灵活性和Redis的高效性,为应用程序提供强大的数据支持。 ...
Redis是一种高性能的键值对数据存储系统,常用于构建缓存、消息队列以及数据库等应用场景。它以内存中的数据结构存储数据,并可持久化到硬盘,以保证数据的可靠性。Redis支持丰富的数据类型,包括字符串(Strings)、...
Redis 支持五种基本数据类型:字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。每种类型都有其特定的应用场景,如字符串可用来存储简单值,哈希适合存储对象,列表可实现消息...
4. 持久化管理:查看和管理RDB和AOF两种持久化策略的设置和执行情况。 5. 监控与报警:监控Redis服务器的状态,包括内存使用、CPU占用、连接数等,并在达到预设阈值时发出警告。 6. 性能分析:分析Redis服务器的性能...
SpringBoot中利用Redis实现消息队列,代码亲测可用, 可以传输字符串,或java对象都可以