redis的对象是什么

news/2024/11/29 21:44:23/

前言:redis没有直接使用前面介绍的几种数据类型
sds、双端链表、字典、压缩列表、整数集合等等。
而是基于这些数据结构创建了一个对象系统,这个对象系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象。每种对象都用到了至少一种我们前面所介绍的数据结构。
redis的对象系统还实现了基于引用计数技术的内存回收机制(竟然redis也有),当程序不再使用某个对象的时候,这个对象所占有的内存就会被自动释放。redis还通过引用计数技术实现了对象共享机制。这一机制可以在适当的条件下,通过让多个数据库键共享同一个对象来节约内存。
redis的对象带有访问时间记录信息。该信可以用于计算数据库键的空转时长。服务器启用maxmemory功能的情况下。空转时长较大的那些键可能会优先被服务器删除。

8.1 对象的类型与编码

set操作时,redis至少会创建两个对象,一个键对象,一个值对象
redis中的每一个对象都由一个redisObject结构表示。
typedef struct redisObject {

// 类型
unsigned type:4;// 编码
unsigned encoding:4;// 对象最后一次被访问的时间
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */// 引用计数
int refcount;// 指向实际值的指针
void *ptr;

} robj;

8.1.1 类型

类型枚举

redis的键对象总是字符串对象,只有值对象会有区别。因此这样约定
●当我们称呼一个数据局键为“字符串键”时,我们指的是“这个数据库键对应的值为字符串对象”
执行type命令时,返回的是值的类型

SET msg “hello world”
TYPE msg

8.1.2 编码和底层实现

对象的ptr指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定。
encoding属性记录了对象所使用的编码,即这个对象使用了什么数据结构,作为对象的底层实现。

每种类型的对象都至少使用了两种不同的编码。

object encoding命令可以查看一个数据库键的值对象的编码
OBJECT ENCODING msg

通过encoding属性来设定对象所使用的编码,而不是为特定类型的对象关联一种固定的编码。极大的提升了redis的灵活性和效率
举个🌰:
列表对象包含的元素比较少时,redis使用压缩列表作为底层实现
压缩列表比双端列表更节约内存,在元素数量较少时,会更快加入缓存
列表对象包含的元素越来越多时,会转为双端列表。
其他类型也会有类似的优化。
接下来会分别介绍redis的五种不同类型的对象。这些对象底层所使用的编码方式,
给出从一种编码转为另一种编码的条件,以及同一个命令在不同编码上的实现方法

8.2 字符串对象

字符串对象的编码可以是int、raw或者embstr
如果一个字符串对象保存的是整数值,并且这个正数值可以用long类型来表示。那么字符串对象会将整数值保存字符串对象结构的ptr属性里(将void*转换成long)。并将字符串对象的编码设置为int
127.0.0.1:6379> set number 10086
OK
127.0.0.1:6379> object enchoding number
(error) ERR Unknown subcommand or wrong number of arguments for ‘enchoding’. Try OBJECT HELP.
127.0.0.1:6379> object encoding number
“int”
127.0.0.1:6379>

●字符串对象保存的是一个字符串值,并且这个字符串长度大于32字节。那么字符串对象将使用一个简单动态字符串(sds)来保存这个字符串值,并将对象的编码设置为raw
127.0.0.1:6379> set story “the prince loved the rose because it’s his rose”
OK
127.0.0.1:6379> object encoding story
“raw”
127.0.0.1:6379>

指针ptr指向一个sds数据
●字符串长度小于等于32字节,字符串对象将使用embstr编码来保存

127.0.0.1:6379> object encoding number
“int”
127.0.0.1:6379> set story “i miss you”
OK
127.0.0.1:6379> object encoding story
“embstr”

embstr是专门用来保存短字符串的一种优化编码方式。
embstr的好处
●分配内存和回收内存相较于raw只需要一次
●保存在连续内存里,embstr能更好利用缓存带来的优势
brew services restart redis
redis-cli
127.0.0.1:6379> set msg “hello”
OK
127.0.0.1:6379> object encoding msg
“embstr”
127.0.0.1:6379>

可以用long double类型表示的浮点数在redis中也是作为字符串值来保存的。如果要保存一个浮点数到字符串对象里,程序会先将这个浮点数转换成字符串,再保存转换所得的字符串值。
why
127.0.0.1:6379> set pi 3.14
OK
127.0.0.1:6379> object ecoding pi
(error) ERR unknown subcommand ‘ecoding’. Try OBJECT HELP.
127.0.0.1:6379> object encoding pi
“embstr”
127.0.0.1:6379>

还可以保存整数,编码方式是int
127.0.0.1:6379> set pi 3
OK
127.0.0.1:6379> object encoding pi
“int”
127.0.0.1:6379>

8.2.1 编码的转换

对于int编码的字符串对象,执行一些命令使得这个对象不再是整数时,编码会从int变成raw
127.0.0.1:6379> set number 10086
OK
127.0.0.1:6379> object encoding number
“int”
127.0.0.1:6379> append number “is a good number”
(integer) 21
127.0.0.1:6379> object encoding number
“raw”

embstr只读,不可修改,执行修改命令时,会先转换成raw,再执行修改
127.0.0.1:6379> set me chen
OK
127.0.0.1:6379> object encoding me
“embstr”
127.0.0.1:6379> append me " happy"
(integer) 10
127.0.0.1:6379> object encoding me
“raw”

8.2.2 api

8.3 列表对象

列表对象的编码ziplist或者linkedlist
ziplist编码的列表对象使用压缩列表作为底层实现
encoding和type决定了ptr指向的数据结构是什么,从而进行读取
ziplist:ptr指向的是ziplist,保存的是列表里的值,每一节点里存的都是一个字符串对象

