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 相当于count

zscore books “think in java” 获取指定value的score

zrank books “think in java” 按score排序后,当前value的排名

zrangebyscore books 0 8.91 在区间之内的所有value

zrangebyscore books -inf 8.91 withscore 在区间之内所有的value+score

zrem books “think in java” 删除value(可以通过这个命令来确保只有一个线程抢到队列(zset)中的)

跳跃列表

b2bd74c8102944bd8349841f418b31e1.png

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

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

 

 

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

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

相关文章

跟着pink老师前端入门教程-day14

2.6 main 主体模块制作 HTML&#xff1a; <div class"w"><div class"main"><!-- 焦点图模块 --><div class"focus"><ul><li><img src"./images/banner_bg.png" alt""></li>…

提高 NFS Azure 文件共享性能

本文内容 适用于增加预读大小以提高读取吞吐量Nconnect另请参阅 本文介绍如何提高 NFS Azure 文件共享的性能。 适用于 展开表 文件共享类型SMBNFS标准文件共享 (GPv2)、LRS/ZRS 标准文件共享 (GPv2)、GRS/GZRS 高级文件共享 (FileStorage)、LRS/ZRS 增加预读大…

指针的深入理解(二)

这节主要复习函数指针 函数指针 函数指针的标志就是int (* ) (数据类型)&#xff0c; 是储存函数的地址的指针变量。函数名就是的首地址。我们平常使用的函数名就是函数的地址&#xff1a; 由此可以发现&#xff0c;我们可以通过函数的地址来使用函数。 那么我们就可以知道函…

什么是Vue Vue入门案例

一、什么是Vue 概念&#xff1a;Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套 构建用户界面 的 渐进式 框架 Vue2官网&#xff1a;Vue.js 1.什么是构建用户界面 基于数据渲染出用户可以看到的界面 2.什么是渐进式 所谓渐进式就是循序渐进&#xff0c;不一定非得把V…

NC开发客户端(前端)连接启动失败can‘t connect to server, please wait

效果图 解决方法 IP地址和端口要对应 1-IP地址中间启动&#xff0c;肯定是这个127.0.0.1 2-端口号&#xff0c;要对应中间件启动在控制台输出的端口 或者是在home目录-》bin-》sysConfig.bat这里面的服务器&#xff0c; 里面可以看到对应启动ip地址和端口

2023年春秋杯网络安全联赛冬季赛_做题记录

可信计算 基于挑战码的双向认证1 可信计算赛题-双向认证挑战模式.docx 使用命令进行SSH登录上去 ssh player8.147.131.156 -p 18341 # 记得加上-p参数指定端口&#xff0c;不然默认的是22端口看见word文档的提示&#xff0c;先尝试一下 直接获得了flag1 web 魔术方…

Linux:理解信号量以及内核中的三种通信方式

文章目录 共享内存的通信速度消息队列msggetmsgsndmsgrcvmsgctl 信号量semgetsemctl 内核看待ipc资源单独设计的模块ipc资源的维护 理解信号量总结 本篇主要是基于共享内存&#xff0c;延伸出对于消息队列和信号量&#xff0c;再从内核的角度去看这三个模块实现进程间通信 共享…

SpringCloudStream整合MQ

目录 概念 快速搭建SCS环境 一秒切换MQ 组件 1. Binder 2. Binding 3. Message 分组消费 概念 Spring Cloud Stream&#xff08;SCS&#xff09; 的主要目标是一套代码&#xff0c;兼容所有MQ, 降低MQ的学习成本&#xff0c;提供一致性的编程模型&#xff0c;让开发者能更…

数据可视化练习

文章目录 试题示例 试题示例 绘制下图所示的表格 根据下表的数据&#xff0c;将班级名称一列作为x轴的刻度标签&#xff0c;将男生和女生两列的数据作为刻度标签对应的数值&#xff0c;使用bar()函数绘制下图所示的柱形图。 方式一 import numpy as np import matplotlib.p…

