1、简介

Redis的五大数据类型也称五大数据对象;前面介绍过6大数据结构,Redis并没有直接使用这些结构来实现键值对数据库,而是使用这些结构构建了一个对象系统redisObject;这个对象系统包含了五大数据对象,字符串对象(string)、列表对象(list)、哈希对象(hash)、集合(set)对象和有序集合对象(zset);而这五大对象的底层数据编码可以用命令OBJECT ENCODING来进行查看。

redisObject结构

1 typedef structredisObject {2 //类型

3 unsigned type:4;4 //编码

5 unsigned encoding:4;6 //指向底层实现数据结构的指针

7 void *ptr;8 //...

9 } robj;

redis是以键值对存储数据的,所以对象又分为键对象和值对象,即存储一个key-value键值对会创建两个对象,键对象和值对象。

键对象总是一个字符串对象,而值对象可以是五大对象中的任意一种。

type属性存储的是对象的类型,也就是我们说的 string、list、hash、set、zset中的一种,可以使用命令 TYPE key 来查看。

encoding属性记录了队形所使用的编码,即这个对象底层使用哪种数据结构实现。

表中列出了底层编码常量及对应的OBJECT ENCODING 命令的输出,前三项都是字符串结构

我们在存入key-value键值对时并不会指定对象的encoding,而是Redis会根据不统的使用场景来为一个对象设置不同的编码,可以达到节约内存、加快访问速度等目的。

2、字符串对象(string)

字符串对象底层数据结构实现为简单动态字符串(SDS)和直接存储,但其编码方式可以是int、raw或者embstr,区别在于内存结构的不同。

(1)int编码

字符串保存的是整数值,并且这个正式可以用long类型来表示,那么其就会直接保存在redisObject的ptr属性里,并将编码设置为int,如图:

(2)raw编码

字符串保存的大于32字节的字符串值,则使用简单动态字符串(SDS)结构,并将编码设置为raw,此时内存结构与SDS结构一致,内存分配次数为两次,创建redisObject对象和sdshdr结构,如图:

(3)embstr编码

字符串保存的小于等于32字节的字符串值,使用的也是简单的动态字符串(SDS结构),但是内存结构做了优化,用于保存顿消的字符串;内存分配也只需要一次就可完成,分配一块连续的空间即可,如图:

字符串对象总结:

在Redis中,存储long、double类型的浮点数是先转换为字符串再进行存储的。

raw与embstr编码效果是相同的,不同在于内存分配与释放,raw两次,embstr一次。

embstr内存块连续,能更好的利用缓存在来的优势

int编码和embstr编码如果做追加字符串等操作,满足条件下会被转换为raw编码;embstr编码的对象是只读的,一旦修改会先转码到raw。

3、列表对象(list)

列表对象的编码可以是ziplist和linkedlist之一。

(1) ziplist编码

ziplist编码的哈希随想底层实现是压缩列表,每个压缩里列表节点保存了一个列表元素。

(2)linkedlist编码

linkedlist编码底层采用双端链表实现,每个双端链表节点都保存了一个字符串对象,在每个字符串对象内保存了一个列表元素。

列表对象编码转换:

列表对象使用ziplist编码需要满足两个条件:一是所有字符串长度都小于64字节,二是元素数量小于512,不满足任意一个都会使用linkedlist编码。

两个条件的数字可以在Redis的配置文件中修改,list-max-ziplist-value选项和list-max-ziplist-entries选项。

图中StringObject就是上一节讲到的字符串对象,字符串对象是唯一个在五大对象中作为嵌套对象使用的。

4、哈希对象(hash)

哈希对象的编码可以是ziplist和hashtable之一。

(1)ziplist编码

ziplist编码的哈希对象底层实现是压缩列表,在ziplist编码的哈希对象中,key-value键值对是以紧密相连的方式放入压缩链表的,先把key放入表尾,再放入value;键值对总是向表尾添加。

(2)hashtable编码

hashtable编码的哈希对象底层实现是字典,哈希对象中的每个key-value对都使用一个字典键值对来保存。

