Redis学习-Redis的九种数据结构

String (字符串)

虽然redis是用C语言编写,但是redis中的string是redis自己实现的字符串结构,叫Simple Dynamic String简称(SDS),因为redis做为中间件会接受不同语言编写的程序传过来的字符串,它们都可能和C语言中的字符串结构不一样,例如C语言中以’\0’表是字符串的结尾,当传过来的二进制数据转换成C语言中的字符串中间有’\0’那么C语言就会认为这个字符串已经结束了,则后面的数据就丢失了。redis中的string包含四部分:一个char类型的数组buff、一个len记录已经使用的长度、一个flags标识当前string的头信息以及一个alloc记录给当前string分配的大小。当客户端通过append或者setbit命令对string进行操作时,如果增加的字符串长度小于等于alloc-len则还是在当前string内存空间中直接添加即可,如果超出了string中剩余空间,则会重新分配一块内存,大小为新的字符串的长度*2(如果字符串的大小超过1mb则之后的扩容不会翻倍扩容而是每次增加1mb)。string最大的大小为512MB

使用场景

  • 计数器:Redis的原子递增操作可以用来实现Web应用中的各种计数功能,如页面访问计数、点赞数、评论数等。
  • 分布式锁:在需要保证操作原子性的场景下,比如防止多个用户同时修改同一资源,可以使用Redis的String类型实现分布式锁。
  • 会话共享:在多实例部署的Web应用中,可以使用Redis来存储用户的会话信息,实现会话共享,避免因会话问题导致的登录失效。
  • 限流:通过设置特定的key来限制用户在一定时间内的请求次数,如短信验证码的发送频率控制,防止滥用。
  • 全局序列号生成:在分布式系统中,可以使用Redis生成全局唯一的序列号,适用于订单号、票据号等。
  • 消息队列:虽然不是String类型的直接应用,但可以通过List或Pub/Sub功能来实现消息队列,处理异步任务或事件通知。
  • 存储JSON对象:将序列化后的JSON对象存储在Redis的String类型中,用于快速读取和修改,如用户配置、系统状态等,(如果对象中的某些字段经常修改时,建议用hash存储)。
  • Webhook触发器:存储Webhook URL,当特定事件发生时,通过调用这些URL来触发外部服务。
  • 分布式系统间的通信:在微服务架构中,Redis可以作为不同服务间的通信桥梁,传递轻量级的消息或数据。
  • 缓存静态资源:将不经常变动的静态资源如图片、CSS和JavaScript文件缓存到Redis中,以减少数据库和文件系统的压力。
  • 用户个性化设置:存储用户的个性化设置,如主题偏好、界面布局等,以便快速加载用户定制的界面。

常用命令

set key value//存储字符串键值对
mset key value [key value....]//批量存储字符串键值对
setnx  key value//存入一个不存在的字符串键值对
get key//通过key获取value
mget key [key....]//批量获取value
del key [key....]//删除键值对
expire key seconds//设置过期时间
setex key seconds value//存储键值对并设置过期时间(秒)
psetex key milliseconds value//存储键值对并设置过期时间(毫秒)
append key value//key存在则追加字符串,不存在则设置
incr key//将key对应的数字值加一
decr key//将key对应的数字值减一
incrby key increment//将key对应的数字值加increment 
decrby key increment//将key对应的数字值减increment 

hash(散列)

redis的K-V键值对用的结构是dict,hash用的也是这个结构,类似于java中的hashtalbe,先有一个数组假设长度是4,当hset key field value时,将field通过hash算法如CRD16(field)计算得到一个0-65535之间的一个整数,再和数组长度取模得到这个field在数组中的位置,如果这个位置已经有了数据则将当前的value加入对应的链表中(当前的value为首节点)。
hash表中有一个重要的参数叫负载因子(负载因子 = used / size ; used 是哈希数组存储的元素个数,size 是哈希数组的长度)。当负载因子过大或过小,hash表会进行扩展或缩容,这两种都是通过渐进式rehash的方式完成的。
渐进式rehash:当哈希表中的元素过多时,如果一次性rehash到新的hashtable里,庞大的计算量,可能导致redis服务在一段时间不可用。为了避免rehash对服务器带来的影响,redis分多次、慢慢的将原本的哈希表中的键值对rehash到新的哈希表,这就是渐进式rehash
注:使用hash结构时,应避免单个hash结构过大,否则使用hgetall的操作时可能会导致线程阻塞,而且field是无法单独设置过期时间的

