本学习笔记概述了流数据的定义、特性、访问模式和典型系统
Overview
流数据(stream)一种数据的组织方式(其他组织常见的组织方式例如关系型数据,图数据,宽表等)
流是抽象程度比较高的数据类型,发布订阅模式 和 消息队列 均可以看做是流数据的某种访问模式。流的分组消费模式是发布订阅和消息队列的集大成者,是一种复杂但能够解决许多业务场景的数据基础设施。
基本特性
最关键的特性包括时序性 和无界性
时序性: 流数据中的单个元素一般随时间流动产生。在真实系统中的流数据一般都会用各种时间戳的变体来做ID。在这个角度来看流数据和时序数据有一定的相似性。
无界性: 在系统开始运行后,流数据会源源不断的随时间流逝而产生。
数据无限但存储有限,因而常见的流处理系统也会配备相应的回收机制避免流数据无限制的增长。例如Redis Stream 的 xTRIM
命令和Kafka
的 Rententaion Policy
;常见的回收机制包括基于容量的(最多保存N条信息)和基于时间的(最多保留长达N秒的信息)
一些其他的特性包括
- 唯一性: 如何确保消息只被消费一次?
- 多样性: 相比于关系型数据,流数据的
schema
是松散的 数据多样性导致数据质量可能较差,因而面向错误case 设计对于流处理系统可能直观重要.
访问模式
顺序读取
顺序读取类似于在Linux系统上对某个文件使用tail -f
: 读取端监听某个流上的变更,在新数据产生后尽快获取并消费新增数据。
顺序读取的读取端倾向于无状态设计,读取端仅读取状态,并不保存其他信息,例如已读标记,错误重试次数等等; 顺序读取的服务端可以有状态也可以无状态,取决于消息消费的语义。
发布订阅模式 和一些简单的消息队列 均可被看做是流的顺序访问模式.
经典的 Redis Pub-Sub 可以看做服务端无状态的一个例子;而QOS=2
的MQTT Retain Message 则是一个服务端有状态的例子。
随机读取
随机读取下,流数据的存储端必须要维护一部分状态,以实现表现的类似一个时序数据库一样, 支持读取端可以获取给定时间范围内的流数据信息; 读取端倾向于不保存状态。
分组消费
分组消费指多个消费者分组并按照一定的约束消费流中的数据, 是一种复杂但是实用的访问模式。
进行分组消费时,存在多个消费者组,每个消费者组中存在多个消费者。
多个消费者组都能够看到流中全部的信息,或者说,流中的每一条消息都会被广播给所有的消费者组。此处存在一个Fan Out语义,类似于发布订阅模式
而一个消费者组内的每个消费者都只能拿到流中的部分消息,消费者组会以基于某种负载均衡的策略,将流中的消息分发到每个消费者上,以实现并行处理。此处的语义类似消息队列
基于上述定义的分组消费模式,衍生出了几个关键的问题
- 消息的递送语义:给定一条消息,他可能被消费几次?(无保证,至少一次,至多一次,精确一次)
- 消费者的错误恢复:消费者故障时,如何处理其分配的消息?
- 多条消息的处理顺序:先到的消息是否一定会先被处理?
为了实现分组消费,存储端和消费端往往都需要维护状态信息,大大提高了系统的复杂性。
典型系统
Kafka
Redis Stream
参考阅读
[什么是流数据?- 流数据简介 - AWS](https://aws.amazon.com/cn/what-is/streaming-data/)