web自动化搞定文件上传

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

Spring 学习1

1、什么是Spring Spring 是一款主流的 Java EE 轻量级开源框架 &#xff0c;Spring 由“Spring 之父”Rod Johnson 提出并创立&#xff0c;其目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言…

AI算力专题:算力系列之四-各省算力规划建设梳理-绿色低碳高质量发展-部署算力建设AI产业研究

今天分享的是AI算力系列深度研究报告&#xff1a;《AI算力专题&#xff1a;算力系列之四-各省算力规划建设梳理-绿色低碳高质量发展-部署算力建设AI产业研究》。 &#xff08;报告出品方&#xff1a;中泰证券&#xff09; 报告共计&#xff1a;40页 数据中心能耗情况 随着越…

java的面向对象编程(oop)——认识接口

前言&#xff1a; 打好基础&#xff0c;daydayup! 接口 接口概述 java提供一个关键字interface&#xff0c;用这个关键字可以定义出特殊结构&#xff1a;接口 接口格式&#xff1a; public interface 接口名{//成员变量&#xff08;常量&#xff09;//成员方法&#xff08;抽…

Dragons

题目链接&#xff1a; Problem - 230A - Codeforces 解题思路&#xff1a; 用结构体排序就好&#xff0c;从最小的开始比较&#xff0c;大于就加上奖励&#xff0c;小于输出NO 下面是c代码&#xff1a; #include<iostream> #include<algorithm> using namespac…

【2024.1.30练习】李白打酒加强版(25分)

题目描述 题目思路 在最多数据的情况下&#xff0c;有100个店100朵花&#xff0c;总情况为的天文数字&#xff0c;暴力枚举已经不可能实现&#xff0c;考虑使用动态规划解决问题。最后遇到的一定是花&#xff0c;所以思路更倾向于倒推。 建立二维数组&#xff0c;容易联想到为…

软件个性化选型:制造企业如何选择适合自身的工单管理系统-亿发

企业制造业是实体经济中非常重要和基础的组成部分&#xff0c;直接关系到国家经济的血脉。然而&#xff0c;传统制造业在生产与管理上所采用的老一套方法和经验已不再适应当下的发展需求。信息化、数字化和智能化被视为制造企业的必然趋势。要想在竞争激烈的市场中永立潮头&…

都2024年了,谁还在逛良品铺子?

作者 | 辰纹 来源 | 洞见新研社 2019年年初&#xff0c;良品铺子举办了一场高端零食战略发布会&#xff0c;当时还花重金请来顶流明星为品牌代言&#xff0c;在强化“高端零食”定位的同时&#xff0c;良品铺子坚定的表示&#xff0c;要“抛弃价格战”。 时任良品铺子董事长杨…

24小时涨粉10w+的AI小游戏-哄哄模拟器

近年来&#xff0c;随着chatGPT的爆火&#xff0c;一系列的AI应用应运而生。比如&#xff1a;AI绘画&#xff0c;AI写作等。今天我们来看看最近很火的一个AI小游戏-哄哄模拟器。 1. 试玩体验 这款游戏名叫“哄哄模拟器”&#xff0c;体验地址为&#xff1a;https://hong.grea…

RGMII接口介绍

RGMII接口概述 RGMII全称为Reduced Gigabit Media Independent Interface&#xff0c;是一种网络接口标准&#xff0c;用于千兆以太网芯片与PHY芯片之间的接口标准。RGMII接口的设计目的是为了减少I/O的数量&#xff0c;尽可能减小网卡PCB占用面积&#xff0c;同时提高数据传输…

Nacos服务注册源码:客户端

入口 我们就拿nacos自己example下的NamingExample来做测试 public class NamingExample {public static void main(String[] args) throws NacosException, InterruptedException {Properties properties new Properties();properties.setProperty("serverAddr", …