字典键值对即是,字典的键和值都是字符串对象,字典的键保存key-value的key,字典的值保存key-value的value。

哈希对象编码转换:

哈希对象使用ziplist编码需要满足两个条件:一是所有键值对的键和值的字符串长度都小于64字节;二是键值对数量小于512个;不满足任意一个都使用hashtable编码。

以上两个条件可以在Reids配置文件中修改hash-max-ziplist-value选项和hash-max-ziplist-entries选项。

5、集合对象(set)

集合对象的编码可以是intset和hashtable之一。

(1)intset编码

intset编码的集合对象底层实现是整数集合,所有元素都保存在整数集合中。

(2)hashtable编码

hashtable编码的集合对象底层实现是字典,字典的每个键都是一个字符串对象,保存一个集合元素,不同的是字典的值都是NULL;可以参考java中的hashset结构。

集合对象编码转换:

集合对象使用intset编码需要满足两个条件:一是所有元素都是整数值;二是元素个数小于等于512个;不满足任意一条都将使用hashtable编码。

以上第二个条件可以在Redis配置文件中修改et-max-intset-entries选项。

6、有序集合对象(zset)

有序集合的编码可以是ziplist和skiplist之一。

(1)ziplist编码

ziplist编码的有序集合对象底层实现是压缩列表,其结构与哈希对象类似,不同的是两个紧密相连的压缩列表节点,第一个保存元素的成员,第二个保存元素的分值,而且分值小的靠近表头,大的靠近表尾。

(2)skiplist编码

skiplist编码的有序集合对象底层实现是跳跃表和字典两种;

每个跳跃表节点都保存一个集合元素,并按分值从小到大排列;节点的object属性保存了元素的成员,score属性保存分值;

字典的每个键值对保存一个集合元素,字典的键保存元素的成员,字典的值保存分值。

为何skiplist编码要同时使用跳跃表和字典实现?

跳跃表优点是有序,但是查询分值复杂度为O(logn);字典查询分值复杂度为O(1) ,但是无序,所以结合连个结构的有点进行实现。

虽然采用两个结构但是集合的元素成员和分值是共享的,两种结构通过指针指向同一地址,不会浪费内存。

有序集合编码转换:

有序集合对象使用ziplist编码需要满足两个条件:一是所有元素长度小于64字节;二是元素个数小于128个;不满足任意一条件将使用skiplist编码。

以上两个条件可以在Redis配置文件中修改zset-max-ziplist-entries选项和zset-max-ziplist-value选项。

7、总结

在Redis的五大数据对象中,string对象是唯一个可以被其他四种数据对象作为内嵌对象的;

列表(list)、哈希(hash)、集合(set)、有序集合(zset)底层实现都用到了压缩列表结构,并且使用压缩列表结构的条件都是在元素个数比较少、字节长度较短的情况下;

四种数据对象使用压缩列表的优点:

(1)节约内存,减少内存开销,Redis是内存型数据库,所以一定情况下减少内存开销是非常有必要的。

(2)减少内存碎片,压缩列表的内存块是连续的,并分配内存的次数一次即可。

(3)压缩列表的新增、删除、查找操作的平均时间复杂度是O(N),在N再一定的范围内,这个时间几乎是可以忽略的,并且N的上限值是可以配置的。

(4)四种数据对象都有两种编码结构,灵活性增加。

参考:

《Redis设计与实现》黄健宏著,网上对Redis的详解等

此博客为笔者使用redis很久之后,参考网络上各类文章总结性书写,原创手打,如有错误欢迎指正。

