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

【每日八股】Redis篇(二):数据结构

Redis 数据类型?

主要有 STRING、LIST、ZSET、SET 和 HASH。

STRING

String 类型底层的数据结构实现主要是 SDS(简单动态字符串),其主要应用场景包括:

  • 缓存对象:可以用 STRING 缓存整个对象的 JSON;
  • 计数:Redis 处理命令是单线程,所以执行命令的过程是原子的。故 String 适合技术场景,比如计算访问次数、点赞、转发、库存数量等;
  • 分布式锁:利用 SETNX 命令;
  • 共享 Session 信息:服务器都会去同一个 Redis 获取相关的 Session 信息,解决了分布式系统下 Session 存储的问题;

LIST

LIST 类型底层采用双向链表和压缩列表实现。

  • 若列表元素个数小于 512 个,其元素值小于 64 bytes,Redis 用压缩列表作为 List 类型的底层数据结构;
  • 否则使用双向链表;

Redis 3.2 之后,List 类型底层只由 quicklist 实现。Redis 7.0 之后,压缩列表数据结构被废弃,由 listpack 实现。

LIST 的应用场景包括:

  • 微信朋友圈点赞:要求按照点赞顺序显示点赞好友的信息,如果点赞取消则移除相应的好友信息;
  • 消息队列:可以使用左进右出的命令组成来完成队列的设计。

HASH

Hash 类型的底层数据结构是由压缩列表或哈希表实现的:

  • 如果哈希类型元素个数小于 512 个,所有值小于 64 字节的话,Redis 会使用压缩列表作为 Hash 类型的底层数据结构;
  • 如果哈希类型元素不满足上面条件,Redis 会使用哈希表作为 Hash 类型的底层数据结构。

在Redis 7.0 中,压缩列表数据结构被废弃,交由 listpack 来实现。HASH 应用场景主要有:

  • 缓存对象:一般采用 String + JSON 存储,对象中某些频繁变化的属性可以考虑抽出来用 Hash 类型存储;
  • 购物车:以用户 id 为 key,商品 id 为 field,商品数量为 value,恰好构成了购物车的3个要素。

SET

Set 类型的底层数据结构是由哈希表或整数集合实现的:

  • 如果集合中的元素都是整数且元素个数小于 512个,Redis 会使用整数集合作为 Set 类型的底层数据结构;
  • 如果集合中的元素不满足上面条件,则 Redis 使用哈希表作为 Set 类型的底层数据结构。

为什么 Redis 中的 SET 是 Key-Value 结构?

原因在于,Redis 是一个键值对数据库,其中的所有数据类型(String、List、Hash、Set、Sorted Set 等)都以 key-value 的形式存储。对于 Set 来说,key 是集合名称,value 是集合的内容。

SET 应用的主要场景:

  • 点赞:key 是文章 id、value 是用户 id;
  • 共同关注:Set 类型支持交集运算,故可用来计算共同好友或共同关注的公众号。key 是用户 id,value 是已关注的公众号的 id;
  • 去重:存储某活动中中奖的用户名 ,Set 类型因为有去重功能,可以保证同一个用户不会中奖两次。

ZSET

ZSET 类型(Sorted Set,有序集合)可以根据元素的权重来排序,可以自己来决定每个元素的权重值。比如说,可以根据元素插入Sorted Set 的时间确定权重值,先插入的元素权重小,后插入的元素权重大。应用场景主要有:

  • 在面对需要展示最新列表、排行榜等场景时,如果数据更新频繁或者需要分页显示,可以优先考虑使用 ZSET;
  • 有序集合比较典型的使用场景就是排行榜。例如学生成绩的排名榜、游戏积分排行榜、视频播放排名、电商系统中商品的销量排名等。

BITMAP

bit 是计算机中最小的单位,使用它进行储存将非常节省空间,特别适合一些数据量大且使用二值统计的场景。可以用于签到统计、判断用户登陆态等操作。

HyperLogLog

HyperLogLog用于统计,统计规则是基于概率完成的,不准确,标准误算率是 0.81%。优点是,在输入元素的数量或者体积非常非常大时,所需的内存空间总是固定的、并且很小。比如百万级网页 UV 计数等;

GEO

