系列文章目录
Redis内存优化——String类型介绍及底层原理详解
Redis内存优化——Hash类型介绍及底层原理详解
Redis内存优化——List类型介绍及底层原理详解
Redis内存优化——Set类型介绍及底层原理详解
Redis内存优化——ZSet类型介绍及底层原理详解
Redis内存优化——Stream类型介绍及底层原理详解
文章目录
- 系列文章目录
- 前言
- Stream
- 概述
- 应用场景
- 底层原理
- Rax Tree
- Stream
- 总结
前言
Redis是一个开源的高性能键值数据库,它支持多种数据结构,如字符串、列表、集合、散列、有序集合等。在Redis 5.0版本中,新增了一种数据结构:Stream,它主要用于实现消息队列(MQ,Message Queue)
消息队列是一种异步通信机制,它允许多个生产者和消费者之间发送和接收消息,而不需要直接相互联系。消息队列有很多优点,如解耦、缓冲、重试、负载均衡、广播等。消息队列也有很多应用场景,如日志收集、任务调度、数据同步、事件驱动等。
Stream
概述
stream 是一个类似于日志的数据结构,它可以记录一系列的键值对,每个键值对都有一个唯一的 ID。一个 stream 类型的键最多可以存储 2^64 - 1 个键值对。
stream 类型的底层实现是 rax(基数树),它是一种压缩的前缀树结构,它将所有的键值对按照 ID 的字典序存储在一个树形结构中。rax 可以快速地定位、插入、删除任意位置的键值对
应用场景
stream 类型的应用场景主要是实现事件驱动的架构,比如:
- 消息队列,利用 xadd 和 xread 命令实现生产者消费者模式。
- 操作日志,利用 xadd 和 xrange 命令实现操作记录和回放。
- 数据同步,利用 xadd 和 xreadgroup 命令实现多个消费者组之间的数据同步。
底层原理
Rax Tree
rax tree是一种基于基数树(radix tree)的变体,也叫做压缩前缀树(compressed prefix tree),它被应用于redis stream中,用来存储streamID,其数据结构为
typedef struct raxNode {
uint32_t iskey:1; /* Does this node contain a key? */
uint32_t isnull:1; /* Associated value is NULL (don't store it). */
uint32_t iscompr:1; /* 前缀是否压缩 */
uint32_t size:29; /* Number of children, or compressed string len. */
unsigned char data[];
} raxNode;
iskey
:是否包含keyisnull
:是否存储value值iscompr
:前缀是否压缩。决定了size
存储的是什么和data
的数据结构size
:iscompr=0
:节点为非压缩节点,size
是孩子节点的数量iscompr=1
:节点为压缩节点,size
是已压缩的字符串长度
data
:iscompr=0
:节点为非压缩节点,数据格式为[header strlen=0][abc][a-ptr][b-ptr][c-ptr](value-ptr?)
。其有size个字符,iscompr=1
:节点为压缩节点,数据格式为[header strlen=3][xyz][z-ptr](value-ptr?)
。
为了便于理解,设定一些场景举例说明
场景一:只插入foot
数据结构为:
其中,z-ptr
指向的叶子节点的iskey=1
,标识foot
这个key。下图为使用树状图的形式来展现其数据结构
场景二:插入foot后,插入footer
数据结构为:
其插入过程为:
- 与foot节点中每个字符进行比较,获得最大公共前缀
foot
- 将er作为foot的子节点,其
iskey=1
,标识foot
这个key - 将er的子节点的
iskey=1
,标识footer
这个key
下图为使用树状图的形式来展现其数据结构
场景三:插入foot后,插入fo
数据结构为:
其插入过程为:
- 与foot节点中每个字符进行比较,获得最大公共前缀
fo
- 将foot拆成fo和ot
- 将ot作为fo的子节点,其
iskey=1
,标识fo
这个key - 设置ot的子节点的
iskey=1
,标识foot
这个key
下图为使用树状图的形式来展现其数据结构
场景四:插入foot后,插入foobar
数据结构为:
其插入过程为:
- 与foot节点中每个字符进行比较,获得最大公共前缀
foo
- 将foot拆成foo和t
- 将footbar拆成foo、b、ar
- 将t、b作为foo的子节点
- 设置ot的子节点的
iskey=1
,标识foot
这个key - 将ar作为b的子节点
- 设置ar的子节点的
iskey=1
,标识footbar
这个key
下图为使用树状图的形式来展现其数据结构
Stream
stream的底层使用了rax tree
和listpack
两种结构,rax tree
用来存储streamID,而listpack
用来存储对应的值,结构图如下:
总结
本文介绍了Redis Stream的类型介绍及底层原理。Redis Stream是一种非常强大和灵活的数据结构,它不仅可以实现高级消息队列的功能,还可以支持多种模式和场景。Redis Stream是Redis 5.0版本中新增加的数据结构,它体现了Redis作为一个开源项目不断创新和进步的精神。