redis的zset的底层实现_Redis(三)--- Redis的五大数据类型的底层实现相关推荐

  1. Redis(三)【五大数据类型三种特殊数据类型】

    目录 三. 五大数据类型 Redis-Key String(字符串) List(列表) Set(集合) Hash(哈希) Zset(有序集合) 6. 三种特殊数据类型 geospatial 地理位置 ...

  2. redis种类型对应java类型_Redis的五种基本数据类型介绍

    Redis作为缓存具有极其丰富的功能,比如计数器.好友关系以及排行榜等等.而Redis之所能够实现如此强大的功能,完全是依赖着它的基本数据结构.今天我们来看看Redis的五种基本的数据结构,分别是字符 ...

  3. redis 五大数据类型

    文章目录 一.Redis-Key 二.String 三.List 四. Set ( 集合 ) 五.Hash(哈希) 六.Zset(有序集合) 视频链接 官网: https://redis.io/ 中文 ...

  4. Redis中ZSet的底层数据结构跳跃表skiplist,你真的了解吗?

    欢迎大家关注我的微信公众号[老周聊架构],Java后端主流技术栈的原理.源码分析.架构以及各种互联网高并发.高性能.高可用的解决方案. 一.前言 老周写这篇文章的初衷是这样的,之前项目中有大量使用 R ...

  5. 底层实现_Redis有序集合zset的底层实现

    1. 编码 zset的编码有ziplist和skiplist两种. 底层分别使用ziplist(压缩链表)和skiplist(跳表)实现. 什么时候使用ziplist什么时候使用skiplist? 当 ...

  6. redis 图片2进制保存_Redis数据结构底层的SDS了解吗

    面试场景 面试官:Redis有哪些数据类型? 我:String,List,set,zset,hash 面试官:没了? 我:哦哦哦,还有HyperLogLog,bitMap,GeoHash,BloomF ...

  7. redis存10万条数据_redis详细介绍

    一 介绍 1. redis介绍(redis安装在磁盘,redsi数据存储在内存) 服务器交互 2. Redis是一种基于键值对(key-value)数据库,其中value可以为string. hash ...

  8. redis五种数据类型的应用场景_Redis五种不同的数据类型

    一.redis集群测试环境搭建 参考文章:https://www.jianshu.com/p/0a2f8f80983a redis-cli -c -h 10.96.87.129 -p 7001注意:- ...

  9. 配置文件存int类型_Redis详解(五)------ redis的五大数据类型实现原理

    > 本系列教程持续更新,可以微信搜索「 IT可乐 」第一时间阅读.回复<电子书>有我为大家特别筛选的书籍资料 前面两篇博客,第一篇介绍了五大数据类型的基本用法,第二篇介绍了Redis ...

最新文章

  1. flutter怎么手动刷新_flutter局部刷新的实现示例
  2. linux自动运行python脚本,执行脚本如何在linux环境下自启动
  3. 专 linux命令之set x详解
  4. 【Linux系统编程】进程间通信之共享内存
  5. OpenGL函数:wglCreateContext
  6. GDB分析PHP连接Memcached 导致coredump问题
  7. (Redis_学习一)Redis关于string类型和hash类型数据操作
  8. 重启apache下php,linux下apache重启并查看php环境
  9. git配置取消代理_「高手」如何优雅的解决 git 超时
  10. 调整home和根分区大小
  11. MySQL常用系统表
  12. 学生个人网页制作html代码
  13. 根据经纬度获取精确地址 (百度地图)
  14. JAVA定时调度框架Quartz使用案例
  15. 最落魄的日子你是怎样熬过来的
  16. 一次苦中作乐的追码过程(上)
  17. 网工神器:PNETLab模拟器踩坑过程
  18. EasyExcel 导出 excel(二)添加序号列,设置excel打印样式,导出即可打印
  19. Vladik and fractions
  20. 传感器自学笔记第八章——DHT11温湿度传感器(附带自己写的很好用的51单片机DHT11代码模板,参数列表只有一个字符数组指针)

热门文章

  1. 简单了解tengine
  2. Bootstrap 排版
  3. MySQL 迁移到半同步模式
  4. 都是大人物,看看你认识几个。
  5. linux编译源码问题 环境变量的设置
  6. ASP.NET 2.0+Atlas编写鼠标拖放程序
  7. 黑苹果 wifi android,动动手指零负担让你的黑苹果连上Wifi
  8. 3d制作中需要注意的问题_浅谈线路板制作时需要注意的问题
  9. 600. 不含连续1的非负整数
  10. Python-strace命令追踪ssh操作