Redis-对象

参考资料 极客时间Redis(亚风)

Redis对象

String

• 基本编码⽅式是RAW,基于简单动态字符串(SDS)实现,存储上限为512mb。
• 如果存储的SDS⻓度⼩于44字节,则会采⽤EMBSTR编码,此时object head与SDS是⼀段连续空间。申请内存时只需要调⽤⼀次内存分配函数,效率更⾼。
• 如果存储的字符串是整数值,并且⼤⼩在LONG_MAX范围内,则会采⽤INT编码:直接将数据保存在RedisObject的ptr指针位置(刚好8字节),不再需要SDS了。
对应第一种情况:
在这里插入图片描述
对应第二种情况:
在这里插入图片描述
对应第三种情况:
在这里插入图片描述

List

Redis采⽤QuickList实现List。

在这里插入图片描述

Set

Set是Redis中的集合,不⼀定确保元素有序,可以满⾜元素唯⼀、查询效率要求极⾼。
为了查询效率和唯⼀性,set采⽤HT编码(Dict)。Dict中的key⽤来存储元素,value统⼀为null.
当存储的所有数据都是整数,并且元素数量不超过set-max-intset-entries时,Set会采⽤lntSet编码,以节省内存。
第一中情况都是int类型:IntSet 实现

在这里插入图片描述
第二种:使用dict实现
在这里插入图片描述
上面过程对应的源码:

int setTypeAdd (robj *subject, sds value) {
	Long Long llval;
	if (subject->encoding==OBJ_ENCODING_HT) { 
	//已经是HT编码,直接添加元素
	dict *ht = subject->ptr;
	dictEntry *de = dictAddRaw(ht,value,NULL)if (de) {
	dictSetKey(ht, de, sdsdup (value))dictSetVal(ht,de, NULL)return 1 ; }
	}
	else if (subject->encoding == OBJ_ENCODING_INTSET){ 
	// ⽬前是INTSET
	// 判断value是否是整数
	if (isSdsRepresentableAsLongLong(value,&llval) == C_OK) {
	uint8_t success = 0;
	// 是整数,直接添加元素到set
	subject->ptr=intsetAdd (subject->ptr, llval, &success)if (success){
	/* 当intset元素数量超出set_max_intset_entries,则转为HT.*/
	size_t max_entries = server.set_max_intset_entries;
	if (max_entries >= 1<<30) max_entries=1<<30;
	if (intsetLen(subject->ptr) > max_entries)
	setTypeConvert(subject,OBJ_ENCODING_HT)return 1;
	}
	) else {
	// 不是整数,直接转为HT
	setTypeConvert(subject,OBJ_ENCODING_HT)serverAssert(dictAdd(subject->ptr,sdsdup (value),NULL)== DICT_OK)return 1;}
} }
ZSet

底层是用三种数据结构实现的(HT + SkipList + ZPlist)

typedef struct zset {
	// Dict指针
	dict *dict;
	// SkipList指针
	zskiplist *zsl;
} zset;

当元素数量不多时,HT和SkipList的优势不明显,⽽且更耗内存。因此zset还会采⽤ZipList结构来节省内存,不过需要同时满⾜两个条件:
① 元素数量⼩于zset-max-ziplist-entries,默认值128
② 每个元素都⼩于zset-max-ziplist-value字节,默认值64
源码如下:

// zadd添加元素时,先根据key找到zset,不存在则创建新的zset
zobj = LookupKeywrite(c->db, key)if (checkType (c, zobj,OBJ_ZSET)goto cleanup;
//判断是否存在
if (zobj == NULL) {// zset不存在
if (server.zset_max_ziplist_entries == 0
server.zset_max_ziplist_value < sdslen(c->argv [scoreidx+1]->ptr))
{ 
// zset_max_ziplist_entries设置为0就是禁⽤了ZipList,
//或者value⼤⼩超过了zset_max_ziplist_value,采⽤HT + SkipList
Zobj = createzsetobject()} else {
// 否则,采⽤ ZipList
zobj = createzsetziplistobject()}
dbAdd(c->db, key, zobj)}
zsetAdd(zobj,score, ele, flags, &retflags, &newscore)

Ziplist本身没有排序功能,⽽且没有键值对的概念,因此需要有zset通过编码实现:
• Ziplist是连续内存,因此score和element是紧挨在⼀起的两个entry,element在前,score在后
• score越⼩越接近队⾸,score越⼤越接近队尾,按照score值升序排列
在这里插入图片描述

Hash

Hash底层采⽤的编码与Zset也基本⼀致,只需要把排序有关的SkipList去掉即可:
• Hash结构默认采⽤ZipList编码,⽤以节省内存。Ziplist中相邻的两个entry 分别保存field和value
• 当数据量较⼤时,Hash结构会转为HT编码,也就是Dict,触发条件有两个:
① ZipList中的元素数量超过了hash-max-ziplist-entries(默认512)
② ZipList中的任意entry⼤⼩超过了hash-max-ziplist-value(默认64字节)
在这里插入图片描述

// 插入命令
void hsetCommand(client *c) {
	int i, created = 0;
	robj *o;
	//判断hash的key是否存在,不存在则创建⼀个新的,默认采⽤ZipList编码
	if ((o = hashTypeLookupwriteOrCreate(c, c->argv[1]))==NULL) return;
	// 判断是否需要把ZipList转为Dict
	hashTypeTryConversion(o,c->argv,2,c->argc-1)// 循环遍历每⼀对field和value,井执⾏hset命令
	for (i = 2;i<c-argc; i += 2)
	created += !hashTypeSet(o,c->argv[I]->ptr,c->argv[i+1]->ptr, HASH_SET_COPY);
	}
	robj *hashTypeLookupwriteOrCreate(client *c, robj *key)
	// 查找key
	robj *o = LookupKeywrite(c->db, key)if (checkType(c,o, OBJ_HASH)return NULL;
	// 不存在,则创建新的
	if (o == NULL) {
	o = createHashobject()dbAdd (c->db, key,o)}
	return o;
}
robj *createHashobject (void) {
	// 默认采⽤zipList编码,申请ZipList内存空间
	unsigned char *z1 = ziplistNew();
	robj *o = createobject(OBJ_HASH, z1)//设置编码
	o->encoding = OBJ_ ENCODING_ZIPLIST;
	return 0;
}
// ziplist 在什么时候转换为HT
void hashTypeTryConversion(robj *o,robj **argv, int start, int end)
	int i;size_t sum = 0;
	// 本来就不是ZipList编码,什么都不⽤做了
	if (o->encoding != OBJ_ENCODING_ZIPLIST) return;
	//依次遍历命令中的field、 value参数
	for (i = s. start; i < c. end;j++)
	if (!sdsEncodedobject (argv[i]))
	continue;
	size_t len = sdsLen (argv[i]->ptr)// 如果field或value超过hash_max_ziplist_value,则转为HT
	if (len > server.hash_max_ziplist_value) {
	hashTypeConvert(o, OBJ_ENCODING_HT)return;
	}
	sum += len;
	}
	// ziplist⼤⼩超过1G,也转为HT
	if (!ziplistSafeToAdd(o- >ptr, sum))
	hashTypeConvert(o, OBJ_ENCODING_HT)}
