Redis 基础——五大类型与数据结构

引言

Redis 区分于 memcahced 的一个重要不同就是它具有明确的类型概念,在Redis 的使用过程中,都离不开这些类型的学习,它不仅是 Redis 能力的基础,同时也是一些重要数据结构和算法思想的体现。

本博客总结了五大类型的书面重点,帮助快速梳理和总结 Redis 类型相关的知识点,理论性和记忆性较强。可以作为 Redis 数据类型的学习大纲,建议在实践之前牢记这些知识。

一、Redis简介

在开始之前,回顾一下redis的介绍性知识。

redis的底层语言是C,它是一种高性能键值对、NoSQL内存数据库。可以用作缓存、数据库、消息中间件、分布式锁等。

它的几大优点:

1、性能优秀:内存中运行,读写速度快,支持10W并发QPS。

2、单进程单线程:线程安全,采用IO多路复用机制。

3、丰富的数据结构:五大数据类型,类型检查和命令多态。

4、数据持久化:AOF和RDB,以及混用模式。

5、高可用方案:主从复制、哨兵模式等。

6、适合多种分布式业务场景:消息中间件、分布式锁、消息订阅发布等等。

二、键值存储对象 —— RedisObject

Redis 中使用 redisObject 对象来表示数据库中的 key(始终是字符串对象)和 value(五种对象类型的任意一种)。

每次在 Redis 中新创建一个键值对时,它至少会创建两个对象(键对象、值对象)。

redisObject 包含几个重要的属性:

type 属性记录对象类型——五大类型;

encoding 属性记录对象所使用的编码,即对象的底层实现是怎样的数据结构;

ptr 属性指向对象的底层数据结构,这些数据结构由encoding决定;

refcount 属性记录对象的引用计数,redis 可以改变这个值是否 = 0 来决定是否回收对象内存;同时,它也是实现对象共享机制的基础。

lru 属性记录对象最后一次被命令访问的时间。

三、五大基本类型

一般我们说Redis中的数据类型通常指值对象的类型,因为键始终是字符串对象。

对象类型由 redisObject 中的 type 属性记录,它有以下五种类型,可以使用 TYPE 命令查看对象类型:

TYPE keyname

五大基本类型

1、String :最基本的类型,二进制安全可以存储包括图片等文件格式,编码方式有raw、int 等。最大能够存储512M。

2、Hash :键值对集合对象,类似Java 中的 Map,但键值都得是字符串。适合存储对象信息,且支持更改某一项属性。

3、List :简单的字符串列表,底层实现是双向链表。按照插入顺序排序,操作分为左右,如 LPUSH、RPUSH等。可以用作消息队列模型。

4、Set :无序、不可重复字符串集合。通过 hashtable实现。增删查都是O(1)复杂度,支持交、并、差集操作。

5、ZSet:有序、不可重复字符串集合。通过 hashtable 和 skiplist 实现。可以根据 Double 类型的 score 从小到大排序。

三、八种编码方式

对象编码表示 Redis 以何种结构结构存储数据,由 redisObject 的 encoding 属性记录。

编码方式并不一定表示某种具体的数据结构,例如 skiplist 编码的 ZSet 对象,底层实际使用了字典+跳跃表的复合结构。

Redis 为何要将数据类型拆分为 type 和 encoding 呢?

对象类型不关联固定的编码,是为了提升redis的灵活性和效率,同时也有性能方面的考虑。

Redis可以根据不同的使用场景为一个对象设置不同的编码,从而优化对象在某一场景下的效率。例如,在列表对象包含元素较少时,使用 ziplist,它比 linkedlist 更节约内存,在内存中以连续的方式保存数据,可以更快的载入到缓存中。但如果 List 中的元素越来越多,就会使用 linkedlist,它更适合保存大量元素的场景。

编码方式有 8 种:

int、embstr、raw、hashtable、linkedlist、ziplist、intset、skiplist

可以使用 OBJECT ENCODING k1 来查看 key 的值对象的编码方式。

它们与类型的关系如下:

String :int、embstr、raw

Hash :ziplisthashtable

List :ziplist、linkedlist

Set :intset、hashtable

ZSet  :ziplist、skiplist

四、字符串

39个字节区分 raw 和 embstr (<=39)编码,embstr 编码是专门用于保存短字符串的一种优化编码方式。