使用场景

类似于电商购物车这样的需要对对象中某一属性频繁修改的数据。

常用命令

HSET key field value//存储一个哈希表key的键值
HSETNX key field value//存储一个不存在的哈希表key的键值
HMSET key field value [field value ...]//在一个哈希表key中存储多个键值对
HGET key field//获取哈希表key对应的field键值
HMGET key field [field ...]//批量获取哈希表key中多个field键值
HDEL key field [field ...]//删除哈希表key中的field键值
HLEN key//返回哈希表key中field的数量
HGETALL ey//返回哈希表key中所有的键值
HINCRBY key field increment//为哈希表key中field键的值加上增量increment

list(列表)

一个有序的链表结构,使用quicklist和ziplist实现。
当List满足以下两个条件时,使用Ziplist编码:

  • 列表中的元素数量小于或等于list-max-ziplist-entries配置(默认512个)。
  • 列表中每个元素的长度小于或等于list-max-ziplist-value配置(默认64字节)

在这里插入图片描述
ZipList虽然节省内存,但申请内存必须是连续空间,如果内存占用较多,申请内存效率很低。所以我们必须限制ZipList的长度和entry大小。当list中的元素大小超过list-max-ziplist-value或者元素个数超过list-max-ziplist-entries,就会使用quciklist编码,将一个list拆分成多个小的ziplist,ziplist作为quicklist的节点,由quicklist来控制多个ziplist之间的联系。
配置参数:

  • list-max-ziplist-size:控制着每个ziplist的最大长度,超过这个长度时,Redis会创建新的ziplist。
  • list-compress-depth:控制着压缩的层数,即在进行列表操作时,Redis会从外到内压缩多少层ziplist。

quickList结构如下:

  • head:quickListNode头节点
  • tail:quickListNode尾节点
  • count:所有的ziplist中的entry总数量
  • len:ziplist节点数量
  • fill:ziplist中entry的上限,默认为-2
  • compress:首尾节点不压缩的个数,若设置为1,则首尾节点各有一节点不压缩,中间节点压缩,中间节点压缩为0x4…等乱码,读的时候需要解压缩;写的时候需要重新压缩;设置为0,则代表所有节点不压缩

quickListNode结构如下:

  • prev: 前一个节点指针
  • next:后一个节点指针
  • zl: 当前节点ziplist指针
    具体结构如图
    在这里插入图片描述

使用场景

  1. Stack(栈) = LPUSH + LPOP
  2. Queue(队列)= LPUSH + RPOP
  3. Blocking MQ(阻塞队列)= LPUSH + BRPOP

常用命令

LPUSH key value [value ...]//将一个或多个值value插入到key列表的表头(最左边)
RPUSH key value [value ...]//将一个或多个值value插入到key列表的表尾(最右边)
LPOP key//移除并返回key列表的头元素
RPOP key//移除并返回key列表的尾元素
LRANGE key  start stop//返回列表key中指定区间内的元素,区间以偏移量start和stop指定
BLPOP key [key ...] timeout//从key列表表头弹出一个元素,若列表中没有元素,阻塞等待					timeout秒,如果timeout=0,一直阻塞等待
BRPOP key [key ...] timeout//从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待					timeout秒,如果timeout=0,一直阻塞等待

set (无序集合)

set是一个无序的、自动去重的集合数据类型,它的基本数据结构就是value为null的dict,当set中存储的元素都是整型,且set中元素的个数没有超过set-max-intset-entries(默认512,intset能存储的最大元素个数)的大小,则set集合编码为intset结构。

使用场景

  1. 抽奖
  2. 微信朋友圈点赞用户列表
  3. 微博我关注的人、共同关注、朋友推荐

常用命令

