redis系列之------对象

前言

Redis 并没有直接使用数据结构来实现键值对数据库, 而是基于这些数据结构创建了一个对象系统, 这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象, 每种对象都用到了至少一种我们前面所介绍的数据结构。

通过这五种不同类型的对象, Redis 可以在执行命令之前, 根据对象的类型来判断一个对象是否可以执行给定的命令。 使用对象的另一个好处是, 我们可以针对不同的使用场景, 为对象设置多种不同的数据结构实现, 从而优化对象在不同场景下的使用效率。

除此之外, Redis 的对象系统还实现了基于引用计数技术的内存回收机制: 当程序不再使用某个对象的时候, 这个对象所占用的内存就会被自动释放; 另外, Redis 还通过引用计数技术实现了对象共享机制, 这一机制可以在适当的条件下, 通过让多个数据库键共享同一个对象来节约内存。

对象的类型与编码

Redis 使用对象来表示数据库中的键和值, 每次当我们在 Redis 的数据库中新创建一个键值对时, 我们至少会创建两个对象, 一个对象用作键值对的键(键对象), 另一个对象用作键值对的值(值对象)。

Redis 中的每个对象都由一个 redisObject 结构表示, 该结构中和保存数据有关的三个属性分别是 type 属性、 encoding 属性和 ptr 属性:

1 typedef struct redisObject { 2  3     // 类型 4     unsigned type:4; 5  6     // 编码 7     unsigned encoding:4; 8  9     // 指向底层实现数据结构的指针10     void *ptr;11 12     // ...13 14 } robj;

我们可以看到一个对象中主要包含了三种字段。

type: 表示对象的类型。比如String,List,Hash等等

encoding:表示对象底层用的是什么数据结构。如INT(整数),EMBSTR(简洁版sds),RAW(sds),HT(map)等等

ptr:ptr是一个指针,指向对象所用的数据结构。

如下图所示:

set  k v

k是String类型,embstr数据结构,也就是简洁版的sds,后续讲。

embstr与sds区别

之前我们讲数据结构,都没有见到过embStr,是的,我也是看到这一节才知道有这个东西的。

Redis为了优化,搞了一个embStr,他是为了专门存短字符串的一种编码优化方式。

  • embstr 编码将创建字符串对象所需的内存分配次数从 raw 编码的两次降低为一次。raw 编码会调用两次内存分配函数来分别创建 redisObject 结构和 sdshdr 结构, 而 embstr 编码则通过调用一次内存分配函数来分配一块连续的空间, 空间中依次包含 redisObject 和 sdshdr 两个结构。因为一个连续,一个不连续。
  • 释放 embstr 编码的字符串对象只需要调用一次内存释放函数, 而释放 raw 编码的字符串对象需要调用两次内存释放函数。理由同上
  • 因为 embstr 编码的字符串对象的所有数据都保存在一块连续的内存里面, 所以这种编码的字符串对象比起 raw 编码的字符串对象能够更好地利用缓存带来的优势。

总的来说,因为embstr分配的是一段连续的内存,使得它分配释放内存都是一次,所以效率会有所提高。同时embste   <==>  sds  为44个字节。

从下图中,我们可以明确看到。 len <= 44 都是embster的数据结构,如果len > 44 则转变为raw。至于为啥44。

大家可以去算一下。参考文章:

https://zhuanlan.zhihu.com/p/67876900

https://xiaoyue26.github.io/2019/01/19/2019-01/redis%E7%9A%84embstr%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF39B/

内存

Redis为了节省内存,真的是操碎了心。

c语言不像Java,Go等语言,本身不具备自动回收内存机制。Java的内存回收导致STW一直被人诟病,最近看了ZGC的数据,Java真的是崛起了。

因此Redis 在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制, 通过这一机制, 程序可以通过跟踪对象的引用计数信息, 在适当的时候自动释放对象并进行内存回收。

但熟悉JVM的都知道,引用计数他有一种缺陷就是,解决不了循环引用的问题。

如  A   <==>  B  但已经没有其他任何节点引用AB了,但AB由于相互引用,计数为1,永远不会被回收。所以Java用了GC ROOT。

但Redis不知道为啥不存在这个问题,找了资料,也没找出什么原因。大多都说Redis没有复杂的结构,所以?有大佬能解答下不?

引用计数我们可以通过  OBJECT refcount token 命令,查询到token被引用了几次,如果为0,那么则可以回收了。

还有最重要的一点是,Redis对整数 0-9999(共1W个整数)做了缓存。类似于Java对-128-127做缓存一样。

但是没有对值的字符串,如aaaaa的这种缓存,毕竟判断一个字符串是否在库里面,需要扫整个库,非常耗时,并且cpu压力非常的大。

处于优化,折中的考虑,也就缓存了0-9999吧。其实看看淘宝商品的价格,缓存0-100足矣,毕竟0-100占据了99%的商品。

具体可看:http://redisbook.com/preview/object/share_object.html

后言

  • Redis 数据库中的每个键值对的键和值都是一个对象。
  • Redis 共有字符串、列表、哈希、集合、有序集合五种类型的对象, 每种类型的对象至少都有两种或以上的编码方式, 不同的编码可以在不同的使用场景上优化对象的使用效率。
  • 服务器在执行某些命令之前, 会先检查给定键的类型能否执行指定的命令, 而检查一个键的类型就是检查键的值对象的类型。
  • Redis 的对象系统带有引用计数实现的内存回收机制, 当一个对象不再被使用时, 该对象所占用的内存就会被自动释放。
  • Redis 会共享值为 0 到 9999 的整数对象。
  • 对象会记录自己的最后一次被访问的时间, 这个时间可以用于计算对象的空转时间。

参考:

(0)

相关推荐

  • Python面试的50个经典问答(上)

    Python面试的50个经典问答(上)

  • 一文读懂 Redis 常见对象类型的底层数据结构

    (给数据分析与开发加星标,提升数据技能) 转自:伍陆七, 链接:cnblogs.com/chentianming/p/13838347.htm Redis 是一个基于内存中的数据结构存储系统,可以用作 ...

  • [Go] GO中的字符串底层数据结构

    一个字符串是一个不可改变的字节序列,字符串通常是用来包含人类可读的文本数据.和数组不同的是,字符串的元素不可修改,是一个只读的字节数组.每个字符串的长度虽然也是固定的,但是字符串的长度并不是字符串类型 ...

  • Redis 核心篇:唯快不破的秘密

    " 天下武功,无坚不摧,唯快不破! " 学习一个技术,通常只接触了零散的技术点,没有在脑海里建立一个完整的知识框架和架构体系,没有系统观.这样会很吃力,而且会出现一看好像自己会,过 ...

  • 15张图解Redis为什么这么快

    来自公众号:IT界农民工 作为一名服务端工程师,工作中你肯定和 Redis 打过交道.Redis 为什么快,这点想必你也知道,至少为了面试也做过准备.很多人知道 Redis 快仅仅因为它是基于内存实现 ...

  • 如何使用好 Redis 内存数据库

    接下来,我们来聊聊如何使用好 Redis 内存数据库. 目前主流的内存数据库是 Redis,它使用 IO 多路复用机制监听多个文件描述符的读写事件,然后使用单线程来处理任务.如下图所示. 虽然能避免线 ...

  • StackExchange.Redis 系列 1:基础使用

    本系列博文是"伪"官方文档翻译,并非完全将官方文档进行翻译,而是我在查阅.测试原始文档并转换为自己东西后进行的"准"翻译. 本系列本博文基于 redis 5.0 ...

  • Redis系列(一):介绍、安装(Docker、Windows、Linux)

    一.介绍 Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cac ...

  • Redis系列之-Redis-Sentinel

    一主从复制高可用 123 #主从复制存在的问题:#1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变成master#2 主从复制,只能主写数据,所以写能力和存储能力有限 ...

  • Redis系列总结,满满的干货技术文!

    Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源.包含多种数据结构.支持网络.基于内存.可选持久性的键值对存储数据库,其具备如下特性: 基于内存运行,性能高效 ...

  • redis系列之------简单的动态字符串(SDS)

    前言 Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串), 而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的 ...

  • [转载]如何合婚找到合适的对象系列一

    很好的参考 原文地址:如何合婚找到合适的对象系列一作者:叶飘然 夫妇之道为人伦之始!古人论婚嫁一直比较混乱,一直以来比较盛行的是唐代吕才的合婚图,后世批判此法者甚多,婚嫁搭配自古一直有以下几类方法: ...

  • Redis分布式缓存系列(三)- Redis中的Hash类型

    本系列将和大家分享Redis分布式缓存,本章主要简单介绍下Redis中的Hash类型. 散列Hash:类似dictionary,通过索引快速定位到指定元素的,耗时均等,跟string的区别在于不用反序 ...

  • Redis分布式缓存系列(二)- Redis中的String类型以及使用Redis解决订单秒杀超卖问题

    本系列将和大家分享Redis分布式缓存,本章主要简单介绍下Redis中的String类型,以及如何使用Redis解决订单秒杀超卖问题. Redis中5种数据结构之String类型:key-value的 ...

  • Redis分布式缓存系列(四)- Redis中的Set类型

    本系列将和大家分享Redis分布式缓存,本章主要简单介绍下Redis中的Set类型,以及如何使用Redis解决数据去重.共同好友.可能认识.统计访问网站的IP数.统计点赞数和随机获取某项值等问题. S ...