主要用于存储地理位置信息,并对存储的信息进行操作。底层是由Zset实现的,使用GeoHash编码方法实现了经纬度到Zset中元素权重分数的转换,这其中的两个关键机制就是「对二维地图做区间划分」和「对区间进行编码」。一组经纬度落在某个区间后,就用区间的编码值来表示,并把编码值作为Zset元素的权重分数。

Stream

Redis专门为消息队列设计的数据类型。相比于基于 List 类型实现的消息队列,有这两个特有的特性:自动生成全局唯一消息ID,支持以消费组形式消费数据。

之前方法缺陷:不能持久化,无法可靠的保存消息,并且对于离线重连的客户端不能读取历史消息。

Redis 底层数据结构?

SDS

SDS 不仅可以保存字符串,还可以保存二进制数据。

SDS 可以在 O(1) 内获取字符串长度,因为有 Len 属性。

SDS 不会发生缓冲区溢出,因为 SDS 在拼接字符串之前会检查空间是否满足要求,如果空间不够那么就自动扩容,故不会导致缓冲区溢出的问题。

链表

Redis 封装了名为 listNode 的数据结构,并构成双向链表。双向链表包括节点数量len,以及可以自定义实现的 dup、free、match 函数。

  • listNode 链表结点的结构中只包含 prev 和 next 指针;
  • list 提供了 head 和 tail 指针,因此获取链表首尾元素的时间复杂度为O(1)

缺点:

  • 链表每个节点之间的内存都是不连续的,无法很好利用 CPU 缓存。能很好利用CPU缓存的数据结构是数组,因为数组的内存是连续的。
  • 保存一个链表节点的值都需要一个链表节点结构头的分配内存开销较大

压缩列表

压缩列表是由连续内存块组成的顺序型数据结构,类似于数组。不仅可以利用 CPU 缓存,而且会针对不同长度的数据,进行相应编码,这种方法可以有效地节省内存开销。不能保存过多的元素,否则查询效率就会降低;新增或修改某个元素时,压缩列表占用的内存空间需要重新分配,甚至可能引发连锁更新的问题。

缺点:

  • 空间扩展操作也就是重新分配内存,因此连锁更新一旦发生,就会导致压缩列表占用的内存空间要多次重新分配,直接影响到压缩列表的访问性能。
  • 如果保存的元素数量增加了,或是元素变大了,会导致内存重新分配,会有连锁更新的问题。
  • 压缩列表只会用于保存的节点数量不多的场景,只要节点数量足够小,即使发生连锁更新也能接受。

哈希

哈希表是一种保存键值对(key-value)的数据结构。优点在于能以O(1)的复杂度快速查询数据。Redis 采用了拉链法来解决哈希冲突,在不扩容哈希表的前提下,将具有相同哈希值的数据串起来,形成链接。

跳表

跳表(Skip List) 是一种基于有序链表的数据结构,通过添加多级索引来实现高效的查找、插入和删除操作。跳表的平均时间复杂度为 O(log n),接近平衡树的性能,但实现更简单。

跳表的核心思想

一. 多层链表

  • 跳表由多层链表组成,最底层是完整的有序链表,每一层都是下一层的“索引”;
  • 每一层的元素是随机选择的,高层元素少,低层元素多;

二. 跳跃查找:

  • 查找时从最高层开始,如果当前节点的下一个节点小于目标值,则向右移动;否则向下移动一层。
  • 通过跳跃查找,可以快速缩小查找范围。

三. 随机化

  • 插入新节点时,通过随机算法决定节点的高度(即层数),保证跳表的平衡性。
    在这里插入图片描述

整数集合

整数集合本质上是一块连续内存空间。

整数集合有一个升级规则,就是当将一个新元素加入到整数集合里面,如果新元素的类型(int32_t)比整数集合现有所有元素的类型(int16_t)都要长时,整数集合需要先进行升级,也就是按新元素的类型(int32_t)扩展 contents 数组的空间大小,然后才能将新元素加入到整数集合里,升级的过程中也要维持整数集合的有序性。

quicklist

其实 quicklist 就是双向链表 + 压缩列表组合,quicklist 就是一个链表,而链表中的每个元素又是一个压缩列表。quicklist 解决办法,通过控制每个链表节点中的压缩列表的大小或者元素个数,来规避连锁更新的问题。因为压缩列表元素越少或越小,连锁更新带来的影响就越小,从而提供了更好的访问性能。

