redis数据结构

本文详细介绍了Redis,一种基于内存的高速缓存数据库,探讨了其数据结构如String、List、Set、Hash和Zset的应用,以及发布/订阅模式、Stream消息队列和时间回拨问题的解决方案。
摘要由CSDN通过智能技术生成

redis优势

Redis是缓冲中间件,是C语言编写的基于内存的高速缓存数据库,key-value存储系统结构,包含丰富的数据类型,string,list,set,zset,hash

Redis中提供很多功能

  • 缓存,事件发布或订阅,高速队列等场景
  • 丰富数据结构用于直接存取
  • 基于内存速度快
  • 可持久化

五种基础数据结构

  • String
  • List
  • Set
  • Hash
  • Zset

![[Pasted image 20240423102833.png]]

String

Redis中String是二进制安全的,可以存储任何数据: 数字,字符串,图片,序列化对象等
二进制安全: char[]本质还是数组,只不过不是\0结束,弄了个新数组数据结构

List

Redis中List是双向链表,可以用来当做stack,queue等
使用列表的技巧

  • lpush+lpop=Stack(栈)
  • lpush+rpop=Queue(队列)
  • lpush+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息队列)

Set集合

Redis中Set是String类型的无序集合,删除,查找,新增复杂度都是O(1)

Hash散列

Redis中Hash是一个String的字段key和value的映射表,适合用来存储对象

如果要嵌套对象存储: 将对象序列化(JSON等)

Zset有序集合

Redis中ZSet也是一个String类型的元素集合,不允许重复,但是每个元素有关联一个double类型的分数,Zset就是通过分数来给集合中成员进行从小到大的排序

有序集合成员唯一,但是分数不用,一般是下面两种数据结构

  1. 压缩列表(ziplist): ziplist是为了提高存储效率而设计的一种特殊编码的双向链表。它可以存储字符串或者整数,存储整数时是采用整数的二进制而不是字符串形式存储。它能在O(1)的时间复杂度下完成list两端的push和pop操作。但是因为每次操作都需要重新分配ziplist的内存,所以实际复杂度和ziplist的内存使用量相关
  2. 跳跃表(zSkiplist): 跳跃表的性能可以保证在查找,删除,添加等操作的时候在对数期望时间内完成,这个性能是可以和平衡树来相比较的,而且在实现方面比平衡树要优雅,这是采用跳跃表的主要原因。跳跃表的复杂度是O(log(n))。

压缩列表 ziplist

为什么列表不用链表而是用zipList?

  • 因为链表是分散存储的,对于内存管理不友好,每个节点都占用独立一块内存容易产生内存碎片
  • 指针占用额外开销

zipList优势

  • 分配一小块连续空间来作为链表内存,没有内存碎片
  • 只用记录节点大小,和前面节点大小,就能起到双向链表的作用,无需存储指针内存的开销

zipList的缺陷:

  • 内存限制:如果分配的连续内存空间不足,则整个zipList的所有节点都要重新分配内存创建
  • 级联更新,如果添加和删除节点,可能导致影响后续所有节点.例如previous_entry_length是根据长度分配的直接,之前前面是一个字节长度的节点,现在插入了256个字节,那么此节点分配的一个长度直接无法满足,一次只能扩展,如果此时长度正好发生变化,后续节点也要扩展

跳跃表

特殊数据结构

HyperLogLogs

Bitmap

geospatial

发布订阅模式

发布-订阅是很常见的设计模式,存在两个角色:订阅者(用于接受消息),发布者(用于发送消息).
订阅者订阅一个或者多个频道,每当发布者有新消息发布到频道,则会将消息通知给所有订阅者.角色关系如下:
在这里插入图片描述

redis有两种发布/订阅模式

  • 基于频道(Channel)的发布/订阅
  • 基于模式(Pattern)的发布/订阅
基于频道

命令:

命令描述
PUBSUB subcommand查看订阅和发布系统状态
PUBLIST channel message将消息发送给对于channel
SUBSCRIBE channel订阅给定的一个或者多个频道
SUBSCRIBE chanenel退订指定频道