SADD key member [member ...]//往集合key中存入元素,元素存在则忽略,若key不存在则新建
SREM key member [member ...]//从集合key中删除元素
SMEMBERS key//获取集合key中所有元素 点赞用户列表
SCARD key//获取集合key的元素个数 点赞数量
SISMEMBER key member//判断member元素是否存在于集合key中 是否点赞
SRANDMEMBER key [count]//从集合key中选出count个元素,元素不从key中删除 单次抽奖
SPOP key [count]//从集合key中选出count个元素,元素从key中删除 一等奖 二等奖 三等奖 且不能重复获奖的情况
SINTER key [key ...]//交集运算 共同关注
SINTERSTORE destination key [key ..]//将交集结果存入新集合destination中
SUNION key [key ..]//并集运算
SUNIONSTORE destination key [key ...]//将并集结果存入新集合destination中
SDIFF key [key ...]//差集运算 朋友推荐 
SDIFFSTORE destination  key [key ...]//将差集结果存入新集合destination中

Sort set (有序集合)

sortset是一个有序且去重的集合,当数据量较小时使用ziplist结构编码,当到达一定数量时使用dict+skiplist的结构去实现。
ziplist结构编码使用条件

  • 元素数量小于zset_max_ziplist_entries,默认值128
  • 每个元素都小于zset_max_ziplist_value,默认值64byte

ZipList本身没有排序功能,而且没有键值对的概念,因此存储sortset时score和element是紧挨在一起的两个entry,element在前,score在后,Score越小越接近队首,score越大越接近队尾,按照score值升序排列。
skiplist基于score进行排序,每个节点存有索引数组,所以有多个索引层级,优先从最高的层级查询,依次往下级索引查询,每个节点都有指针(每个指针的跨度可能不同)指向上一个和下一个节点,所以skiplist还是一个双向链表,具体结构如图:

  • 逻辑图:
    在这里插入图片描述
  • 实际结构:
    在这里插入图片描述

使用场景

  1. 排行榜,例如微博热搜top10

常用命令

ZADD key score member [[score member]]//往有序集合key中加入带分值元素
ZREM key member [member …]//从有序集合key中删除元素
ZSCORE key member//返回有序集合key中元素member的分值
ZINCRBY key increment member//为有序集合key中元素member的分值加上increment 
ZCARD key//返回有序集合key中元素个数
ZRANGE key start stop [WITHSCORES]//正序获取有序集合key从start下标到stop下标的元素
ZREVRANGE key start stop [WITHSCORES]//倒序获取有序集合key从start下标到stop下标的元素
ZUNIONSTORE destkey numkeys key [key ...]//并集计算
ZINTERSTORE destkey numkeys key [key …]//交集计算

bitmap(位图)

基于string类型实现,相当于是对一个二进制的字符串进行操作,每个位都表示一个数据,0和1表示不同的两种状态。

使用场景

  1. 布隆过滤器:将数据经过哈希算法和取模,最终数据可以落在bitmap的某一个位上,将这个位设为1,查询时如果存在,可能因为哈希冲突的问题不能确认当前记录是否存在,但是如果获取不到则一定不存在,可用于缓存穿透问题中对大部分系统内没有的数据进行过滤
  2. 用户登录:一个string最大长度是512MB,则一个bitmap最大可以记录一天内51210241024*8 = 4294967296个用户的登录情况

常用命令

setbit key offset value//对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。当 key 不存在时,自动生成一个新的字符串值。未设置的位置以 0 填充。
getbit key offset //对 key 所储存的字符串值,获取指定偏移量上的位(bit)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0
bitop operation destkey key [key ...]//对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种
bitop and destkey key [key ...]//获取指定的天数都有登录的用户
bitop or destkey key [key ...]//指定天数中登录过的用户
bitcount key [start] [end]//计算给定字符串中,被设置为 1 的比特位的数量。

HyperLogLog(超日志)

HyperLogLog(HLL)是一种概率数据结构,用于估计集合中唯一元素的数量,而不需要存储这些元素本身。

使用场景

  1. 可用于统计大数据量且不重复的数据,例如一个页面的用户访问量,用户需要去重的情况

常用命令

PFADD key elemet [elemet...]# 添加元素到HyperLogLog
PFCOUNT key#获取HyperLogLog的基数估计值
PFMERGE destkey key[key...]# 合并多个HyperLogLog

Geospatial(地理空间)

地图经纬度信息,基于Sort set实现,存入时会将经纬度通过GeoHash算法转换为整数作为score存入sort set

使用场景

  1. 计算两点之间的距离
  2. 附件的人

常用命令