linkedList:prt指向的是链表头节点,

8.3.1 编码转换

●对象中保存的字符串长度不超过64字节
●元素数量小于512
两个条件任意一个不能满足就会由ziplist编码转为linkedList编码

8.3.2 命令列表(实用)

命令 含义
lpush push新元素到列表头
rpsh push新元素到列表尾
lpop pop头节点
rpop pop尾节点
lindex 返回指定节点
llen 长度
linsert 插入表头、表尾或者其他位置
lrem 删除给定元素
ltrim 删除所有不在指定索引范围内的节点
lset 更新节点值

8.4 哈希对象

ziplist或者hastable
ziplist:key和value挨着
hashtable:key连续,且保存了value的地址?

8.4.1 编码转换

●不超过64字节
●键值对数量不多于512
同时满足:ziplist
否则 hashtbale

8.5 集合对象

●都是整数值
●元素数量不超过512
此时用的是intset
否则用hashtable
条件二通过set-max-intset-entries来修改
命令:sadd、scard、sismember(查找是否存在)、srandmember(随机返回一个)、spop(随机返回并删除)、srem(删除给定元素)

8.6 有序集合对象

ziplist和skiplist
ziplist中,集合元素按分值从小到大排序,分值小的元素被放在靠近表头的方向,分值较大的元素放置在靠近表尾的方向。
zset结构中包含一个字典和一个跳跃表
如注释:
●dict用来支持o(1)复杂度的按成员取分值操作
● zsl(跳跃表)用来支持平均复杂度为O(log N)的按照分值定位成员和范围操作
typedef struct zset {

// 字典,键为成员,值为分值
// 用于支持 O(1) 复杂度的按成员取分值操作
dict *dict;// 跳跃表,按分值排序成员
// 用于支持平均复杂度为 O(log N) 的按分值定位成员操作
// 以及范围操作
zskiplist *zsl;

} zset;

跳跃表里
object属性:保存了元素的成员
score属性:保存了元素的分值
zscore命令是通过dict来实现的。
这两种类型的数据结构是通过指针来共享相同元素的成员和分值。虽然是两种数据结构,但是不会产生任何重复的成员或者分值

●元素数量小于128
●所有元素成员长度小于64
此时使用ziplist,否则用skiplist
命令
zadd、zcard、zcount(统计分值在给定范围内的节点数量)、zrange(表头向表尾遍历,返回给定索引范围内的所有元素)、zrank、

8.7 类型检查与命令多态

命令类型检查:检查type字段
命令多态:虽然使用的是同一个命令,但是会根据type和encoding字段确定使用的是哪种数据结构,并调用相应的api
因此被称为命令多态
typedef struct redisObject {

// 类型
unsigned type:4;// 编码
unsigned encoding:4;// 对象最后一次被访问的时间
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */// 引用计数
int refcount;// 指向实际值的指针
void *ptr;

} robj;

8.8 内存回收

通过refcount字段实现,当refcount字段为0时,对象占用的内存会被回收

8.9 对象共享

整数类型的对象会被共享


http://www.ppmy.cn/news/39151.html

相关文章

7年测试,从功能测试到测试开发,我总算证明了自己

我感觉我是一个比较有发言权的人吧,我在测试行业爬模滚打7年,从点点点的功能测试到现在成为测试开发工程师,工资也翻了几倍; 个人觉得,测试的前景并不差,只要自己肯努力;我刚出来的时候是在鹅厂…

递归过程与递归工作栈

首先了解一下任意两个函数之间进行调用的情况: 比如在a函数里面调用b函数,那么在使用b函数之前,计算机还会1.把实参,返回地址给复制下来(但只是复制而已,地址不是原来的。)如图: 此外2.为被调用…

mitmproxy安装配合selenium使用教程

1.去Python官网下载指定版本 https://www.python.org/downloads/windows/ 2. 分开安装 pip install mitmproxy pip install selenium pip install m3u8 pip install requests pip install bs4 pip install pycryptodome 3.cmd启动 4.安装对应Chrome驱动 地址一: …

linux管理控制面板--可视化管理linux

市面上主要的网站主机分为三大类,具体差异简单说明: 【虚拟主机】:也是大家口中说的”主机空间“,可定制化低,适合纯小白和新手,完全不懂技术。说明白点,就是一台云服务器分割空间和内存形成的…

Qt5.12实战之dll中导出类对象

1.创建动态库并导出 如导出类中有静态变量要先初始化: 生成lib与dll文件 导入库引用头文件及指定你包含目录与库目录 链接器中的附加依赖项添加lib名 直接通过类对象调用类成员,或者调用类静态成员

ctf.show 愚人杯

1、奇怪的压缩包 下载附件解压提示要密码 使用010editor打开,发现frFlags 和 deFlags 的值都被修改了,这就会造成压缩包的伪加密, 将它们都改回0。 另存为一个文件再打开,没有密码提示了 解压发现图片并不完整,反正高…

Shell 输入输出重定向

1 普通重定向 命令说明command > file将输出重定向到 file。command < file将输入重定向到 file。command >> file将输出以追加的方式重定向到 file。n > file将文件描述符为 n 的文件重定向到 file。n >> file将文件描述符为 n 的文件以追加的方式重定向…

React应用(基于React脚手架)

目录前言&#xff1a;一、使用create-react-app创建react应用1、什么是 react 脚手架&#xff1f;2. 创建 cli 脚手架方式13. 创建 cli 脚手架方式24. npx:5. react脚手架项目结构6. 功能界面的组件化编码流程&#xff08;通用&#xff09;7. 如何更改脚手架版本二、React 组件…