Redis stream 方案
#1634
Replies: 1 comment
-
需求原始是想从项目从redis迁移到pika, 原来是用了redis的mq机制,不需要严格的mq服务器那种的,希望pika有这块的实现能迁移过来就很ok了 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
原文档链接:https://t8dj523v5p.feishu.cn/wiki/YRmJwKI5oiPYtLkiQfcczmd2ndd
by 周开颜
这个 stream 功能对于 redis 来说是相对比较独立的,和其它模块耦合性非常低,同理 pika 应该也一样
实现需求上的疑问
实现原则
是做一个允许消息丢失的mq(比如 redis),还是一个百分百可靠的mq?
需要实现的指令
具体要做到什么程度,是要做到跟 redis 一样的功能以及兼容其所有指令么?(redis stream 的实现代码,除了数据结构和测试代码,本身有 4000 多行,工作量初步看起来其实有点大,如果真的有这个需求,我可以当作一个长期的 issue 去做)
参考 redis 的指令,总共有 21 条指令(https://redis.io/commands/?group=stream)
其中核心指令有以下几条
其中比较关键的概念是
消费组
,每个组可以互相独立地消费消息,但组内的成员对消息是竞争消费关系。指令具体使用以及详细解析:
redis stream 实现原理
宏观结构
宏观上来看所谓消息队列其实就是一个 List,链头通过插入的方式发布消息,链尾则以向前遍历的方式进行消费。
通常来说,消息队列除了队列的性质,还需要支持对消息的快速查找,所以一般的实现方式都是一个类似于跳表的形式加上索引结构。前者用于保持队列的性质,后者用于低时间复杂度的查找。
数据结构:radix tree
redis stream 中,针对每一条消息,都必须设置唯一且递增的消息 ID。
这种一段时间内的连续 ID,前缀都有一些高度重复性,所以用这类前缀树可以有效节约空间使用率。
除了用于存储消息,同 hash_map 的使用方式类似,它还被用来存储以下关系。
数据结构:listpack
*A lists of strings serialization format:*一个字符串列表的序列化格式,也就是将一个字符串列表进行序列化存储。
简单的理解 listpack 就是一款专门为
节省内存空间
,通过特定的编码方式将数据进行编码和解码的数据结构,这种结构天生就是为节省空间而存在的。总的来看,每个 stream 都用对应一个 radix tree,value 则存储了一个指向 listpack 的指针,同一个 listpack 可能存储多个消息的 value。
新的消息条目会被添加到Listpack中。如果添加新条目后的Listpack大小超过了设定的限制,那么会从Radix Tree中分裂出一个新的Listpack来存储超出的数据。
多播支持
实际上就是对消费组的支持,主要需要注意以下细节:
持久化方案
理论上需要将 stream 和其用到的数据结构对 RDB 和 AOF 做支持。
RDB 支持:
参考博客
pika 具体实现方式(实现文档初稿,进行中)
命令注册
所有命令在以下文件夹中与cmd_table绑定(以 LPUSH 为例)
其次在下方文件声明对应的命令,继承于 Cmd 类
最终通过 Do 函数,传递到命令的具体实现位置
(原来 wiki上有现成的 https://www.cnblogs.com/sigma0-/p/12831546.html)
实现位置
Stream 类算是一个存储抽象,应该是在 storage 中实现?
基础数据结构
Pika 的存储结构
疑问:代码里面并没有看到 blackwidow 相关的概念。倒是大致看到了以下的结构:
从存储的实现上来看,最底层是一个叫做
Redis
的类,在Redis的基础上,分别派生出了string
,set
,lists
,hash
,zset
几个存储结构,它们的实现都是基于 RocksDB 的实例:在一个 storage 抽象中会同时拥有上述五种存储的实例(这个也和文档上的 blackwindow 概念相似)
命令在解析和执行时,有个关键的步骤用于获取 storage 实例。后续命令的实现,会从 slot 获取具体的 storage,并执行相应的操作。
Stream 的结构
stream 初步来看有三种实现方式,前两种实现方式较为现实
直接用 blackwidow 实现的结构,比如 List 和 Hash
类似 blackwidow 的实现,直接在 RocksDB 上封装一层实现?
抠 rax-tree 和 listpack,或者手写数据结构。
实现细节
命令解析
应该有大部分现成的解析代码,只需要正确链接到指令对应的实现函数就行
主要功能
我理解的主要功能包含:
Group => Stream
的映射,需要用一个可持久化的 hash 结构来实现,redis 中使用的是 ratix tree, pika 中可能可以用 RocksDB 来存储。除此之外,还需要存储一些相关的元数据。Consumer => Group
的映射,以及一些元数据。持久化
如果用 RocskDB 实现,应该不用直面持久化的问题,但是暂时还不知道 pika 恢复的流程,stream 相关的元数据也要额外考虑。
兼容主从复制
注意到每条命令都有一个如下的函数,应该是用于生成 binlog 的函数,应该需要自己实现?
既然 Binlog 有了,按道理主从复制的逻辑不会和 Stream 的具体实现耦合度太高。
Beta Was this translation helpful? Give feedback.
All reactions