第十一章:流处理
1. 流处理的核心范式
流处理(Stream Processing)面向无界事件序列,强调“持续计算 + 低延迟反馈”。它不是批处理的对立面,而是把“全量重算”改为“增量更新”。
2. 事件流传输模型
2.1 直接消息传输
生产者直接调用消费者(TCP/HTTP/RPC)实现简单,但耦合高、容错弱,消费者不可用时易丢消息。
2.2 消息代理
引入 Broker 解耦生产与消费,实现缓冲、重试和多订阅。
2.2.1 传统队列模型
RabbitMQ/ActiveMQ 常见“消费即删除”,适合任务分发,但历史回放能力弱。
2.2.2 日志模型
Kafka/Pulsar/Kinesis 采用分区追加日志,消费者以 offset 自主推进,支持回放与多消费组并行。
2.3 分区日志关键语义
- 单分区内有序。
- 跨分区无全局顺序。
- 保留策略按时间或大小控制。
3. 数据库与流的统一视角
3.1 双写问题
应用同时写数据库与搜索/缓存会产生竞态与不一致。更稳妥模式是“单一事实来源 + 变更流派生”。
3.2 变更数据捕获(CDC)
从数据库 WAL/Binlog 提取变更事件,驱动下游索引、数仓和缓存同步,降低跨系统耦合。
3.3 事件溯源(Event Sourcing)
把状态变化建模为不可变事件序列,当前状态由事件回放得到。它比“直接改状态”更有审计性与可追溯性。
3.4 日志压缩
按键保留最新值可控制日志体积,并支持快速重建当前快照状态。
4. 流处理模式
4.1 CEP 与流分析
CEP:检测复杂事件模式。- 流分析:实时聚合指标,如
UV、分位数、异常检测。
4.2 物化视图维护
流作业可持续维护查询友好的下游视图,本质是“增量更新数据库”。
4.3 流上的搜索与告警
通过规则引擎和索引维护,可实现近实时检索与异常告警。
5. 时间语义
5.1 事件时间与处理时间
- 事件时间:事件真实发生时刻。
- 处理时间:系统实际处理时刻。
两者受网络与排队影响可能严重偏离,统计口径应优先基于事件时间。
5.2 窗口机制
常见窗口包括滚动窗口、滑动窗口、跳跃窗口和会话窗口,选择取决于业务语义与延迟目标。
5.3 迟到数据与水位线
水位线用于表达“某时刻之前的数据大概率已到齐”。迟到事件可选择丢弃、修正或补偿,需在准确性与时效性间权衡。
6. 流 Join
6.1 流-流 Join
必须限定时间窗口并维护状态,避免无限缓存导致状态爆炸。
6.2 流-表 Join
常用于事件富化。为了低延迟,维表通常通过 CDC 同步到本地状态而非远程实时查询。
6.3 表-表 Join
通过持续消费两侧变更流维护物化连接结果,适合实时画像与时间线场景。
7. 容错与 Exactly-once
7.1 微批与检查点
- 微批:把流切成小批次复用批处理容错。
- 检查点:定期持久化算子状态,故障后从最近快照恢复。
7.2 Exactly-once 的边界
工程上的 Exactly-once 更准确地说是 Effectively-once,通常依赖:
- 可重放输入。
- 状态更新与位点提交原子化。
- 下游写入幂等或事务化。
7.3 端到端一致性
只要链路中某一环节不支持幂等或事务,端到端 Exactly-once 就会退化为“至少一次 + 去重补偿”。
8. 实务建议
- 先定义时间语义,再设计窗口与迟到策略。
- 把状态大小、重放成本、恢复时间纳入容量规划。
- 用批处理定期回放校准流处理结果,构建闭环数据质量体系。