实时数据技术栈入门:消息队列、流处理引擎与实时存储

实时数据产品化,说白了就是让数据从产生到被消费的时间窗口缩到最短。这个链条上有三个核心环节:消息队列负责传输,流处理引擎负责计算,实时存储负责落地。我这些年做过的实时项目,几乎都绕不开这三件套。

今天咱们就把这三个东西拆开看看。不追求大而全,只讲你上手必须知道的核心概念。

消息队列(Kafka)基础概念

消息队列是整个实时 pipeline 的「血管」。数据从各个源头打进来,先到消息队列里排队,下游的消费者再按需取走。Kafka 是当前最主流的选型,没有之一。

Kafka 的核心角色

  • Producer(生产者):把数据发到 Kafka 的客户端。比如埋点日志、数据库变更事件。
  • Broker(代理节点):Kafka 集群里的每一台服务器。数据就存在 Broker 上。
  • Consumer(消费者):从 Kafka 拉取数据的客户端。比如 Flink 任务、日志采集程序。
  • Topic(主题):数据的逻辑分类。好比数据库里的表,所有消息按 Topic 归类。
  • Partition(分区):Topic 的物理分片。一个 Topic 可以拆成多个 Partition,分布在不同的 Broker 上,实现并行读写。

一句话记住:Producer 往 Topic 写消息,Consumer 从 Topic 读消息,Broker 负责存,Partition 负责拆。

为什么 Kafka 这么快?

我刚开始接触 Kafka 时也有这个疑问。后来看了它的存储设计才明白——顺序写盘 + 零拷贝。

传统消息队列写一条消息要随机寻道,Kafka 直接往文件末尾追加,磁盘顺序写的速度比随机写快好几个数量级。消费时又通过零拷贝技术直接把数据从磁盘映射到网卡,绕过了用户态内存拷贝。

嗯,这里要注意:Kafka 不保证消息的全局有序,只保证同一个 Partition 内的消息有序。如果你需要全局有序,就只能用单 Partition,但那样就失去了并行能力。这是个 trade-off。

Consumer Group 与 Offset

Consumer Group 是 Kafka 实现「一条消息被多个业务复用」的关键机制。同一个 Group 内的消费者共同消费一个 Topic,每条消息只会被 Group 内的一个消费者处理。不同 Group 之间互不干扰。

每个消费者会记录自己消费到了哪个位置,这个位置叫 Offset(偏移量)。Kafka 把 Offset 保存在一个内部 Topic 里(__consumer_offsets),所以消费者重启后能接着上次的位置继续消费。

避坑指南:我曾经遇到过一个线上事故——消费者处理消息时抛了异常,但代码里先提交了 Offset 再处理业务逻辑。结果消息没处理完,Offset 已经往前跳了,重启后那些异常消息再也消费不到了。正确的做法是:先处理业务,再提交 Offset,或者开启 Kafka 的「自动提交」但把间隔设得足够长。

流处理引擎(Flink / Spark Streaming)简介

消息队列里的数据是「死」的,需要流处理引擎把它「活」起来。目前市面上最主流的两个引擎是 Flink 和 Spark Streaming。

Flink:真正的实时流处理

Flink 的设计哲学是「每条数据来了就处理」,延迟通常在毫秒级。它的核心概念包括:

  • DataStream:无限流数据的抽象。你写的所有算子(map、filter、keyBy)都是作用在 DataStream 上。
  • Checkpoint:Flink 的容错机制。它会定期把算子的状态快照保存到外部存储(比如 HDFS)。如果任务挂了,重启后能从最近的 Checkpoint 恢复,做到 Exactly-Once 语义。
  • Watermark:处理乱序事件的「时钟」。比如你统计过去 5 分钟的订单量,但有些订单因为网络延迟晚到了 2 分钟。Watermark 告诉 Flink:「等到某个时间点,不再等更晚的数据了,开始计算。」

个人经验:我做过一个实时大屏项目,要求展示「过去 5 分钟的用户点击量」。一开始没配 Watermark,结果晚到的数据导致指标反复跳动。后来加了 30 秒的 Watermark 延迟,大屏终于稳了。记住:Watermark 不是用来消除乱序的,而是用来定义「什么时候该出结果」。

Spark Streaming:微批处理的代表

Spark Streaming 的思路是把连续的数据流切成一个个小批次(Micro-Batch),每个批次作为一个 RDD 来处理。默认批次间隔是 1 秒,所以延迟在秒级。

它的核心概念:

  • DStream:Discretized Stream,本质上是连续的 RDD 序列。
  • Structured Streaming:Spark 2.x 之后推出的新 API,把流数据当作「不断追加的无限表」来处理,写起来跟批处理几乎一样。