listpack

listpack 没有压缩列表中记录前一个节点长度的字段了,listpack 只记录当前节点的长度,当向 listpack 加入一个新元素的时候,不会影响其他节点的长度字段的变化,从而避免了压缩列表的连锁更新问题。

为什么用跳表而不用平衡树?

  • 从内存占用上来说,跳表比平衡树更灵活一些:平衡树每个结点包含 2 个指针,而跳表每个结点平均包含 1/(1-p)
  • 在做范围查找的时候,跳表比平衡树操作要简单:在平衡树上,找到指定范围的小值之后,还需要以中序遍历的顺序继续寻找其它不超过大值的节点。如果不对平衡树进行一定的改造,这里的中序遍历并不容易实现。而在跳表上进行范围查找就非常简单,只需要在找到小值之后,对第 1 层链表进行若干步的遍历就可以实现。
  • 从算法的实现难度上来说,跳表比平衡树要简单很多:平衡树的插入和删除操作可能引发子树的调整,逻辑复杂,而跳表的插入和删除只需要修改相邻节点的指针,操作简单又快速。

相关文章:

【每日八股】Redis篇(二):数据结构

Redis 数据类型? 主要有 STRING、LIST、ZSET、SET 和 HASH。 STRING String 类型底层的数据结构实现主要是 SDS(简单动态字符串),其主要应用场景包括: 缓存对象:可以用 STRING 缓存整个对象的 JSON&…...

windows使用命令解压jar包,替换里面的文件。并重新打包成jar包,解决Failed to get nested archive for entry

有一个jar包,需要替换里面的文件,使用解压工具打开项目,然后找到对应的子包,再次打开,然后进行手工替换重新压缩成jar包后,发现启动服务报错Failed to get nested archive for entry。 使用下面的命令可实…...

2025电商与跨境贸易实战全解析:DeepSeek赋能细分领域深度指南(附全流程案例)

🚀 2025电商与跨境贸易实战全解析:DeepSeek赋能细分领域深度指南(附全流程案例)🚀 📚 目录 DeepSeek在电商与跨境贸易中的核心价值选品与市场分析:AI驱动的精准决策Listing优化与多语言营销:提升转化率的秘密物流与供应链管理:AI赋能的效率革命客户服务与私域运营:…...

驱动开发系列39 - Linux Graphics 3D 绘制流程(二)- 设置渲染管线

一:概述 Intel 的 Iris 驱动是 Mesa 中的 Gallium 驱动,主要用于 Intel Gen8+ GPU(Broadwell 及更新架构)。它负责与 i915 内核 DRM 驱动交互,并通过 Vulkan(ANV)、OpenGL(Iris Gallium)、或 OpenCL(Clover)来提供 3D 加速。在 Iris 驱动中,GPU Pipeline 设置 涉及…...

自动驾驶中planning为什么要把横纵向分开优化?

在自动驾驶系统中,将 横向(Lateral)规划 和 纵向(Longitudinal)规划 分开优化是一种常见的设计范式,其核心原理在于 解耦车辆运动控制的多维复杂性,同时兼顾 计算效率 和 安全性约束。以下从原理…...

Linux 命令大全完整版(06)

2. 系统设置命令 pwunconv 功能说明:关闭用户的投影密码。语法:pwunconv补充说明:执行 pwunconv 指令可以关闭用户投影密码,它会把密码从 shadow 文件内,重回存到 passwd 文件里。 rdate(receive date) 功能说明&a…...

第9章:LangChain结构化输出-示例2(数字提取服务)

如何使用LangChain4j框架创建和使用多种AI服务。它通过定义接口和注解,将自然语言处理任务(如情感分析、数字提取、日期提取、POJO提取等)封装为服务,并通过LangChain4j的AiServices动态生成这些服务的实现。 本章主要讲述基于Lan…...

每天五分钟深度学习pytorch:使用Inception模块搭建GoogLeNet模型

本文重点 前面我们学习了Incetption模块,它的作用类似于vgg块对于VGG网络模型一样,本文我们使用Inception搭建GoogLeNet网络,如果使用卷积层开始从头开始搭建GoogleNet,那么这样看起来会很不清晰,我们使用已经封装好的Inception来搭建GoogLeNet网络 关键点 关键点在于I…...

