Redis系列-数据结构篇
数据结构
string(字符串)
redis的字符串是动态字符串,类似于ArrayList,采用预分配冗余空间的方式减少内存的频繁分配。
struct SDS<T>{
T capacity;
T len;
byte flags;
byte[] content;
}
当字符串比较短时,T可以是byte和short来表示(能省点空间),一个简单的SDS至少占用3字节
struct SDS<T>{
int8 capacity;
int8 len;
int8 flags;
byte[] content;
}
embstr和raw
当字符串比较短时,存储形式embstr;当字符串比较长时,存储形式raw。
暂时无法在文档外展示此内容
struct RedisObject {
int4 type; //4bits
int4 encoding; //4bits
int24 lru; //24bits,对象的热度
int32 refcount; //32bits,记录对象的引用计数,当lru为0时,对象会被销毁
void *ptr; //64bits
}
每个对象除了内容以外,RedisObject本身也占用1/2+1/2+3+4+8 = 16字节
如图所示,embstr存储时会把数据结构redisObject和数据SDS挨边存储;raw存储时数据结构RedisObject和SDS时分开存储,通过ptr指针指向SDS的内存地址。
所以一个简单的字符串最少占用3字节+16字节= 19字节
而redis使用的内存分配器jemalloc,tcmalloc分配内存时的单位都是1/4/8/16/32/64,所以假设内存分配给分配了64字节的空间,那么最多给字符串内容的空间只有44字节 = 64 - 3 - 16 - 1(最后一个1是因为字符串需要以null结尾,占一个子节)
扩容
预分配空间大小:capacity
实际字符串长度:len
创建字符串时,len和capacity是一样的长度
当字符串长度小于1M时,扩容都是加倍现有的空间,即
if(len<1024*1024 && len+appendLen>=capacity){capacity = 2*capacity;
}
当字符串长度大于1M时,每次扩容比当前多1M空间
if(len>1024*1024 && len+appendLen>=capacity){capacity = capacity + 1024*1024;
}
常用操作
set,get,mset,mget,expire,setnx,incr
mset name1 aa name2 bb name3 cc
mget name1 name2 name3
expire name1 5. #5秒后过期
incr age 1
incr age by 5。 #signed long的最大最小值之间
位图
位图来自于字符串的另一种表示,我们知道字符串实际是存储byte数组,redis以此可以单独设置某key第n位为0还是1。通过位图,我们可以节省更多的内存,当然需要配合适当的场景使用
常用操作
零存整取
setbit key index 0/1
get key
整存整取(即字符串)
set key value
get key
整存零取
set key value
getbit key index
零存零取
setbit key value
getbit key index
bitcount:用来统计指定范围内1的个数
bitcount key 0 1 前两个字符(0~1)中1的个数
bitpos:用来查找指定范围内出现的第一个0或1
bitpos key 1 第一个1位
bitpos key 0 第一个0位
bitpos key 1 start end 在start~end范围的字节内,第一个0位
list(列表)
相当于java里面的LinkedList,可以在头部(Left)和尾部(Right)插入/删除
两元素之间使用双向链表连接,可以支持向前向后遍历
encoding:ziplist,quicklist
满足
create if not exists
drop if no elements
常用操作
rpush books python java golang
llen books
lpop books
rpop books
lpush books newBook
lindex books 1 #获取books列表中第2位元素
ltrim books 0 1 #区间内的元素保留,特别的如果后面元素=-1,表示结尾。同理-2表示倒数第二个
lrange books 0 1 #相当于sublist,特别的如果后面元素=-1,表示结尾。同理-2表示倒数第二个
与java中linkedList不同有2
如果redis list中元素比较少时,使用ziplist存储,
如果redis list中元素比较多时,使用ziplist+linkedList存储,即每个“元素”实际上是一个ziplist
问题:为什么redis list中的“元素”是ziplist,不是简单的元素
redis是基于内存的操作,所以对内存的使用要求很苛刻。尽其所能对使用的内存进行优化。如果redis list中元素存储的是简单的元素,那么仅仅元素间的两个指针就占了不少空间,特别是当元素本身占用空间很少时。
为什么元素是ziplist呢?
首先ziplist本身是一个聚集型的列表,通过连续存储以及快速定位,能够提高在ziplist内遍历的效率。同时ziplist内部可以选择压缩深度,也能极大的减少使用的空间
压缩链表
struct ziplist{int32 zlbytes; //整个压缩链表占用字节数int32 zltail_offset; //最后一个元素距离压缩列表起始位置的偏移量int16 zllength; //元素个数T[] entries; //元素集合int8 zlend; //压缩链表结束节点,OxFF}struct entry{int prevlen; //前一个entry的字节长度int encoding; //元素类型编码optional byte[] content; //元素内容}
往ziplist里面追加元素
因为ziplist是紧凑型的数据结构,意味着每追加一个元素都需要调用realloc扩展内存,取决于内存分配算法和ziplist当前的内存大小,可能会重新扩展全新的内存,并把原有的拷贝过来,也可能在原来的位置直接扩展
快速链表
无法复制加载中的内容
每个ziplist存储超过8KB就会新起一个ziplist
redis可以选择对quicklist中的每个ziplist进行压缩,以压缩深度表示。默认是压缩深度为0。如果压缩深度等于1,那么收尾两个ziplist不压缩,其他的都压缩。如果压缩深度等于2,那么链表头两个和链表尾两个都不压缩,其他都压缩。
hash(字典)
满足
create if not exists
drop if no elements
与java中的HashMap很相近。都是数组加链表的形式。
encoding:ziplist,hashtable
不同有三:
redis的hash的value只能是字符串,所以需要在业务系统中将其做序列化和反序列化。
redis hash的rehash与HashMap的rehash也不一样。HashMap是一次性将元素进行rehash,如果元素比较多,可能会有卡顿的情况。redis hash中的rehash是渐进式的,发起rehash之后,会通过定时任务或者hash操作指令,渐进式的将旧的hash表的内容拷贝到新hash表中。
redis hash可以对对象的具体属性进行操作,比如
hset books borrowTime 111111
hincr books borrowTime 5
常用操作
hset,hget,hgetall,hmset,hincr,hincrby
set(集合)
满足
create if not exists
drop if no elements
相当于Java里面的HashSet,所有key对应的value都只用一个NULL。且内部的键值是无序的,唯一的
若set中存在某元素,则再次set时,返回0,可以以此判断是否存在元素
encoding:inset,dict(rehash时,通过COW的思维来做)
typedef struct intset {uint32_t encoding; // 编码方式,后面会详细解释uint32_t length; // 集合中元素的个数,也就是contents数组的长度int8_t contents[]; // 保存元素的数组
} intset;
常用操作
sadd,spop,smembers,sismember,scard(count)
如果set中的元素都是整数并且数据量比较小时,redis会选择使用inset进行数据的存储
struct inset{int32 encoding;int32 length;int content;}
encoding会有int16,int32,int64三种类型。可以向上扩,不能向下缩。(存储的内容都是整数,并不会占用很大空间,但如果向下缩,就需要额外的内存分配以及原有的内存回收,得不偿失)
zset(有序列表)
满足
create if not exists
drop if no elements
类似于java中SortedSet和HashMap的集合体,一方面可以保证唯一性,另一方面可以为每一个元素添加score,并以此作为排序依据
内部实现是一种叫做“跳跃列表”的数据结构
encoding:ziplist,skiplist
常用操作
zadd books 9.0 “think in java”zrange books 0 -1 相当于sublist,并且按照score正序列出zrevrange books 0 -1 相当于sublist,并且按照score倒序列出zcard books 相当于countzscore books “think in java” 获取指定value的scorezrank books “think in java” 按score排序后,当前value的排名zrangebyscore books 0 8.91 在区间之内的所有valuezrangebyscore books -inf 8.91 withscore 在区间之内所有的value+scorezrem books “think in java” 删除value(可以通过这个命令来确保只有一个线程抢到队列(zset)中的)
跳跃列表
其中每根柱子代表一个元素,每个元素可能有多个层级,最左边是表头,它的高度是当前列表最高高度。当要寻找某一个值的时候,从表头最高层开始按照箭头找,只到最底层的节点。表头的score是Double.MIN_VALUE用来垫底
插入元素时,需要按照查找的逻辑找到最底部的节点,然后插入节点,接着会采用随机策略决定新节点有多少层。第一层的概率是100%,第二层的概率是50%,第三层的概率是25%,以此类推,最高可以有64层
相关文章:

Redis系列-数据结构篇
数据结构 string(字符串) redis的字符串是动态字符串,类似于ArrayList,采用预分配冗余空间的方式减少内存的频繁分配。 struct SDS<T>{ T capacity; T len; byte flags; byte[] content; } 当字符串比较短时,…...

正则表达式(RE)
什么是正则表达式 正则表达式,又称规则表达式(Regular Expression)。正则表达式通常被用来检索、替换那些符合某个规则的文本 正则表达式的作用 验证数据的有效性替换文本内容从字符串中提取子字符串 匹配单个字符 字符功能.匹配任意1个…...

发布技术路线图!美国量子计算公司QuEra公开三年OKR
编辑丨慕一 编译/排版丨琳梦 卉可 深度好文:1100字丨8分钟阅读 近期,美国量子计算公司QuEra Computing宣布了一系列关于容错量子计算机的战略路线图,该路线图从2024年开始,最终目标是打造具有100纠错逻辑量子比特的系统。 在…...
Vue2:请求接口的两种方式axios和vue-resource
一、场景描述 前端和后端的交互,肯定是要发生接口调用的 这个时候,就要涉及前端如何向后端接口发送请求,获取数据 二、请求方式 1、axios方式(推荐) 这个方式本质就是ajax,底层就是对xhr(XMLHttpRequest)的封装 1、安装axios…...

扩展学习|商业智能和大数据分析的研究前景(比对分析)
文献来源: Liang T P , Liu Y H .Research Landscape of Business Intelligence and Big Data analytics: A bibliometrics study[J].Expert Systems with Applications, 2018, 111(NOV.):2-10.DOI:10.1016/j.eswa.2018.05.018. 信息和通信技术的快速发展导致了数字…...

『Docker入门指南』- 详细安装与配置教程,助你起航容器化世界!
引言 在探索云计算和自动化部署的时代,Docker以其独特的容器化技术站在了风口浪尖。如果你期待着无缝地将你的应用从一个环境迁移到另一个环境,那么Docker无疑是你的得力助手。但首先,我们得学会如何正确地安装和配置Docker。这篇文章将详细…...
如何提高http连接成功率?
问题 丢包、错包、乱包 高延迟 响应数据回来时间长,甚至大于客户端等待时间 带宽小 每次能够通信的内容较少,数据包越大受影响可能越大 网络断续 网络经常断开又连接 优化处理 采用TCP协议、实现长连接,采用长连接池,节省…...
Elasticsearch 中使用MustNot等同于不等于遇到的坑
1、在写关键词推荐时,需要把当前文章过滤掉,不能再推荐自己的文章,所以再es中需要用到 MustNot属性查询 /// <summary> /// 服务中心es检索 /// </summary> /// <param name="input"></param> /// <returns></…...

嵌入式工程师day15(链表)
内存管理 一.内存管理: 1.malloc void *malloc(size_t size); 功能: 申请堆区空间 参数: size:申请堆区空间的大小 返回值: 返回获得的空间的首地址 失败返回NULL 2.free void free(void *ptr); 功能: 释放…...

Coppeliasim倒立摆demo
首先需要将使用Python远程控制的文件导入到文件夹,核心是深蓝色的三个文件。 本版本为4.70,其文件所在位置如下图所示,需要注意的是,目前不支持Ubuntu22的远程api: 双击Sphere这一行的灰色文件,可以看到远程…...

汽车燃油泵数据分析:全球市场的年复合增长率将达到10%左右
燃油泵是汽车配件行业的专业术语。是电喷汽车燃油喷射系统的基本组成之一,位于车辆油箱内部,燃油泵在启动和发动机运转时工作,如果发动机停止而点火开关仍处于ON时,HFM-SFI控制模块关闭燃油泵的电源,以避免意外点火。 …...
DC-磁盘管理(23国赛真题)
2023全国职业院校技能大赛网络系统管理赛项–模块B:服务部署(WindowServer2022) 文章目录 题目配置步骤组成RAID 5,磁盘分区命名为卷标H盘:Raid5。手动测试破坏一块磁盘,做RAID磁盘修复,确认RAID 5配置完毕。验证查看Raid5(打开磁盘管理器,查看raid信息)Raid5磁盘修复…...

216961-98-7,BODIPY 493/503 NHS 活化酯,可以应用于分子生物学等领域中
您好,欢迎来到新研之家 文章关键词:216961-98-7,BODIPY 493/503 NHS 活化酯,BODIPY 493/503 NHS ester,BODIPY 493/503 SE 一、基本信息 产品简介:BODIPY 493/503 NHS ester是一种特殊的染料,…...

Python采集学习笔记-读取excel数据
表格格式 方法一:使用xlrd import xlrd 1.读取Excel文件 workbook xlrd.open_workbook(plc.xlsx) 2.读取第一个表 sheet workbook.sheet_by_index(0) 3.获取表格总行数 total_rows sheet.nrows 4.创建列表,存储表格一行中每一列信息 plc_info [] for row in range(1…...

幻兽帕鲁服务器游戏怎么升级版本?
幻兽帕鲁服务器游戏怎么升级版本?自建幻兽帕鲁服务器进入Palworld游戏提示“您正尝试加入的比赛正在运行不兼容的游戏版本,请尝试升级游戏版本”什么原因?这是由于你的客户端和幻兽帕鲁服务器版本不匹配,如何解决?更新…...
【ASP.NET Core 基础知识】--身份验证和授权--授权和策略
一、授权和策略的概念及应用 在ASP.NET Core中,授权和策略是重要的安全概念,用于确定用户是否有权限执行特定的操作或访问特定的资源。以下是关于ASP.NET Core中授权和策略的概念及其应用的一些重要信息: 1.1 授权(Authorizatio…...

20240130在ubuntu20.04.6下卸载NVIDIA显卡的驱动
20240130在ubuntu20.04.6下卸载NVIDIA显卡的驱动 2024/1/30 12:58 缘起,为了在ubuntu20.4.6下使用whisper,以前用的是GTX1080M,装了535的驱动。 现在在PDD拼多多上了入手了一张二手的GTX1080,需要将安装最新的545的驱动程序&#…...

汽车标定技术(十七)--Bypass的前世今生
目录 1.Bypass的诞生 2.Bypass的发扬光大 2.1 基于XCP的Bypassing 2.2 基于Debug的Bypass 2.3 小结 3.Bypass的实际应用 1.Bypass的诞生 下图我相信只要用过INCA的朋友都非常熟悉。 这是远古时期(2000年左右?我猜)ETAS针对发动机控制参数标定设计的一种并行数据…...

【开源精选导航】GitHub-Chinese-Top-Charts:一榜在手,优质中文项目轻松找寻
各位热爱开源技术的朋友们,你们是否有过这样的困扰:面对浩瀚的GitHub海洋,想找寻那些具有高质量中文文档的优秀开源项目却无从下手?今天,我们就为大家揭晓一个宝藏般的开源项目——GitHub 中文项目集合(访问…...
C++ 11新特性之语法甜点1
概述 C 11中引入了许多简化编程工作的语法上的新特性,我们暂且美其名曰:“语法甜点”。下面,我们将对这些“语法甜点”一一进行介绍。 语法甜点1:序列for循环 序列for循环是一种简化的for循环,可用于遍历一组序列&…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...