GEOADD key longitude latitude member [longitude latitude member ...]//将一个或多个指定的地理位置(经度和纬度)添加到给定的键(key)中。
GEOPOS key member [member ...]//返回一个或多个在键(key)中已存储的地理位置的坐标(经度和纬度)。
GEODIST key member1 member2 [m|km|mi|ft]//计算两个地理位置之间的距离。
GEORADIUS key longitude latitude radius m|km|mi|ft [WITHCOORD] [WITHDIST]//返回给定中心坐标和半径内的所有地理位置。
GEORADIUSBYMEMBER key member radius m|km|mi|ft [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]//返回与给定位置名称为中心的指定半径内的所有地理位置。
GEOHASH key member [member ...]//返回一个或多个位置对象的Geohash表示。

Stream (流)

  1. redis最早可以使用list来实现消息队列,但是list只能由一个消费者消费,不能广播。
  2. 之后redis引入了发布/订阅模式,l引入一个概念叫channel,生产者通过publish接口投递消息时会指定channel,消费者通过subscribe接口订阅它关心的channel,调用subscribe后这条连接会进入一个特殊的状态,通常不能在发送其他请求,当有消息投递到这个channel时Redis服务端会立刻通过该连接将消息推送到消费者。这里一个channel可以被多个应用订阅,消息会同时投递到每个订阅者,做到了消息的广播。另一方面,消费者也可以订阅一批channel。这解决了List结构单播的局限,允许一个消息被多个客户端接收。但是pub/sub模式中,是不管消费者是否接受到消息的,发完广播消息就删掉了,所以容易出现消息丢失的问题。
  3. redis在5.0之后引入了stream,提供了消息持久化,消费者群组,消费者待确认消息列表以及消费者确认消息的功能

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

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

相关文章

Oracle Hint 语法详解

什么是Hint Hint 是 Oracle 提供的一种 SQL 语法,它允许用户在 SQL 语句中插入相关的语法,从而影响 SQL 的执行方式。 因为 Hint 的特殊作用,所以对于开发人员不应该在代码中使用它,Hint 更像是 Oracle 提供给 DBA 用来分析诊断问…

Python中pyside2出现的pyside2 qt platform plugin could be in错误及其解决方法

系统平台:Win10 64bit python版本: python 3.8 使用pip install pyside2安装 pyside2 这是找不到QT平台的插件,这是环境变量QT_QPA_PLATFORM_PLUGIN_PATH出现错误 具体解决方法: 我们可以在每一段程序开始之前设定环境变量&…

pytorch与深度学习

ChatGPT PyTorch是一个由Facebook AI Research Team开发的开源深度学习库,它提供了一个灵活的环境和丰富的API,用于快速且方便地构建、训练和部署深度学习模型。PyTorch在科学界和工业界都收到了广泛的使用,其中包括了学术研究、小型项目和大…

第50篇:算法的硬件实现<一>

Q:本期我们来开始介绍如何使用算法状态机(ASM)图在硬件开发板上实现算法。 A:算法状态机 (Algorithmic State Machine,ASM) 图是描述数字系统控制单元的工作流程图,主要用来描述控制单元的时序操作特性&am…

功能测试用例设计思路

我们为什么要写好一份测试用例呢?测试同学应该都知道测试用例的重要性,测试用例就是我们测试的依据,也是测试过程中不能缺少的测试文档。 一、用例编写规范目的: 1、提高测试用例的可读性,可执行性、合理性。 2、测试…

Spring(下)

