RedisObject
前言
Redis 是一个基于内存的,以 Key-Value 形式存储数据的 NoSQL 数据库。
相较于其它 NoSQL 数据库,Redis 提供了更丰富的数据类型和 API,开发者可以基于 Redis 实现数据缓存、消息队列、分布式锁等场景。
Redis 底层用一个全局哈希表来存储所有的键值对,Value 是一个指针,指向 Key 对应的数据对象。
Redis 服务端在执行数据处理命令时,首先要检查命令和操作的对象类型是否匹配,例如调用 GET 命令处理 Hash 对象,Redis 就会返回一个错误信息:
> HSET hash_key name Lisa
(integer) 1
> get hash_key
(error) WRONGTYPE Operation against a key holding the wrong kind of value
由此可见,Redis 首先要能根据 Key 获取到 Value 的数据类型,最简单的方式就是用一个结构体来对 Value 指向的底层数据结构做一个描述封装,这个结构体就是 RedisObject。
RedisObject
源码中对 RedisObject 结构体的定义如下:
typedef struct redisObject {unsigned type:4;unsigned encoding:4;unsigned lru:LRU_BITS;int refcount;void *ptr;
} robj;
属性 | 长度 | 说明 |
---|---|---|
type | 4 Bit | 对外的对象类型 例如:string list hash |
encoding | 4 Bit | 对象的编码类型 例如:ziplist skiplist intset |
lru | 24 Bit | 对象最近一次访问的时间戳 用于LRU缓存淘汰 |
refcount | 4 Byte | 对象引用次数 |
ptr | 8 Byte | 指向底层数据结构的指针 |
type、encoding、lru 三个属性后面都有一个冒号跟着一个数值,这是 C 语言里的位域定义法,目的是节省内存空间。当一个变量占用不了所有 Bit 时,就可以将其划分成多个位域,每个位域占用的 Bit 数称作 位宽。这里 type 和 encoding 的位宽都是 4,lru 的位宽是 24,合在一起就是 32 Bit,即 4 个字节。
下面分别介绍各个属性的作用。
type
type 表示 RedisObject 对外的数据类型,常用类型有以下五种,大家都很熟悉了。
#define OBJ_STRING 0 /* String object. */
#define OBJ_LIST 1 /* List object. */
#define OBJ_SET 2 /* Set object. */
#define OBJ_ZSET 3 /* Sorted set object. */
#define OBJ_HASH 4 /* Hash object. */
encoding
encoding 表示 RedisObject 底层的编码类型,即使是同一种数据类型,也可以用不同的编码类型来实现。例如:hash 既可以用 哈希表实现,也可以用 ziplist 实现。
目前的编码类型有以下十一种:
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
根据 type 和 encoding 俩属性,Redis 就知道 ptr 指针指向的具体数据类型了,也就知道该如何访问对象了。
lru
lru 代表对象最近一次访问的时间戳,Redis 每次访问对象,都会写入最新的时间戳,当内存资源不够时,Redis 会随机采样一批对象,然后比较 lru 字段,把最久未访问的对象清理掉。
你应该已经发现了,lru 字段才占用 24 Bit,Redis 为了节省内存,没有写入全量时间戳,而是以秒为单位,只写入时间戳的低 24 位。
获取 LRU 时钟的方法是getLRUClock()
:
unsigned int getLRUClock(void) {/*** 毫秒时间戳/1000 & lru时钟最大值* 当前秒级时间戳 只保留低24位 16777215/3600/24 约194天*/return (mstime()/LRU_CLOCK_RESOLUTION) & LRU_CLOCK_MAX;
}
预估对象闲置时间的方法是estimateObjectIdleTime()
:
unsigned long long estimateObjectIdleTime(robj *o) {// 获取LRU时钟 以秒为单位的当前时间戳,只保留低24位unsigned long long lruclock = LRU_CLOCK();if (lruclock >= o->lru) {return (lruclock - o->lru) * LRU_CLOCK_RESOLUTION;} else {// 溢出了,要加上溢出值return (lruclock + (LRU_CLOCK_MAX - o->lru)) *LRU_CLOCK_RESOLUTION;}
}
为什么是“预估”呢?因为受限于 lru 的空间限制,Redis 无法获得对象真正被闲置的时间。lru 只有 24 Bit,以秒为单位,最多能表示 16777215 秒,约 194 天。一旦超过这个范围,就会发生溢出,此时就会出现这种现象:一个对象明明已经闲置 194 天了,但是 Redis 认为它刚刚才被访问过,此时的LRU淘汰策略就会出问题,好在发生这种情况的概率并不高。
refcount
refcount 代表对象的引用次数。Redis 是内存数据库,对象的存储和释放都要进行内存管理,当 refcount=0 时代表对象可以被安全的回收。
另外,Redis 为了节约资源会尽量避免创建相同对象,会提前创建一批共享对象缓存起来以实现对象复用,例如服务端的响应信息:+OK \r\n
、PONG\r\n
等:
void createSharedObjects(void) {shared.crlf = createObject(OBJ_STRING,sdsnew("\r\n"));shared.ok = createObject(OBJ_STRING,sdsnew("+OK\r\n"));shared.emptybulk = createObject(OBJ_STRING,sdsnew("$0\r\n\r\n"));shared.czero = createObject(OBJ_STRING,sdsnew(":0\r\n"));shared.cone = createObject(OBJ_STRING,sdsnew(":1\r\n"));shared.emptyarray = createObject(OBJ_STRING,sdsnew("*0\r\n"));shared.pong = createObject(OBJ_STRING,sdsnew("+PONG\r\n"));shared.queued = createObject(OBJ_STRING,sdsnew("+QUEUED\r\n"));shared.emptyscan = createObject(OBJ_STRING,sdsnew("*2\r\n$1\r\n0\r\n*0\r\n"));shared.space = createObject(OBJ_STRING,sdsnew(" "));shared.colon = createObject(OBJ_STRING,sdsnew(":"));shared.plus = createObject(OBJ_STRING,sdsnew("+"));......
}
如果要修改一个共享对象,首先要检查 refcount 是否为0,大于0代表对象已经被引用,此时必须拷贝一个副本修改,以保证共享数据不被破坏。
ptr
ptr 是一个指针,指向 Value 的底层数据结构。根据 type 和 encoding 的不同,ptr 指向的数据结构也不相同。
相关文章:

RedisObject
前言 Redis 是一个基于内存的,以 Key-Value 形式存储数据的 NoSQL 数据库。 相较于其它 NoSQL 数据库,Redis 提供了更丰富的数据类型和 API,开发者可以基于 Redis 实现数据缓存、消息队列、分布式锁等场景。 Redis 底层用一个全局哈希表来存…...

【剑指Offer】31.栈的压入、弹出序列
题目 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就…...

Linux设置开机自启动奇安信可信浏览器,并配置默认页面
1. 先安装奇安信可信浏览器 安装完成后,会在/usr/share/applications/目录下生成一个 qaxbrowser-safe.desktop文件。 2.配置fixfox开机自启动 使用root用户进行如下操作: 将qaxbrowser-safe.desktop 文件复制到 ~/.config/autostart/ 目录下…...

flink1.15 异步维表Join 用于外部数据访问的异步 I/O scala版本
官方文档 Asynchronous I/O for External Data Access 异步 I/O | Apache Flink 核心问题 问什么有官方文档,我还要写个博客,因为scala Future这块有坑. 1 为什么我的算子显示反压100% 2 为什么我的任务不报错,也没有输出 3 Future对象我该怎么构建,有哪些注意事项. pom …...

Elasticsearch Relevance Engine---为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解]
Elasticsearch Relevance Engine—为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解] 今天要介绍的 Elasticsearch Relevance Engine™ (ESRE™),提供了多项用于创建高度相关的 AI 搜索应用程序的新功能。ESRE 站在 Elastic 这个搜索领域的巨人…...

微信小程序之会议OA系统首页布局搭建与Mock数据交互
目录 前言 一、Flex 布局( 分类 编程技术) 1、Flex布局是什么? 2、基本概念 3、容器的属性 3.1 flex-direction属性 3.2 flex-wrap属性 3.3 flex-flow 3.4 justify-content属性 3.5 align-items属性 3.6 align-content属性 4、项目…...

动态规划解股票类型
文章目录 单只股票买卖多次买卖单只股票最多两次买卖股票最多买k次含冷静期含手续费 单只股票买卖 买卖股票的最佳时机 关键思路:找到一个值,他与之后的最大值之差最大。 用minprice记录最小的值,用maxprofit记录最大的收益。 想清楚一个点…...