// 真正插入元素的逻辑
int hashTypeSet(robj *o,sds field, sds value, int flags){
	int update = 0// 判断是否为ZipList编码
	if (o->encoding == OBJ_ENCODING_ZIPLIST) {
	unsigned char *zl, *fptr, *vptr;
	zl = o->ptr;
	// 查询head指针
	fptr = ziplistIndex(zl, ZIPLIST_HEAD)if (fptr != NULL)// head不为空,说明ZipList不为空,开始查找key
	fptr = ziplistFind(zl, fptr, (unsigned char*) field, sdslen(value));
	if (fptr != NULL){//判断是否存在,如果已经存在则更新
	update=1;
	ziplistReplace(zl, vptr, (unsigned char*) value,sdslen (value))// 不存在,则直接push
	if(!update){ // 依次push新的field和value到zipList的尾部
	zl = ziplistPush(zl, (unsigned char*) field, sdslen(field),ZIPLIST_TAIL);
	zl = ziplistPush(zl, (unsigned char*)value, sdslen (value),ZIPLIST_TAIL)}
	o->ptr = zl;
	/* 插⼊了新元素,检查list⻓度是否超出,超出则转为HT */
	if (hashTypeLength(o)>server.hash_max_ziplist_entries)
	hashTypeConvert(o, OBJ_ENCODING_HT)} else if (o->encoding == OBJ_ENCODING_HT) {
	// HT编码,直接插⼊或覆盖
	} 
	return update;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

线性代数(一)

1.标量&#xff1a;标量由只有⼀个元素的张量表⽰。 x np.array(3.0) y np.array(2.0) x y, x * y, x / y, x ** y (array(5.), array(6.), array(1.5), array(9.))2.向量&#xff1a;向量可以被视为标量值组成的列表&#xff0c;列向量是向量的默认⽅向。 x np.arange(4…

MyBatis原理解读

我们项目中多用MyBatis进行数据库的读写,开源的MyBatis-Plus框架对其进行了增强,使用上更加简单,我们之前的很多项目也是直接用的MyBatis-Plus。 数据库操作的时候,简单的单表读写,我们可以直接在方法里链式组装SQL,复杂的SQL或涉及多表联合join的,需要在xml手写SQL语句…

RabbitMQ不公平分发问题分析及问题解决

1.不公平分发 1.1 不公平分发策略是什么&#xff1f; 在 RabbitMQ 中&#xff0c;不公平分发&#xff08;Unfair Dispatch&#xff09;是指当多个消费者&#xff08;Consumers&#xff09;同时订阅同一个队列&#xff08;Queue&#xff09;时&#xff0c;消息的分发机制是不公…

网上下载的python如何运行,python可以下载到d盘吗

本篇文章给大家谈谈如何在python官网上下载python&#xff0c;以及python可以在手机上下载吗&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 从Python官网下载Python的步骤 如果你是想要学习Python编程的初学者&#xff0c;那么第一步就是要从官方网站下载Py…

uniGUI之MASK遮罩

在页面进行后台数据库操作的时候&#xff0c;不想 用户再进行 页面上的 其他操作&#xff0c;这时候就要 将页面 遮罩。例如UniDBGrid有LoadMask属性。 1]使用ScreenMask函数 2]JS调用 3]一个控件控制遮罩另一个控件(如Button遮罩UniDBGrid) //很简单&#xff0c;本例子就是告…

Android14创建Pixel6 Pro模拟器(一百七十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Vue3项目中集成mars3D简单三部曲

Vue3项目中集成mars3D简单三部曲 这里是参考网址&#xff0c;大佬可以点击一件跳转 1.安装依赖 npm install vite-plugin-mars3d --save-dev2.修改 vite.config.ts 配置文件 import { defineConfig } from vite; import { mars3dPlugin } from vite-plugin-mars3d;export d…

C++ Qt开发:自定义Dialog对话框组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍自定义Dialog组件的常用方法及灵活运用。 在…

Stable-Diffusion|从图片反推prompt的工具:Tagger(五)

stable-diffusion-webui-wd14-tagger 前面几篇&#xff1a; Stable-Diffusion|window10安装GPU版本的 Stable-Diffusion-WebUI遇到的一些问题&#xff08;一&#xff09; 【Stable-Diffusion|入门怎么下载与使用civitai网站的模型&#xff08;二&#xff09;】 Stable-Diffusi…

QQ邮箱发送工具类的实现

我们在日常开发中&#xff0c;需要实现一个对邮箱的发送&#xff0c;今天就实现邮箱的发送工具类&#xff0c;只需要一些注册邮箱之后的配置即可&#xff0c;我这边使用的是qq邮箱 0.加上依赖 <!--邮箱--><dependency><groupId>org.springframework.boot&l…

DevOps常用工具全家桶,实现高效运维和交付

专栏集锦&#xff0c;大佬们可以收藏以备不时之需&#xff1a; Spring Cloud 专栏&#xff1a;http://t.csdnimg.cn/WDmJ9 Python 专栏&#xff1a;http://t.csdnimg.cn/hMwPR Redis 专栏&#xff1a;http://t.csdnimg.cn/Qq0Xc TensorFlow 专栏&#xff1a;http://t.csdni…

Linux:进程地址空间

目录 1.程序地址空间 2.进程地址空间 1.程序地址空间 我们在讲C/C语言的时候&#xff0c;32位平台下&#xff0c;我们见过这样的空间布局图 我们来验证一下这张图的正确性&#xff1a; int un_gval;int init_gval100;int main(int argc, char* argv[],char* env[]){//代码…

C语言之变量的存储方式和生存周期

一、变量的存储方式 C语言变量的存储有两种方式&#xff1a;静态存储方式和动态存储方式&#xff0c;相应的生产期也有两种&#xff1a;静态生存期和自动生存期。 ①静态存储方式&#xff1a;在程序运行前为变量内存分配内存&#xff0c;在程序结束后回收变量的内存。&#x…

java-sec-code中重定向

重定向 状态码3xx 存在问题的代码段 GetMapping("/redirect") public String redirect(RequestParam("url") String url) {return "redirect:" url; }用户访问/redirect路径时&#xff0c;redirect方法会获取web请求中的url参数内容&#xff0…

文化传媒企业网站建设的效果如何

文化传媒业可以细分为多个类目&#xff0c;如企业营销宣传、明星包装、主播打造、马戏团、动漫等&#xff0c;这些都有很高的市场需求度&#xff0c;尤其近些年互联网深入各个行业&#xff0c;线上发展尤为重要&#xff0c;也促进了文化传媒业的发展。 同时该行业需求者&#…

React脚手架搭建

React脚手架 脚手架&#xff1a;可以快速构建项目的基本架构。 脚手架安装命令 可全局安装脚手架 创建项目 来到当前目录下 create-react-app 项目名&#xff08;不要大写字母&#xff09; 运行项目 进到项目里&#xff0c;在项目目录下&#xff0c;执行 npm start &#xff…

FC-13A(用于汽车应用的kHz范围晶体单元,低轮廓贴片)

FC-13A晶体非常适合用在汽车导航系统设计中的应用&#xff0c;是一种具有优异的频率性能和AEC-Q200标准认证的汽车工业级高精度晶体,FC-13A是一款尺寸为3.2 1.5 0.9mm&#xff0c;频率范围32.768KHz耐高温晶振&#xff0c;频率温度系数仅为-0.04ppm/℃&#xff0c;并且其老化…

总结一些vue3小知识2

1.el-tree-select和el-tree组件报错&#xff08;有的下拉选项选择不了&#xff0c;一点击就报错&#xff0c;但是有的却能选择&#xff0c;不会报错&#xff09; 原因:就如同v-for一样&#xff0c;需要添加key才不会出现渲染错误&#xff0c;而el-tree-select和el-tree组件需要…

Python数据科学视频讲解:Python集合

2.14 Python集合 视频为《Python数据科学应用从入门到精通》张甜 杨维忠 清华大学出版社一书的随书赠送视频讲解2.14节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。内容涵盖数据科学应用的全流程&#xff0c;包括数据科学应用…

基于YOLOv8深度学习的西红柿成熟度检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…