接上篇,从第八个问题讲起 八.Spring工厂创建复杂对象 1.什么是复杂对象 简单对象就是可以直接new出来的,也就是直接调用构造方法创建 所以复杂对象就是不能直接通过调用构造方法创建。就比如JDBC中的Connection 2.三种方法 (1&#xff…

4月阿里offer被毁,我该怎么进字节?

在校招求职的浪潮中,有些故事总是让人唏嘘不已。比如最近在社交平台上广泛讨论的一个话题:“4月阿里offer被毁,我该怎么进字节?”这不仅反映了当下职场的变动性,也映射了求职者在面对突如其来的变故时的无助与挣扎。 …

基于springboot实现精准扶贫管理系统项目【项目源码+论文说明】计算机毕业设计

基于SpringBoot实现精准扶贫管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了精准扶贫管理系统的开发全过程。通过分析精准扶贫管理系统管理的不足,创建了一个计算机管理精准扶贫管理系…

docker-003镜像制作

步骤 使用docker commit提交容器使之成为镜像以ubuntu安装vim后的容器为例 1 ubuntu安装vim 启动容器 docker run -it --nameubuntu-vim ubuntu /bin/bash安装vim apt-get update apt-get install vim2 提交容器作为镜像 查看容器 docker ps -a提交容器作为镜像 命令格式&…

随机森林计算指标重要性—从决策树到随机森林Python实现

文章目录 前言一、节点二、决策树2.1 案例分析——优良的水稻2.2 案例分析——家庭财富水平 三、随机森林三、Python代码实现3.1 关键问题3.1.1 节点的表示3.1.2 决策树的表示** 根节点划分左右子树的依据 **3.1.3 随机森林的构造与重要性的表示 3.2 节点类3.2 决策树类3.2.1 初…

阿里云OSS对象存储的使用和快速入门

一、介绍 云存储是一种通过互联网连接的服务,允许用户将数据存储在远程的云服务器上,而不是存储在本地设备上。这些数据可以包括文件、数据库、备份等各种类型的信息。云存储服务提供商通常会管理和维护这些存储设施,并提供用户可以访问、管…

c语言中的数组

数组 数组是一种构造类型,是由基本类型构造而成。当我们想用一群变量来描述同一类相同的东西时候,比如100个年龄变量,我们可以这样int age1;int age2;int age3;……int age 100;这样即不方便书写&#xff…

【公司UI自动化学习】

公司课程链接:https://l.jd.com/student/project/project.du?project_id697509403 公司的课程,是给一个学习方向。 一、 PC自动化 1)什么项目适合 2)PC自动化介入时间点 3)自动化率: 频繁改动的&…

自动化测试Selenium(3)

目录 WebDriver相关API 打印信息 打印title 打印url 浏览器的操作 浏览器最大化 设置浏览器的宽,高 操作浏览器的前进, 后退, 刷新 控制浏览器滚动条 键盘事件 键盘单键用法 键盘组合按键用法 鼠标事件 WebDriver相关API 打印信息 打印title 即打印该网址的标题.…

SAP 销售业务中免费货物的会计核算

此博文主要介绍SAP销售业务中免费货物解决方案中,免费货物的会计核算。如果需要进一步了解SAP SD 销售与分销业务中,免费货物的标准解决方案概览,可先了解本博客博文:SAP销售与分销中的免费货物解决方案相关文章: htt…

负采样重要吗?它的理论与应用综述

Does Negative Sampling Matter? A Review with Insights into its Theory and Applications 负采样重要吗?它的理论与应用综述 Does Negative Sampling Matter? A Review with Insights into its Theory and Applications Zhen Yang, Ming Ding, Tinglin Huang,…

一文掌握运维绩效考核指标及实例参考

运维绩效考核需要综合考虑公司的战略和目标,确保考核公正和合理,同时还需要建立合适的管理和收集系统,根据绩效结果进行反馈和奖惩,并落实改进措施。 运维团队合理的绩效考核非常重要,以激励团队成员不断提高,同时确保团队目标的实现。针对运维团队的绩效评估,我们通常…

十一、Yocto集成tcpdump等网络工具

文章目录 Yocto集成tcpdump等网络工具networking layer集成 Yocto集成tcpdump等网络工具 本篇文章为基于raspberrypi 4B单板的yocto实战系列的第十一篇文章: 一、yocto 编译raspberrypi 4B并启动 二、yocto 集成ros2(基于raspberrypi 4B) 三、Yocto创建自定义的lay…

JVM(java虚拟机 详解三个主要的话题:1.JVM 中的内存区域划分2.JVM 的类加载机制3.JVM 中的垃圾回收算法)

jdk java开发工具包 jre java运行时环境 jvm java虚拟机 JDK、JRE、JVM之间的关系? JDK(Java Development Kit):Java开发工具包,提供给Java程序员使用,包含了JRE,同时还包含了编译器javac与自带的调试工具Jconsole、jstack等。…

【Java】实现一个简单的线程池

📝个人主页:哈__ 期待您的关注 一、线程池的模式 线程池顾名思义就是管理线程的一个池子,我们把创建线程的过程交给线程池来处理,而这个线程池当中的线程都会从阻塞队列当中取获取任务执行。 我们不在直接把任务的创建过程写到…