Ubuntu - Redis 安装、远程访问

参考教程: https://blog.csdn.net/houor/article/details/126672577 https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/ 查看是否安装 redis-cli --versionUbuntu 上安装 更新: sudo apt update …...

SpringBoot+Vue+微信小程序的猫咖小程序平台(程序+论文+讲解+安装+调试+售后)

感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,我会一一回复,希望帮助更多的人。 系统介绍 在当下这个高速发展的时代,网络科技正以令人惊叹的速度不断迭代更新。从 5G …...

二分查找算法的全面解析C++

一、核心原理与特性 二分查找是一种**对数时间复杂度(O(log n))**的高效搜索算法46,需满足两个前提条件: 数据存储在连续内存空间(如数组)数据按升序/降序有序排列35 算法通过折半比较缩小搜索范围: 初始化左右边界…...

深度学习(5)-卷积神经网络

我们将深入理解卷积神经网络的原理,以及它为什么在计算机视觉任务上如此成功。我们先来看一个简单的卷积神经网络示例,它用干对 MNIST数字进行分类。这个任务在第2章用密集连接网络做过,当时的测试精度约为 97.8%。虽然这个卷积神经网络很简单…...

第9章:LangChain结构化输出-示例3(日期和时间提取服务)

如何使用LangChain4j框架创建和使用多种AI服务。它通过定义接口和注解,将自然语言处理任务(如情感分析、数字提取、日期提取、POJO提取等)封装为服务,并通过LangChain4j的AiServices动态生成这些服务的实现。 本章主要讲述基于LangChain调用大模型如何进行结构化输出的真实…...

解决Open WebU无法显示基于OpenAI API接口的推理内容的问题

解决方案 把reasoning content的东西移到content中来 并在reasoning时,手动加上标签。具体做法是截获第三方api返回的stream,并修改其中的内容,再移交给open webUI处理。 在backend\open_webui\routers\openai.py中 找到 generate_chat_com…...

AI颠覆蛋白质工程:ProMEP零样本预测突变效应

概述 在生命科学的“造物革命”中,蛋白质工程一直面临着“试错成本”与“设计效率”的双重挑战——传统方法依赖繁复的多序列比对(MSA)或耗时的实验室筛选,如同在浩瀚的蛋白质宇宙中盲选星辰。而今日,一项发表于《Cel…...

QT闲记-状态栏,模态对话框,非模态对话框

1、创建状态栏 跟菜单栏一样,如果是继承于QMainWindow类,那么可以获取窗口的状态栏,否则就要创建一个状态栏。通过statusBar()获取窗口的状态栏。 2、添加组件 通常添加Label 来显示相关信息,当然也可以添加其他的组件。通过addWidget()添加组件 3、设置状态栏样式 …...

QQ登录测试用例报告

QQ登录测试用例思维导图 一、安全性测试用例 1. 加密传输与存储验证 测试场景:输入账号密码并提交登录请求。预期结果:账号密码通过加密传输(如HTTPS)与存储(如哈希加盐),无明文暴露。 2. 二…...

ipad连接电脑断断续续,不断弹窗的解决办法

因为ipad air 屏幕摔坏,换了一个内外屏,想用爱思检验一下屏幕真伪, 连接电脑时,断断续续,连上几秒钟然后就断开,然后又连上 然后又断开,不断地弹出信任的弹窗。 刚开始以为是数据线问题&#x…...

《FFTformer:基于频域的高效Transformer用于高质量图像去模糊》

paper:2211.12250 GitHub:kkkls/FFTformer: [CVPR 2023] Effcient Frequence Domain-based Transformer for High-Quality Image Deblurring CVPR 2023 目录 摘要 1、介绍 2、相关工作 2.1 基于深度CNN的图像去模糊方法 2.2 Transformer及其在图…...

std::call_once

std::call_once 是 C11 标准库中提供的一个线程安全的一次性调用机制&#xff0c;位于 <mutex> 头文件中。它用于确保在多线程环境中&#xff0c;某个函数&#xff08;或可调用对象&#xff09;仅被调用一次&#xff0c;无论有多少线程尝试调用它。这种机制常用于实现线程…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...