执行subscribe客户端进入订阅状态

  • 客户端此时只能使用subscribeunsubscribepsubscribepunsubscribe这四个属于"发布/订阅"之外的命令,否则会报错
  • 客户端会接收到发布的消息,存在多个返回消息类型,格式如下:第一个是消息类型,第二三个会根据类型有区别,如下:
    • subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个是当前客户端订阅的频道数量。
    • message。表示接收到的消息,第二个值表示产生消息的频道名称,第三个值是消息的内容。
    • unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态,之后就可以执行其他非"发布/订阅"模式的命令了。
基于模式(pattern)

命令:

命令描述
PUBSUB subcommand查看订阅和发布系统状态
PUBLIST pattern message将消息发送给对于模式
PSUBSCRIBE channel订阅给定的一个或者多个模式
PUNSUBSCRIBE chanenel退订指定模式

发布订阅模式底层实现

基于channel

数据结构
channel其实就是字典实现的,每个字典保存了channel和订阅者信息,既字典key是channel name, values则是以链表形式保存的订阅者信息.

数据结构图如下:
在这里插入图片描述

订阅
在对应字典中找到Channel对应的订阅者信息链表,添加到链表中

发布
通过channel name找到对应订阅者信息,然后将message发送给每个订阅者.

取订
去掉channel对应链表中的订阅者信息

基于模式

底层是由存储pattern信息的节点所构成的链表。

在这里插入图片描述

订阅:
每当调用 PSUBSCRIBE 命令订阅一个模式时, 程序就创建一个包含客户端信息和被订阅模式的 pubsubPattern 结构, 并将该结构添加到 redisServer.pubsub_patterns 链表中

发布:
遍历遍历,模式匹配的则发送message

退订:
去掉所在pubsubPattern节点

Stream详解

Stream是redis用做消息队列的数据结构

stream的结构:

![[Pasted image 20240426150620.png]]

  • Consumer group 消费者组,由多个消费者构造
  • Last_delivered_id 游标,指向消费组下一个要消费的消息,当消费组接受消息后,游标会向前移动
  • pending_ids: 消费者状态变量, 用于维护消费者未确认的消息ID. pending_ids 记录了当前已经被客户端读取的消息,但是还没有 ack,用来确保数据一定被消费消费至少一次.

stream消费者

独立消费: 把stream当做队列来处理

消费组消费:

Stream场景问题

Redis中消息ID的设计-考虑了时间回拨

redis消息: 时间戳+序列

时间回拨是什么?
系统时间回调,导致当前时间小于之前生成的时间,从而可能导致后续生成的ID可能重复

redis怎么解决?
redis中生成的序列ID是单调递增的,每个stream中保留一个last_generated_id,用于记录最后一个消息,当服务器时间错误(时间回拨),小于last_generated_id时间戳, 则会采用时间戳不变,序列号递增的方式,从而保证消息ID的唯一性

消费者崩溃,会不会导致消息丢失?

Redis中有Pending列表,用于记录消费者没返回ack的消息ID列表,可以通过获取xpending命令查看消费组内没处理完的消息

pengding消息属性

  • 消息ID
  • 所属消费者
  • 已读取时长
  • 读取次数

只有通过ACK返回后,才会从pending list中去掉消费的消息,有了这样一个Pending机制,就意味着在某个消费者读取消息但未处理后,消息是不会丢失的。等待消费者再次上线后,可以读取该Pending列表,就可以继续处理该消息了,保证消息的有序和不丢失。

消费者宕机后,不再上线,如何用其他消费者替代其处理

消费宕机不再上线,那么其未消费的消息,需要新消费处理.

redis中存在消息转移: 通过xclaim命令将一个消费组中pending List内容转移到其他消费者,转以后IDLE会重置,避免重复转移

xclaim命令: 需要设置组、转移的目标消费者和消息ID,同时需要提供IDLE(已被读取时长),只有超过这个时长,才能被转移.

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值