对于某些浮点数字符串,在执行类似 INCRBYFLOAT命令时,会先将类型转化为浮点数,执行运算操作后,再转换回字符串。

编码转换 :int 和 embstr 在某些条件下会转为 raw

  • int :在执行某些命令后,使得值不再是一个整数(如APPEND),那么编码会从int转为raw。
  • embstr:它实际上是只读的,当对embstr执行修改时,Redis 一定会将其转为 raw,再执行修改命令。

五、哈希

Hash 对象的编码可以是 ziplist 或 hashtable。

ziplist:是一种连续的数据结构,类似数组,当以 ziplist 存储键值对时,它们会以 k-v-k-v... 的形式间隔存入,因此同一键值对的key和value总是紧挨着的。

hashtable:意为“字典”,它以数组保存所有键值对,每对键值都被封装为一个叫 entry 的结构,这与Java中的HashMap非常类似。

编码转换:当所有键和值的字符串长度小于64字节,且键值对数量小于512个时,使用ziplist编码;否则,使用hashtable编码。当然,这两个条件的上限是可以修改的。

六、列表

List 对象的编码可以是 ziplist 或 linkedlist。

ziplist:同 hash类型。

linkedlist:是一种双端链表结构,每个链表节点都会包含一个字符串对象,这是一种嵌套字符串行为,字符串对象是Redis五种类型中唯一一种会被其他四种类型对象嵌套的对象。

也就是说,五种类型对象的键和值都只能是字符串相关的数据结构。

 编码转换:当所有元素长度都小于64字节,且元素个数小于512个时,使用ziplist;否则,使用 linkedlist。限制条件与hash对象是相同的。

七、集合

Set 对象的编码可以是 intset 或 hashtable。

intset:代表一个整数集合。

hashtable:在实现set时,字典的每个键保存了一个元素,而字典的值全部都为NULL。在 Java 中,也会使用 HashMap 来实现 HashSet,不过,在Java中,为了避免空指针,每个 Entry 的值并不是 null,而是都指向了同一个空的 Object。

 编码转换:当所有元素都是整数,且元素个数不超过512个时,使用 intset;否则,使用 hashtable。

八、有序集合

ZSet 对象的编码可以是 ziplist 或 skiplist。

ziplist:每个集合元素使用两个紧挨在一起的节点来保存,前节点保存元素的成员,后节点保存分数score。

skiplist:是一个复合结构——字典 + 跳跃表。它们会引用共享的数据,不会造成重复存储的情况。跳跃表可以按分数顺序存储所有元素,程序可以基于此对有序集合进行范围操作:ZRANK、ZRANGE等;

字典创建了从成员到分数的映射,程序可以用O(1)查找给定成员的分数,如:ZSCORE等。

为什么ZSet 要同时使用跳跃表和字典来实现呢?

单独使用其中一种都达不到同时使用两种结构的性能。可以说这两种结构的结合弥补了有序结构在查找与范围搜索上的先天不足。因此,为了让有序集合在查找和范围操作都尽可能快,Redis 选择了同时使用字典和跳跃表两种数据结构来实现ZSet。

编码的转换:当元素个数小于128,所有元素长度都小于64字节时,使用ziplist;否则使用skiplist编码。 

九、Redis 的类型检查和命令多态

Redis中用于操作key的命令可以分为两类:对全部类型都可用只对特定类型可用

全部类型可用:DEL、EXPIRE、RENAME、TYPE、OBJECT等。

特定类型可用:SET、GET、APPEND、HDEL、RPUSH、SADD、ZADD等等。

9.1 类型检查的实现

为了保证只有特定类型的key可以执行某些特定命令,在执行特定命令之前,redis会先检查key 所对应的value的类型,然后决定是否执行。这种类型检查是通过redisObject的type属性来实现的。

9.2 多态命令的实现

redis会根据值对象的编码,选择正确的“命令实现代码”来执行命令。

例如,List 的编码有 ziplist 和 linkedlist 两种,Redis 会根据encoding的不同,在执行LLEN命令时,考虑使用ziplistlen函数还是使用listlength函数。

以面向对象的术语来说,LLEN命令是多态的

十、内存回收与对象共享

Redis 使用引用计数来实现对象内存空间的回收。

每个值对象上都有一个引用计数——refcount,Redis 可以通过增加或减少引用计数来实现内存回收和对象共享。

