`

Redis 五种对象

阅读更多
        阅读本节前需要阅读 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 编码的字符串对象。下面的命令片段说明了这几点。
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 选项来配置。
分享到:
评论

相关推荐

    Redis数据结构与对象总结

    Redis数据结构与对象总结 数据结构与对象 简单动态字符串 SDS简介 SDS与C字符串的区别 常数复杂度获取字符串长度 O(n) O(1) 杜绝缓冲区溢出 修改字符串长度时内存重分配 空间预分配:对字符串进行增长操作时...

    C# StackExchange.Redis 操作封装类库

    C# StackExchange.Redis 操作封装类库,分别封装了Redis五大数据结构(String,Hash,List,Set,ZSet)的增删改查的操作方法,支持Async异步操作。​支持Redis分库操作。支持信息队列操作。 带有单元测试,为每个...

    redis,phpredis中文手册

    redis,phpredis,redis手册,phpredis中文手册,redis使用说明以及一些php实现的例子

    3.Redis数据类型之List类型

    3.Redis数据类型之List类型

    详解Java在redis中进行对象的缓存

    主要介绍了Java在redis中进行对象的缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    rob:使用 Redis 使 Python 对象持久化

    具有 Redis 后端的持久性 Python 对象。 pip install rob 对象 对字典进行 JSON 转储并将其保存在 Redis 哈希中的对象。 需要定义HASH_KEY - 散列的键。 哈希对象 将其字典保存在 Redis 哈希中的对象。 使用 ...

    78.redis存储对象的方式.avi

    redis存储对象的方式.avi

    Redis如何存储对象与集合示例详解

    这里主要讲redis如何把对象,集合存入,并且取出。下面话不多说了,来一起看看详细的介绍吧。 1.在启动类上加入如下代码 private Jedis jedis;private JedisPoolConfig config;private JedisShardInfo sharInfo;@...

    Redis,redis封装核心方法

    Redis常用方法封装核心类;对象序列化和反序列化;RedisSession 用于微信分部署session操作;Redis数据源操作接口;...针对redis缓存技术进行了封装,对象类型存贮封装了序列化,redis穿透的处理。

    SpringBoot中利用Redis实现消息队列,代码亲测可用, 可以传输字符串,或java对象都可以

    SpringBoot中利用Redis实现消息队列,代码亲测可用, 可以传输字符串,或java对象都可以

    redis字节码存压缩对象

    redis字节码存压缩对象,方便开发工具类,提高开发速度,希望有所帮助,多多交流希望有所帮助,多多交流

    使用.Net 技术操作Redis缓存技术,对Redis缓存进行存储增删改查等相关操作

    使用.Net 技术操作Redis缓存技术,对Redis缓存进行存储增删改查等相关操作

    StackExchange.Redis.zip

    StackExchange.Redis 中核心对象是在 StackExchange.Redis 命名空间中的 ConnectionMultiplexer 类,这个对象隐藏了多个服务器的详细信息。 因为ConnectionMultiplexer要做很多事,它被设计为在调用者之间可以共享和...

    redis可视化工具

    Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。绿色免费可用,这是redis的可视化工具,也可以输入命令

    wp-redis:使用Redis的WordPress对象缓存

    WP Redis 使用Redis的WordPress对象缓存。 由Alley Interactive提供。先决条件 设置将object-cache.php安装到wp-content/object-cache.php 。 在wp-config.php文件中,添加服务器凭据: $redis_server = array( '...

    redis 客户端

    在学习 redis的时候,就利用空闲时间写出来redisClient 的工具类,该工具类重要用于对 redis 集群的操作,不仅可以对对象String对象进行操作,也可以对 Object 进行操作。希望对大家有所帮助。

    Redis的.net客户端StackExchange.Redis.zip

    三种命令模式Sync vs Async vs Fire-and-Forget最后,这里有三种命令模式分别对应 StackExchange.Redis的三类不同的使用场景。Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。Async,异步模式直接走的是...

    spring + redis集群

    采用spring-data-redis 搭建redis集群,代码包含redis工具类,可存储对象集合,maven项目,部署可运行。

    redis配置中文注释

    redis配置中文注释,大家看看吧,网上找了一部分,自己写了一部分,应该没啥问题

Global site tag (gtag.js) - Google Analytics