当前位置: 首页 > news >正文

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;

5e846743eb384667b075a96c04ba8eff.png

d71df69af8104c95be1bad2e81d49f1c.png

f973ee84a288454681fea59441323520.png

常用操作

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)中的)

跳跃列表

b2bd74c8102944bd8349841f418b31e1.png

其中每根柱子代表一个元素,每个元素可能有多个层级,最左边是表头,它的高度是当前列表最高高度。当要寻找某一个值的时候,从表头最高层开始按照箭头找,只到最底层的节点。表头的score是Double.MIN_VALUE用来垫底

插入元素时,需要按照查找的逻辑找到最底部的节点,然后插入节点,接着会采用随机策略决定新节点有多少层。第一层的概率是100%,第二层的概率是50%,第三层的概率是25%,以此类推,最高可以有64层

 

 

相关文章:

Redis系列-数据结构篇

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

正则表达式(RE)

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

发布技术路线图!美国量子计算公司QuEra公开三年OKR

​编辑丨慕一 编译/排版丨琳梦 卉可 深度好文&#xff1a;1100字丨8分钟阅读 近期&#xff0c;美国量子计算公司QuEra Computing宣布了一系列关于容错量子计算机的战略路线图&#xff0c;该路线图从2024年开始&#xff0c;最终目标是打造具有100纠错逻辑量子比特的系统。 在…...

Vue2:请求接口的两种方式axios和vue-resource

一、场景描述 前端和后端的交互&#xff0c;肯定是要发生接口调用的 这个时候&#xff0c;就要涉及前端如何向后端接口发送请求&#xff0c;获取数据 二、请求方式 1、axios方式(推荐) 这个方式本质就是ajax&#xff0c;底层就是对xhr(XMLHttpRequest)的封装 1、安装axios…...

扩展学习|商业智能和大数据分析的研究前景(比对分析)

文献来源&#xff1a; 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入门指南』- 详细安装与配置教程,助你起航容器化世界!

引言 在探索云计算和自动化部署的时代&#xff0c;Docker以其独特的容器化技术站在了风口浪尖。如果你期待着无缝地将你的应用从一个环境迁移到另一个环境&#xff0c;那么Docker无疑是你的得力助手。但首先&#xff0c;我们得学会如何正确地安装和配置Docker。这篇文章将详细…...

如何提高http连接成功率?

问题 丢包、错包、乱包 高延迟 响应数据回来时间长&#xff0c;甚至大于客户端等待时间 带宽小 每次能够通信的内容较少&#xff0c;数据包越大受影响可能越大 网络断续 网络经常断开又连接 优化处理 采用TCP协议、实现长连接&#xff0c;采用长连接池&#xff0c;节省…...

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远程控制的文件导入到文件夹&#xff0c;核心是深蓝色的三个文件。 本版本为4.70&#xff0c;其文件所在位置如下图所示&#xff0c;需要注意的是&#xff0c;目前不支持Ubuntu22的远程api&#xff1a; 双击Sphere这一行的灰色文件&#xff0c;可以看到远程…...

汽车燃油泵数据分析:全球市场的年复合增长率将达到10%左右

燃油泵是汽车配件行业的专业术语。是电喷汽车燃油喷射系统的基本组成之一&#xff0c;位于车辆油箱内部&#xff0c;燃油泵在启动和发动机运转时工作&#xff0c;如果发动机停止而点火开关仍处于ON时&#xff0c;HFM-SFI控制模块关闭燃油泵的电源&#xff0c;以避免意外点火。 …...

DC-磁盘管理(23国赛真题)

2023全国职业院校技能大赛网络系统管理赛项–模块B:服务部署(WindowServer2022) 文章目录 题目配置步骤组成RAID 5,磁盘分区命名为卷标H盘:Raid5。手动测试破坏一块磁盘,做RAID磁盘修复,确认RAID 5配置完毕。验证查看Raid5(打开磁盘管理器,查看raid信息)Raid5磁盘修复…...

216961-98-7,BODIPY 493/503 NHS 活化酯,可以应用于分子生物学等领域中

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;216961-98-7&#xff0c;BODIPY 493/503 NHS 活化酯&#xff0c;BODIPY 493/503 NHS ester&#xff0c;BODIPY 493/503 SE 一、基本信息 产品简介&#xff1a;BODIPY 493/503 NHS ester是一种特殊的染料&#xff0c…...

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…...

幻兽帕鲁服务器游戏怎么升级版本?

幻兽帕鲁服务器游戏怎么升级版本&#xff1f;自建幻兽帕鲁服务器进入Palworld游戏提示“您正尝试加入的比赛正在运行不兼容的游戏版本&#xff0c;请尝试升级游戏版本”什么原因&#xff1f;这是由于你的客户端和幻兽帕鲁服务器版本不匹配&#xff0c;如何解决&#xff1f;更新…...

【ASP.NET Core 基础知识】--身份验证和授权--授权和策略

一、授权和策略的概念及应用 在ASP.NET Core中&#xff0c;授权和策略是重要的安全概念&#xff0c;用于确定用户是否有权限执行特定的操作或访问特定的资源。以下是关于ASP.NET Core中授权和策略的概念及其应用的一些重要信息&#xff1a; 1.1 授权&#xff08;Authorizatio…...

20240130在ubuntu20.04.6下卸载NVIDIA显卡的驱动

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

汽车标定技术(十七)--Bypass的前世今生

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

【开源精选导航】GitHub-Chinese-Top-Charts:一榜在手,优质中文项目轻松找寻

各位热爱开源技术的朋友们&#xff0c;你们是否有过这样的困扰&#xff1a;面对浩瀚的GitHub海洋&#xff0c;想找寻那些具有高质量中文文档的优秀开源项目却无从下手&#xff1f;今天&#xff0c;我们就为大家揭晓一个宝藏般的开源项目——GitHub 中文项目集合&#xff08;访问…...

C++ 11新特性之语法甜点1

概述 C 11中引入了许多简化编程工作的语法上的新特性&#xff0c;我们暂且美其名曰&#xff1a;“语法甜点”。下面&#xff0c;我们将对这些“语法甜点”一一进行介绍。 语法甜点1&#xff1a;序列for循环 序列for循环是一种简化的for循环&#xff0c;可用于遍历一组序列&…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...