十一、对象的空转时长

除了type、encoding、ptr、refcount等属性外,redisObject还有一个属性lru。

lru属性记录了对象最后一次被命令访问的时间。

OBJECT IDLETIME k1 // 该命令可以查看键的空转时长,这是通过将当前时间减去值对象的lru时间计算得出的。

当redis设置了maxmemory选项,且内存回收算法设置为volatile-lru或allkeys-lru,那么当内存超过maxmemory时,空转时间较高的那部分key会优先被服务器释放

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558661.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

比较器的使用

一、TreeMap 实现排序 TreeMap是一个有序结构&#xff0c;TreeSet也是类似。 他们可以实现对元素的排序。TreeMap 是针对 key进行排序。 如果TreeMap的key 是Integer类型&#xff0c;可以无需指定任何特殊条件&#xff0c;默认即按照升序进行排序&#xff0c;如&#xff1a;…

经典数据结构——堆的实现

一、完全二叉树 堆是一种完全二叉树&#xff0c;什么是完全二叉树&#xff1f; 简单的说&#xff0c;一棵满二叉树表示的是所有节点全部饱和&#xff0c;最后一层全部占满&#xff1a; 而完全二叉树指的是满二叉树的最后一层&#xff0c;所有叶子节点都从左往顺序排满&#x…

排序算法 —— 堆排序

引言 此文基于《经典数据结构——堆的实现》中堆结构&#xff0c;实现一个以堆处理排序的算法。 一、算法思想 基于堆结构的堆排序的算法思想非常简单&#xff0c;循环获取大根堆中的最大值&#xff08;0位置的根节点&#xff09;放到堆的末尾&#xff0c;直到将堆拿空。 由…

经典数据结构——前缀树

引言 前缀树——trie /ˈtraɪ//树&#xff0c;也叫作“单词查找树”、“字典树”。 它属于多叉树结构&#xff0c;典型应用场景是统计、保存大量的字符串&#xff0c;经常被搜索引擎系统用于文本词频统计。它的优点是利用字符串的公共前缀来减少查找时间&#xff0c;最大限度…

排序算法 —— 计数排序

引言 计数排序是桶排序思想的一种具体实现&#xff0c;针对一些具有特殊限制的样本数据&#xff0c;如公司员工年龄&#xff0c;那么样本数据本身就一定在0~200之间&#xff0c;针对这样的数据&#xff0c;使用从0到200 的桶数组&#xff0c;桶的位置已经是有序的&#xff0c;…

Java多线程 —— 线程状态迁移

引言 线程状态迁移&#xff0c;又常被称作线程的生命周期&#xff0c;指的是线程从创建到终结需要经历哪些状态&#xff0c;什么情况下会出现哪些状态。 线程的状态直接关系着并发编程的各种问题&#xff0c;本文就线程的状态迁移做一初步探讨&#xff0c;并总结在何种情况下…

Java中的Unsafe

Java和C语言的一个重要区别就是Java中我们无法直接操作一块内存区域&#xff0c;不能像C中那样可以自己申请内存和释放内存。Java中的Unsafe类为我们提供了类似C手动管理内存的能力。 Unsafe类&#xff0c;全限定名是sun.misc.Unsafe&#xff0c;从名字中我们可以看出来这个类对…

Java 写时复制容器 —— CopyOnWriteArrayList

引言 写时复制的含义是当容器发生修改操作时&#xff0c;如add() 等&#xff0c;就会将原来的容器整体复制一份&#xff0c;这个过程是加锁的。而如果只是读取资源&#xff0c;例如 get() &#xff0c;就不会受到任何同步要求的限制。 写时复制的理念是&#xff0c;如果多个读…

arm中断保护和恢复_浅谈ARM处理器的七种异常处理

昨天的文章&#xff0c;我们谈了ARM处理器的七种运行模式&#xff0c;分别是&#xff1a;用户模式User(usr)&#xff0c;系统模式System(sys)&#xff0c;快速中断模式(fiq)&#xff0c;管理模式Supervisor(svc)&#xff0c;外部中断模式(irq)&#xff0c;数据访问中止模式Abor…

Queue —— JUC 的豪华队列组件