Flink vs Spark Streaming:怎么选?

对比维度 Flink Spark Streaming
处理模式 真正的逐条流处理 微批处理(本质是批)
延迟 毫秒级 秒级(取决于批次间隔)
状态管理 原生支持,功能强大 依赖外部存储或 Checkpoint
乱序处理 Watermark + 窗口机制,成熟 基于时间戳的窗口,稍弱
生态兼容 与 Kafka、Hive 等集成良好 与 Hadoop 生态无缝对接
学习曲线 中等偏难 相对平缓(有批处理基础)

我的建议:如果你的业务要求毫秒级延迟(比如实时风控、交易监控),无脑选 Flink。如果延迟容忍度在 3-5 秒以内,且团队已经有 Spark 技术栈,Spark Streaming 完全够用。没必要为了「实时」而实时。

实时数据存储(Redis / ClickHouse)概览

数据算完了,得找个地方存起来供查询。实时场景下的存储选型跟离线完全不同——它要求写入快、查询也快,而且往往要处理高并发。

Redis:缓存与状态存储的首选

Redis 是内存数据库,读写都在内存里完成,单机 QPS 能到 10 万+。在实时链路里,Redis 最常见的两个角色是:

  • 缓存层:把热数据(比如用户画像、商品详情)缓存起来,避免每次查询都穿透到后端数据库。
  • 状态存储:Flink 任务的状态如果太大,可以配置用 Redis 作为状态后端。不过我个人更推荐 RocksDB,因为 Redis 的内存成本太高。

Redis 的数据结构很丰富:String、Hash、List、Set、Sorted Set、HyperLogLog……每个结构都有对应的使用场景。比如实时排行榜用 Sorted Set,UV 统计用 HyperLogLog。

注意:Redis 是单线程模型(6.0 之前),虽然处理单个请求很快,但如果有慢查询(比如 KEYS *),会阻塞所有后续请求。我在生产环境见过因为一个 KEYS 命令导致整个 Redis 集群雪崩的事故。线上永远不要用 KEYS,用 SCAN 代替。

ClickHouse:实时分析型数据库

ClickHouse 是列式存储数据库,专为 OLAP 场景设计。它的写入速度极快(每秒百万行级别),查询速度也快(秒级响应几十亿行数据的聚合查询)。

在实时数据产品里,ClickHouse 通常扮演「实时数仓」的角色:

  • Flink 把清洗后的数据实时写入 ClickHouse
  • BI 工具或大屏直接查询 ClickHouse 做聚合分析
  • 支持 SQL 语法,业务方上手成本低

ClickHouse 的几个关键特性:

  • MergeTree 引擎族:最核心的存储引擎,数据按主键排序,分区存储,支持 TTL 自动过期。
  • 向量化执行:利用 CPU 的 SIMD 指令集,一次处理一批数据,而不是一行一行处理。
  • 物化视图:预计算聚合结果,查询时直接读物化视图,速度更快。

避坑指南:ClickHouse 不适合高频的 point lookup(比如查某一条订单的详情),它更适合大范围的聚合查询。我曾经见过有人拿 ClickHouse 当 MySQL 用,每条查询都带 WHERE id = xxx,结果性能惨不忍睹。记住:ClickHouse 是分析引擎,不是事务数据库。

本章知识体系总览

下面这张图把三个核心组件的关系串起来了。你可以把它当作实时数据 pipeline 的「骨架」:

实时数据技术栈核心架构 数据源 埋点 / 日志 / CDC Kafka Topic / Partition Producer → Consumer Flink DataStream / Checkpoint Spark Streaming DStream / Micro-Batch Redis 缓存 / 状态存储 / 排行榜 Click House 数据流向说明 1. 数据源(埋点/日志/数据库CDC)写入 Kafka 的 Topic 2. Flink 或 Spark Streaming 从 Kafka 消费数据,进行实时计算 3. 计算结果写入 Redis(缓存/状态)或 ClickHouse(实时数仓) 4. 下游应用从 Redis/ClickHouse 读取数据,支撑大屏、报表、API

这张图里我刻意把 Flink 和 Spark Streaming 并列放在一起,因为在实际项目中,你很少会同时用两个引擎。选一个就行,关键是跟上下游打通。

好了,实时数据技术栈的三大件就聊到这儿。消息队列负责传输,流处理引擎负责计算,实时存储负责落地——这三者配合好了,你的实时 pipeline 就稳了八成。剩下的两成,靠的是监控、容错和持续调优。