- 浏览: 131758 次
文章分类
最新评论
阅读本节前需要阅读 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 586Redis 2.6 版本开始引入对 Lua 脚 ... -
Redis事务的实现
2019-09-22 18:56 420Redis 事务是 ... -
Redis集群之复制、故障转移及消息实现
2019-09-14 21:04 451在Redis集群 ... -
Redis集群实现原理
2019-09-14 12:19 591Redis 集群是 Redis 提供的分布式数 ... -
sentinel 系统介绍
2019-08-04 18:35 452Sentinel(哨兵)是 Redis 的高可 ... -
数据库复制
2019-07-13 22:02 336在连接到一 ... -
redis 客户端实现
2019-06-02 15:06 331Redis 服务器是典型的一对多服务器程序,通 ... -
AOF 持久化
2019-05-12 13:36 370除了前面提到的 RDB 持久化功能外,Redi ... -
RDB 文件结构
2019-04-27 12:10 534在RDB 持久化一节中,我们对 RDB 持久化 ... -
RDB 持久化
2019-04-14 17:20 373RDB 持久化功能可以将 Redis 在某个时 ... -
Redis 数据库通知功能的实现
2019-04-07 11:56 1243Reids 数据库通知功能可以让客户端通过订阅 ... -
数据库实现
2019-03-24 13:58 399Redis 服务器将其所有的数据库都保存在 r ... -
Redis 对象系统概览
2019-01-06 13:10 740前面介绍了 Redis 中用到的所有主要数据结 ... -
整数集合与压缩列表
2018-12-09 21:19 552在 Redis 中,当一 ... -
跳跃表在 Redis 中的应用
2018-08-23 16:30 1993前提申明,因篇幅 ... -
字典实现
2018-08-20 15:49 522字典在 Redis 中的应用相当广泛,如 Redis ... -
redis 字符串和列表实现
2018-08-08 16:41 717Redis 虽说由 C 语言 ...
相关推荐
Redis数据结构与对象总结 数据结构与对象 简单动态字符串 SDS简介 SDS与C字符串的区别 常数复杂度获取字符串长度 O(n) O(1) 杜绝缓冲区溢出 修改字符串长度时内存重分配 空间预分配:对字符串进行增长操作时...
C# StackExchange.Redis 操作封装类库,分别封装了Redis五大数据结构(String,Hash,List,Set,ZSet)的增删改查的操作方法,支持Async异步操作。支持Redis分库操作。支持信息队列操作。 带有单元测试,为每个...
redis,phpredis,redis手册,phpredis中文手册,redis使用说明以及一些php实现的例子
3.Redis数据类型之List类型
主要介绍了Java在redis中进行对象的缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
具有 Redis 后端的持久性 Python 对象。 pip install rob 对象 对字典进行 JSON 转储并将其保存在 Redis 哈希中的对象。 需要定义HASH_KEY - 散列的键。 哈希对象 将其字典保存在 Redis 哈希中的对象。 使用 ...
redis存储对象的方式.avi
这里主要讲redis如何把对象,集合存入,并且取出。下面话不多说了,来一起看看详细的介绍吧。 1.在启动类上加入如下代码 private Jedis jedis;private JedisPoolConfig config;private JedisShardInfo sharInfo;@...
Redis常用方法封装核心类;对象序列化和反序列化;RedisSession 用于微信分部署session操作;Redis数据源操作接口;...针对redis缓存技术进行了封装,对象类型存贮封装了序列化,redis穿透的处理。
SpringBoot中利用Redis实现消息队列,代码亲测可用, 可以传输字符串,或java对象都可以
redis字节码存压缩对象,方便开发工具类,提高开发速度,希望有所帮助,多多交流希望有所帮助,多多交流
使用.Net 技术操作Redis缓存技术,对Redis缓存进行存储增删改查等相关操作
StackExchange.Redis 中核心对象是在 StackExchange.Redis 命名空间中的 ConnectionMultiplexer 类,这个对象隐藏了多个服务器的详细信息。 因为ConnectionMultiplexer要做很多事,它被设计为在调用者之间可以共享和...
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。绿色免费可用,这是redis的可视化工具,也可以输入命令
WP Redis 使用Redis的WordPress对象缓存。 由Alley Interactive提供。先决条件 设置将object-cache.php安装到wp-content/object-cache.php 。 在wp-config.php文件中,添加服务器凭据: $redis_server = array( '...
在学习 redis的时候,就利用空闲时间写出来redisClient 的工具类,该工具类重要用于对 redis 集群的操作,不仅可以对对象String对象进行操作,也可以对 Object 进行操作。希望对大家有所帮助。
三种命令模式Sync vs Async vs Fire-and-Forget最后,这里有三种命令模式分别对应 StackExchange.Redis的三类不同的使用场景。Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。Async,异步模式直接走的是...
采用spring-data-redis 搭建redis集群,代码包含redis工具类,可存储对象集合,maven项目,部署可运行。
redis配置中文注释,大家看看吧,网上找了一部分,自己写了一部分,应该没啥问题