目录引言一、Queue 的继承关系1.1 Queue 定义基础操作1.2 AbstractQueue 为子类减负1.3 BlockingQueue 阻塞式Queue1.4 Deque 两头进出二、Queue 的重要实现三、BlockingQueue 的实现原理四、Queue 在生产者消费者模式中的应用五、Queue 在线程池中的应用六、ConcurrentLinkedQ…

daad转换器实验数据_箔芯片电阻在高温应用A/D转换器中的应用

工业/应用领域高温&#xff1a;地震数据采集系统、石油勘探监测、高精度检测仪产品采用&#xff1a;V5X5 Bulk Metal (R) Foil芯片电阻案例介绍TX424是一个完整的4通道24位模数转换器&#xff0c;采用40脚封装。该设计采用最先进设计方案&#xff0c;两个双通道24位调节器和一个…

excel分段排序_学会这个神操作,报表填报不再五花八门,效率远超Excel

在报表工作人员的的日常工作中&#xff0c;常常要面临统计混乱的终端用户输入的问题。由于无法准确限制用户的输入内容&#xff0c;所以在最终进行数据统计时&#xff0c;常常会出现数据不合法的情况。为此需要花费大量的人力和时间核对校验数据。举个简单的例子&#xff0c;某…

IDEA——必备插件指南

目录一、Free-Mybatis-Plugin二、Lombok三、jclasslib Bytecode Viewer一、Free-Mybatis-Plugin 二、Lombok 三、jclasslib Bytecode Viewer 学习 class 文件的必备插件。 使用简单&#xff0c;安装后可以在菜单 View 中看到 show bytecode with jclasslib&#xff1a; 效果…

jitter 如何优化网络_如何做好关键词优化网络?

越来越多的传统企业开始建立自己的网站&#xff0c;进而不断的推广自己的产品。为了能够让自己的企业网站出现在搜索引擎的首页&#xff0c;现在最常用的手段就是竞价排名和关键词优化网络。往往很多企业会选择关键词优化网络这种方式来推广自己的网站&#xff0c;对于新手seoe…

python学生名片系统_Python入门教程完整版400集(懂中文就能学会)快来带走

如何入门Python&#xff1f;权威Python大型400集视频&#xff0c;学了Python可以做什么&#xff1f;小编今天给大家分享一套高老师的python400集视频教程&#xff0c;里面包含入门进阶&#xff0c;源码&#xff0c;实战项目等等&#xff0c;&#xff0c;不管你是正在学习中&…

JVM——详解类加载过程

导航一、过程概述二、Loading2.1 类加载器2.2 双亲委派机制2.3 类在内存中的结构三、Linking四、Initializing一、过程概述 java 源文件编译后会生成一个 .class文件存储在硬盘上。 在程序运行时&#xff0c;会将用到的类文件加载到 JVM 内存中。从磁盘到内存的过程总共分为三…

pkpm板按弹性计算还是塑性_[转载]双向板按弹性还是按塑性方法计算

双向板按弹性方法还是按塑性方法计算茅老师您好&#xff01;想请教您个问题&#xff0c;PKPM计算双向板时一般都是按弹性算吧&#xff0c;可我去年刚进设计院的时候有一个项目是按塑性算的&#xff0c;这样影响大不大啊&#xff0c;支座与跨中弯矩比值系数取得默认的1.8&#x…

Java 的混合执行模式

导航解释执行与编译执行总结解释执行与编译执行 Java 虽然是先编译再运行&#xff0c;但实际上&#xff0c;对于 JVM 来说&#xff0c;依然是逐条解释执行字节码文件中的指令&#xff0c;即大部分情况下&#xff0c;Java 都是解释执行的。 JVM通过 interpreter 解释器解释执行…

下载 Java 学习的权威文档

JVMS 和 JLS 文档的下载 快速直达&#xff1a; https://docs.oracle.com/javase/8/ --> Java Language and Virtual Machine Specifications jvm specification 和 java language specification 是Java 学习的两个最权威的文档。如果你用的是 Java 8&#xff0c;就可以去下载…

iso图像测试卡_4700万像素 五轴防抖 徕卡正式发布SL2无反相机

出自蜂鸟网-器材频道&#xff0c;原文链接&#xff1a;https://m.fengniao.com/document/5358989.html徕卡于今日正式发布SL2相机&#xff0c;搭载4700万像素CMOS感光元件、通过感光元件移位实现光学图像稳定的五轴防抖技术、全新徕卡物距探测式自动对焦技术以及576万像素分辨率…