前端用 js-file-download组件下载后端返回的pdf,word,excel文件
后端返回的pdf,word,excel的文件流导出需要让浏览器下载文件 1、安装js-file-download组件 npm install js-file-download --save 2、在对应的页面引用 import fileDownload from "js-file-download"; 3、在接口返回结果后直接调用即可 let data{id:processId,c…...

Mac硬盘检测工具
Mac硬盘检测软件是一款用于检测和诊断Mac硬盘健康状态的工具,帮助用户及时发现潜在的硬盘问题,避免数据丢失和系统故障。通过全面的检测和报告功能,用户可以更好地了解自己的硬盘状况,确保数据的安全和可靠。给大家介绍几款好用的…...

一篇文章解密如何轻松实现移动应用的电子和手绘PDF签名功能!
对PDF文件签名是移动设备上越来越普遍的使用需求,本文将描述自动生成/“手绘”签名与如何使用DevExpress Office File API组件来实现在.NET MAUI应用程序中快速合并签名/签名支持之间的区别。 DevExpress Office File API是一个专为C#, VB.NET 和 ASP.NET等开发人员…...

【大数据】Kafka 入门简介
Kafka 入门简介 1.什么是 Kafka2.Kafka 的基本概念3.Kafka 分布式架构4.配置单机版 Kafka4.1 下载并解压包4.2 启动 Kafka4.3 创建 Topic4.4 向 Topic 中发送消息4.5 从 Topic 中消费消息 5.实验5.1 实验一:Python 实现生产者消费者5.2 实验二:消费组实现…...

Unity可视化Shader工具ASE介绍——8、UI类型的特效Shader编写
阿赵的Unity可视化Shader工具ASE介绍目录 Unity的UGUI图片特效角色闪卡效果 大家好,我是阿赵。 继续介绍Unity可视化Shader编辑插件ASE的使用。这次讲一下UI类特效Shader的写法。 一、例子说明 这次编写一个Shader,给一张UGUI里面的图片增加一个闪卡…...

科学指南针XPS | SEM | BET 降价:不赚钱,就和您交个朋友
尊敬的各位客户: 感谢您一直以来对科学指南针服务平台(下文简称:科学指南针)的支持和信任!科学指南针本着服务第一,客户至上的精神,多年来坚持为客户提供高质量的测试和服务,获得了广…...

nginx正反向代理,负载均衡
Nginx 正向代理,反向代理 ,负载均衡 Nginx有两种代理协议 七层代理(http协议) 四层代理(tcp/udp流量转发) 四层代理七层代理概念 四层代理 四层代理:基于tcp/ip协议层的转发代理方式&#…...

物联网中的MQTT协议总结
本文引注: https://mp.weixin.qq.com/s/y55wqYoWEvU9Q3-I0uu3cg 物联网曾被认为是继计算机、互联网之后,信息技术行业的第三次浪潮。随着基础通讯设施的不断完善,尤其是 5G 的出现,进一步降低了万物互联的门槛和成本。物联网本身也是 AI 和区…...

断点续传的原理和实现
断点续传是一种文件上传或下载的技术,允许用户在上传或下载中断后恢复操作而不必重新开始。其原理和实现可以分为以下步骤: 原理: 文件分割:将大文件分割成小块(分片)。上传/下载:客户端上传或…...

【小黑嵌入式系统第二课】嵌入式系统的概述(二)——外围设备、处理器、ARM、操作系统
上一课: 【小黑嵌入式系统第一课】嵌入式系统的概述(一)——概念、特点、发展、应用 下一课: 【小黑嵌入式系统第三课】嵌入式系统硬件平台(一)——概述、总线、存储设备(RAM&ROM&FLASH…...

Unity3D 在做性能优化时怎么准确判断是内存、CPU、GPU瓶颈详解
Unity3D是一款广泛应用于游戏开发的跨平台游戏引擎,但在开发过程中,我们经常会遇到性能瓶颈问题,如内存、CPU和GPU瓶颈。本文将详细介绍在Unity3D中如何准确判断和解决这些瓶颈问题,并给出相应的技术详解和代码实现。 对惹&#…...

pyqt5 QProgressDialog 进度条的使用 下载自动更新应用程序
pyqt5 QProgressDialog 进度条的使用 案例截图 思路 实例化进度条窗口设置窗口各属性包括标题 提示文字 和 窗口大小显示进度条窗口同过一个for循环 模拟进度 代码 from PyQt5.QtCore import QCoreApplication, QProcess from PyQt5.QtWidgets import QApplication,QProgre…...

【yolov5目标检测】使用yolov5训练自己的训练集
数据集准备 首先得准备好数据集,你的数据集至少包含images和labels,严格来说你的images应该包含训练集train、验证集val和测试集test,不过为了简单说明使用步骤,其中test可以不要,val和train可以用同一个,…...

出差学小白知识No5:ubuntu连接开发板|上传源码包|板端运行的环境部署
1、ubuntu连接开发板: 在ubuntu终端通过ssh协议来连接开发板,例如: ssh root<IP_address> 即可 这篇文章中也有关于如何连接开发板的介绍,可以参考SOC侧跨域实现DDS通信总结 2、源码包上传 通过scp指令,在ub…...

C++(初阶四)类和对象
文章目录 一、面向过程和面向对象初步认识二、类的引入三、类的定义1、类的概述2、类的两种定义3、成员变量命名规则的建议 四、类的访问限定符及封装1、访问限定符2、封装 五、类的作用域六、类的实例化七、类对象模型1、如何计算类对象的大小2、 类对象的存储方式猜测3、 验证…...

CSS餐厅练习链接及答案
目录 链接: level 1 level 2 level 3 level 4 level 5 level 6 level 7 level 8 level 9 level 10 level 11 level 12 level 13 level 14 level 15 level 16 level 17 level 18 level 19 level 20 level 21 level 22 level 23 level 24 le…...

嵌入式和 Java选哪个?
今日话题,嵌入式和 Java 走哪个?对于嵌入式领域有浓厚兴趣的人,并不会比Java行业薪资低,处于上中游水平。特别是从2020年开始,嵌入式领域受益于芯片产业的兴起,表现出了强劲的增长势头。薪资水平受多方面因素影响。以…...

创建带Axi_Lite接口的IP核与AXI Interconnect(PG059)
AXI Interconnect互连内核将一个或多个 AXI 内存映射主设备连接到一个或多个内存映射从设备。 参考小梅哥文档。 /**************************** 类型定义 ****************** **********/ /** * * 将值写入 AXI_REG_LIST 寄存器。执行 32 位写入。 * 如果组件以较小的宽度实…...

快速解决 Resource not accessible by integration
简介 最近好久没有写博客了,今天在写开源项目 python-package-template 的时候,正好遇到一个问题,记录一下吧。本文将介绍 Resource not accessible by integration 的几种解决方案。 也欢迎大家体验一下 python-package-template 这个项目&…...

港联证券:资金融通构成强支撑 “一带一路”金融合作开新局
本年是共建“一带一路”主张提出十周年。经过十年打开,共建“一带一路”从夯基垒台、立柱架梁到落地生根、持久打开,已成为打开包容、互利互惠、协作共赢的国际协作途径。“资金融通”作为首份“一带一路”白皮书提出的“五通”之一,定位为“…...

mysql varchar int
年龄是数字类型int SELECT * FROM test ORDER BY age; 年龄是字符类型varchar SELECT * FROM test ORDER BY code; 第1种 补前导0可以和数字一样排序 MySQL会比较字符的ASCII值,并根据这些值来确定字符的排列顺序。 印象中oracle好像也是吧。 ASCII (American …...

阿里云/腾讯云国际站账号:私服游戏服务器:阿里云CTO周靖人:AI时代,为什么阿里云一定要做开源
开源技术报告,阿里云私服游戏服务器怎么看待大模型的路径? 随着 Meta 的 Llama2 开源,开源模型,以及聚集大模型开发者的开源社区,正在发挥不可或缺的作用。 一个例子是,上个月 Hugging Face 得到了谷歌、…...

搭建Pytorch的GPU环境超详细
效果 1、下载和安装VS2019 https://visualstudio.microsoft.com/zh-hans/vs/older-downloads/ 登录需要用户名和密码 安装后需要联网下载组件的,安装的时候要勾选使用C++的桌面开发 2、下载和安装显卡驱动 查看自己的显卡型号 从英伟达下载和安装最新驱动...