Arch Day 91: 实时数据架构
实时数据架构是将数据从产生到消费的延迟从小时/天级压缩到秒/毫秒级的端到端系统设计,是"数据驱动决策"的最后一公里。
日期: 2026-06-29 (Day 91) 阶段: 第三阶段 - 零售域深度 标签: #实时数据 #流处理 #Kafka #Flink #Lambda架构 #Kappa架构
核心概念
一句话定义
实时数据架构是将数据从产生到消费的延迟从小时/天级压缩到秒/毫秒级的端到端系统设计,是"数据驱动决策"的最后一公里。
为什么关注
在零售/金融场景中,实时数据架构直接决定业务竞争力:
| 场景 | 批处理(T+1) | 实时处理 | 业务价值差距 |
|---|---|---|---|
| 库存同步 | 次日可见超卖 | 毫秒级扣减 | 超卖率降低90%+ |
| 风控拦截 | 事后审核 | 交易前实时决策 | 欺诈损失降低70%+ |
| 促销监控 | 活动结束才知道效果 | 实时GMV/转化率 | 可动态调整策略 |
| 推荐系统 | 昨天的行为推今天的商品 | 实时行为→实时推荐 | CTR提升15-30% |
| 供应链 | 隔天补货 | 实时库存→智能补货 | 缺货率降低40%+ |
误区与反模式
- "所有数据都要实时" — 实时处理成本是批处理的3-10倍,只有业务真正需要低延迟的场景才值得投入
- "实时=快速批处理" — 微批处理(Spark Streaming)与真正的事件驱动(Flink)在语义和能力上有本质差异
- "Kafka就是实时架构" — Kafka只是消息层,完整的实时架构还包括计算引擎、存储层和服务层
- "实时大屏=实时架构" — 大屏只是展示层,背后需要完整的数据采集→传输→计算→存储→服务链路
知识点详解
1. 流处理引擎深度对比:Flink vs Spark Streaming vs Kafka Streams
根据2025-2026年最新行业实践,三大流处理引擎各有定位:
架构哲学差异
| 维度 | Apache Flink | Spark Structured Streaming | Kafka Streams |
|---|---|---|---|
| 处理模型 | 原生流处理(逐事件) | 微批处理(mini-batch) | 逐事件处理 |
| 延迟 | 毫秒级(1-10ms) | 百毫秒级(100ms+),连续模式可达1ms | 毫秒级 |
| 状态管理 | RocksDB + 分布式快照(Chandy-Lamport) | 基于RDD的状态存储 | Changelog + RocksDB |
| 容错机制 | Checkpoint + Savepoint | WAL / Checkpoint | Changelog复制到Kafka |
| Exactly-Once | 原生支持(Two-Phase Commit) | 通过幂等写入和事务实现 | 通过Kafka事务实现 |
| 部署模型 | 独立集群 / YARN / K8s | Spark集群(共享资源) | 嵌入式(JVM库) |
| 背压处理 | 自动、无需配置 | 需要手动启用和调参 | 基于消费者Pull模型 |
| CDC支持 | 原生Debezium连接器 | 需外部工具发布到Kafka | 通过Kafka Connect |
| 窗口类型 | 滚动/滑动/会话/全局 | 滚动/滑动/会话 | 滚动/滑动/会话 |
| 水印机制 | 灵活自定义水印生成 | 基于事件时间的水印 | 基于记录时间戳(较简单) |
| 适用团队 | 专业流处理团队 | 已有Spark生态的团队 | 微服务/应用开发团队 |
选型决策树
需要实时流处理?
├── 是否已有Kafka生态?
│ ├── 是 → 处理逻辑是否简单(过滤/聚合/Join)?
│ │ ├── 简单 → Kafka Streams(无需额外集群)
│ │ └── 复杂(CEP/复杂窗口/多流Join) → Flink
│ └── 否 → 是否已有Spark集群?
│ ├── 是 → 延迟要求是否<100ms?
│ │ ├── 是 → Flink
│ │ └── 否 → Spark Structured Streaming
│ └── 否 → Flink(最佳默认选择)
性能基准(2025行业数据)
吞吐量(单节点):
Flink: ~150万 events/sec
Spark SS: ~120万 events/sec(微批模式)
Kafka Streams: ~80万 events/sec
端到端延迟(P99):
Flink: 5-20ms
Spark SS: 100-500ms(微批),1-5ms(连续模式,但功能受限)
Kafka Streams: 2-10ms
状态恢复时间:
Flink: 10-30秒(从最近Checkpoint恢复)
Spark SS: 30-60秒
Kafka Streams: 5-15秒(从Changelog恢复)
2. Kafka架构深度解析
Kafka是实时数据架构的核心消息骨干,理解其内部机制至关重要。
核心架构组件
┌─────────────────────────────────────────────────────┐
│ Kafka Cluster (KRaft模式) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Broker 1 │ │ Broker 2 │ │ Broker 3 │ │
│ │(Controller)│ │ │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ ┌────┴────────────┴────────────┴────┐ │
│ │ Topic: order-events │ │
│ │ ┌───────┐ ┌───────┐ ┌───────┐ │ │
│ │ │Part-0 │ │Part-1 │ │Part-2 │ │ │
│ │ │(Leader)│ │(Leader)│ │(Leader)│ │ │
│ │ └───────┘ └───────┘ └───────┘ │ │
│ │ ┌───────┐ ┌───────┐ ┌───────┐ │ │
│ │ │Rep-0 │ │Rep-1 │ │Rep-2 │ │ (ISR副本) │
│ │ └───────┘ └───────┘ └───────┘ │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Partition机制深度
分区策略选择:
| 策略 | 适用场景 | 顺序保证 | 负载均衡 |
|---|---|---|---|
| Key Hash分区 | 需要相同Key顺序(如同一用户事件) | 同Key有序 | 依赖Key分布 |
| Round Robin | 不需要顺序保证,追求吞吐 | 无 | 均匀 |
| Custom分区 | 特殊业务逻辑(如按地区路由) | 自定义 | 自定义 |
| Sticky分区 | 无Key场景优化批量发送 | 无 | 较均匀 |
分区数量规划公式:
目标吞吐量 = T (msg/sec)
单分区写入吞吐 = Pw (msg/sec) // 通常 50K-100K msg/sec
单分区消费吞吐 = Pc (msg/sec) // 通常 100K-200K msg/sec
最小分区数 = max(T/Pw, T/Pc)
示例:
目标100万msg/sec,单分区写入80K
分区数 = 1000000/80000 = 13 → 建议16(留buffer + 2的幂次)
Consumer Group机制
Consumer Group: order-processing-group
┌──────────────────────────────────────────┐
│ Consumer 1 Consumer 2 Consumer 3│
│ ├─ Part-0 ├─ Part-2 ├─ Part-4│
│ └─ Part-1 └─ Part-3 └─ Part-5│
│ │
│ Rebalance触发条件: │
│ 1. 新Consumer加入 │
│ 2. Consumer离开(崩溃/主动退出) │
│ 3. Topic分区数变化 │
│ 4. 订阅的Topic变化 │
│ │
│ KIP-848协议(Kafka 4.0+): │
│ - 增量式再平衡,避免Stop-the-World │
│ - 服务端协调,减少客户端复杂度 │
└──────────────────────────────────────────┘
Exactly-Once语义实现
// Kafka事务性生产者配置
Properties props = new Properties();
props.put("bootstrap.servers", "kafka1:9092,kafka2:9092");
props.put("transactional.id", "order-processor-1"); // 唯一事务ID
props.put("enable.idempotence", true); // 幂等性
props.put("acks", "all"); // 所有ISR确认
props.put("max.in.flight.requests.per.connection", 5);
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
producer.initTransactions();
try {
producer.beginTransaction();
// 原子性:消费偏移量提交 + 生产输出消息
producer.send(new ProducerRecord<>("output-topic", key, value));
producer.sendOffsetsToTransaction(offsets, consumerGroupId);
producer.commitTransaction();
} catch (Exception e) {
producer.abortTransaction();
}
Exactly-Once三层保障:
| 层级 | 机制 | 保障内容 |
|---|---|---|
| Producer幂等 | ProducerID + SequenceNumber | 单分区去重 |
| 事务 | TransactionalID + Two-Phase Commit | 跨分区原子写入 |
| Consumer隔离 | isolation.level=read_committed | 只读已提交数据 |
3. 实时计算核心模式
Event Time vs Processing Time
现实世界时间线:
Event产生 → 网络传输 → 到达系统 → 被处理
↓ 延迟 ↓
Event Time Processing Time
示例:
用户10:00:00下单 → 10:00:03到达Kafka → 10:00:05被Flink处理
Event Time = 10:00:00
Processing Time = 10:00:05
为什么Event Time重要?
- 移动端网络不稳定,事件可能延迟数秒甚至数分钟到达
- 不同数据中心的系统时钟可能不同步
- 业务语义上,"用户什么时候做的"比"系统什么时候处理的"更有价值
Watermark(水印)机制
事件流(按到达顺序,括号内为Event Time):
... [10:01] [10:03] [10:02] [10:05] [10:04] [10:06] ...
↑
当前Watermark = 10:04
含义:系统认为不会再有Event Time < 10:04的事件到达
Watermark生成策略:
1. 固定延迟:W = max(event_time) - 允许延迟
- 简单实用,适合大多数场景
- 例:允许延迟5秒 → W = max_event_time - 5s
2. 自定义水印:根据业务逻辑
- 如:不同来源的数据延迟不同,按来源设置不同延迟
迟到数据处理:
- 丢弃(默认):忽略晚于Watermark的数据
- Side Output:将迟到数据输出到侧流,后续补偿处理
- Allowed Lateness:窗口延迟关闭,更新已有结果
Window(窗口)类型详解
时间轴: |----1----|----2----|----3----|----4----|
1. 滚动窗口(Tumbling):固定大小,不重叠
|████████|████████|████████|████████|
用途:每分钟UV、每小时GMV
2. 滑动窗口(Sliding):固定大小,有重叠
|████████████|
|████████████|
|████████████|
用途:过去5分钟的平均响应时间(每分钟更新)
3. 会话窗口(Session):按活动间隔动态划分
|███| |█████████| |██|
gap gap
用途:用户浏览会话分析
4. 全局窗口(Global):所有数据在同一窗口,需自定义Trigger
|████████████████████████████████████|
用途:累计计数器,配合自定义触发条件
4. 实时指标计算实战
实时GMV计算
-- Flink SQL: 实时GMV(分钟级滚动窗口)
CREATE TABLE order_events (
order_id STRING,
user_id STRING,
amount DECIMAL(10,2),
category STRING,
store_id STRING,
event_time TIMESTAMP(3),
WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
'connector' = 'kafka',
'topic' = 'order-events',
'properties.bootstrap.servers' = 'kafka:9092',
'format' = 'json'
);
-- 实时分钟级GMV
SELECT
TUMBLE_START(event_time, INTERVAL '1' MINUTE) AS window_start,
category,
store_id,
COUNT(*) AS order_count,
SUM(amount) AS gmv,
COUNT(DISTINCT user_id) AS buyer_count
FROM order_events
GROUP BY
TUMBLE(event_time, INTERVAL '1' MINUTE),
category,
store_id;
实时库存计算
-- 实时库存变动追踪
CREATE TABLE inventory_events (
sku_id STRING,
warehouse_id STRING,
change_type STRING, -- 'inbound', 'outbound', 'reserved', 'released'
quantity INT,
event_time TIMESTAMP(3),
WATERMARK FOR event_time AS event_time - INTERVAL '2' SECOND
) WITH (...);
-- 实时库存快照(使用Flink的Deduplication + Aggregation)
SELECT
sku_id,
warehouse_id,
SUM(CASE
WHEN change_type IN ('inbound', 'released') THEN quantity
WHEN change_type IN ('outbound', 'reserved') THEN -quantity
ELSE 0
END) AS available_stock,
MAX(event_time) AS last_updated
FROM inventory_events
GROUP BY sku_id, warehouse_id;
实时风控特征计算
-- 实时用户行为特征(滑动窗口)
SELECT
user_id,
-- 过去5分钟特征
COUNT(*) OVER w5m AS order_count_5min,
SUM(amount) OVER w5m AS total_amount_5min,
COUNT(DISTINCT device_id) OVER w5m AS device_count_5min,
COUNT(DISTINCT ip) OVER w5m AS ip_count_5min,
-- 过去1小时特征
COUNT(*) OVER w1h AS order_count_1h,
SUM(amount) OVER w1h AS total_amount_1h
FROM order_events
WINDOW
w5m AS (PARTITION BY user_id ORDER BY event_time
RANGE BETWEEN INTERVAL '5' MINUTE PRECEDING AND CURRENT ROW),
w1h AS (PARTITION BY user_id ORDER BY event_time
RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND CURRENT ROW);
5. 实时大屏架构全链路
┌─────────────────────────────────────────────────────────────┐
│ 实时大屏完整架构 │
│ │
│ 数据采集层 消息层 计算层 存储/服务层 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ │
│ │ App埋点 │───→│ │──→│ │──→│ Redis │ │
│ │ (SDK) │ │ │ │ │ │ (实时指标) │ │
│ └─────────┘ │ │ │ │ └────┬─────┘ │
│ │ Kafka │ │ Flink │ │ │
│ ┌─────────┐ │ Cluster│ │ Cluster │ ┌────┴─────┐ │
│ │ 订单系统 │───→│ │──→│ │──→│ClickHouse│ │
│ │ (Binlog) │ │ │ │ Job 1: │ │(明细查询) │ │
│ └─────────┘ │ │ │ GMV计算 │ └────┬─────┘ │
│ │ │ │ │ │ │
│ ┌─────────┐ │ │ │ Job 2: │ ┌────┴─────┐ │
│ │ 库存系统 │───→│ │──→│ 库存监控 │──→│WebSocket │ │
│ │ (CDC) │ │ │ │ │ │ Server │ │
│ └─────────┘ │ │ │ Job 3: │ └────┬─────┘ │
│ │ │ │ 风控特征 │ │ │
│ ┌─────────┐ │ │ │ │ ┌────┴─────┐ │
│ │ 日志系统 │───→│ │──→│ Job 4: │──→│ 前端大屏 │ │
│ │(Filebeat)│ │ │ │ 流量分析 │ │(ECharts) │ │
│ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │
│ │
│ 技术选型: │
│ 采集:Debezium CDC / Filebeat / SDK │
│ 消息:Kafka 3.8+(KRaft模式,无ZooKeeper依赖) │
│ 计算:Flink 1.20+ │
│ 存储:Redis 7.x(热数据)+ ClickHouse 24.x(分析查询) │
│ 推送:WebSocket / Server-Sent Events │
│ 展示:ECharts / Grafana / 自研大屏 │
└─────────────────────────────────────────────────────────────┘
6. Lambda vs Kappa vs Delta架构
架构演进趋势(2025-2026最新)
| 维度 | Lambda | Kappa | Delta(Lakehouse) |
|---|---|---|---|
| 提出时间 | 2011(Nathan Marz) | 2014(Jay Kreps) | 2020(Databricks) |
| 核心思想 | 批+流双通道 | 统一流处理 | 统一存储+批流一体 |
| 数据通道 | 批处理层+速度层+服务层 | 单一流处理通道 | Lakehouse + Streaming |
| 代码维护 | 两套代码(批+流) | 一套代码 | 一套代码 |
| 历史重处理 | 批处理层重跑 | 从Kafka日志重放 | 从Delta Lake重读 |
| 一致性 | 最终一致(两层合并) | 强一致 | ACID事务保证 |
| 复杂度 | 高(双系统维护) | 中(单系统但需大Kafka) | 中(需Lakehouse平台) |
| 存储成本 | 高(数据存两份) | 中(Kafka保留策略限制) | 低(对象存储) |
| 2026主流度 | 遗留系统仍在用 | 新系统默认选择 | 大规模数据平台首选 |
2025-2026行业趋势:
- Kappa架构已成为新建实时系统的默认选择,Uber、Shopify等公司已完成从Lambda到Kappa的迁移
- Delta架构(基于Lakehouse)正成为企业级数据平台的主流,Databricks/Apache Iceberg生态快速成熟
- Flink + Kafka + Iceberg/Delta Lake的组合正在成为"现代数据栈"的标准配置
对比分析
实时存储选型对比
| 存储 | 延迟 | 吞吐 | 查询能力 | 适用场景 |
|---|---|---|---|---|
| Redis | <1ms | 10万+ QPS/节点 | KV/简单聚合 | 实时计数器、排行榜、缓存 |
| ClickHouse | 10-100ms | 亿级扫描/秒 | 复杂OLAP | 实时报表、多维分析 |
| Apache Doris | 10-100ms | 亿级扫描/秒 | 复杂OLAP + 实时写入 | 实时Dashboard + Ad-hoc查询 |
| Elasticsearch | 10-50ms | 百万级写入/秒 | 全文搜索+聚合 | 日志分析、搜索场景 |
| TiDB | 5-20ms | 十万级QPS | 完整SQL(HTAP) | 需要事务+分析的混合场景 |
| HBase | 1-5ms | 百万级随机读写/秒 | 行键查询 | 特征存储、时序数据 |
架构设计实操:双11实时大屏
设计目标
为某电商平台设计双11实时大屏系统,核心指标:
- 实时GMV(全平台/分品类/分店铺)
- 实时订单数和支付转化率
- 实时UV/PV
- 实时库存预警
- 实时物流追踪
性能要求
| 指标 | 要求 |
|---|---|
| 数据延迟 | 核心指标<3秒,非核心<10秒 |
| 峰值写入 | 100万订单/秒(双11零点) |
| 大屏刷新 | 每秒更新 |
| 可用性 | 99.99% |
| 准确性 | 最终一致,误差<0.1% |
架构方案
┌────────────────────────────────────────────────────────┐
│ 双11实时大屏架构 │
│ │
│ Layer 1: 数据采集(多源异构) │
│ ┌────────────┬────────────┬────────────┬──────────────┐ │
│ │ 订单Binlog │ 支付回调 │ 用户行为SDK │ 库存变动CDC │ │
│ │ (Debezium) │ (HTTP→MQ) │ (Kafka SDK)│ (Debezium) │ │
│ └─────┬──────┴─────┬──────┴─────┬──────┴──────┬───────┘ │
│ └────────────┴────────────┴─────────────┘ │
│ ↓ │
│ Layer 2: 消息队列(Kafka集群) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Kafka集群(100+ Broker,KRaft模式) │ │
│ │ Topics: │ │
│ │ order-events (256 partitions, RF=3) │ │
│ │ payment-events (128 partitions, RF=3) │ │
│ │ user-behavior (512 partitions, RF=3) │ │
│ │ inventory-events (64 partitions, RF=3) │ │
│ │ 峰值吞吐: 200万msg/sec │ │
│ │ 数据保留: 7天 │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ Layer 3: 流处理(Flink集群) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Flink集群(500+ TaskManager) │ │
│ │ │ │
│ │ Job Group 1: GMV实时聚合 │ │
│ │ 1分钟滚动窗口 → 多维度GMV │ │
│ │ (全平台/品类/店铺/省份) │ │
│ │ │ │
│ │ Job Group 2: 转化率计算 │ │
│ │ 浏览→加购→下单→支付 漏斗实时计算 │ │
│ │ │ │
│ │ Job Group 3: 库存预警 │ │
│ │ 实时库存 < 安全库存 → 告警 │ │
│ │ │ │
│ │ Job Group 4: 风控特征 │ │
│ │ 5分钟滑动窗口用户行为特征 │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ Layer 4: 存储+服务 │
│ ┌──────────┬──────────────┬──────────────┐ │
│ │ Redis │ ClickHouse │ HBase │ │
│ │ Cluster │ Cluster │ Cluster │ │
│ │ │ │ │ │
│ │ 实时计数 │ 明细数据 │ 用户特征 │ │
│ │ GMV累计 │ 多维分析 │ 风控决策 │ │
│ │ 排行榜 │ 下钻查询 │ 状态查询 │ │
│ └────┬─────┴──────┬───────┴──────┬───────┘ │
│ └────────────┴──────────────┘ │
│ ↓ │
│ Layer 5: 服务+展示 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ API Gateway → WebSocket Server → 大屏前端(ECharts)│ │
│ │ 数据刷新频率: 1秒 │ │
│ │ 推送策略: 增量推送(只推变化数据) │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
ADR: 选择Kappa而非Lambda架构
状态: 已采纳
背景: 双11大屏需要同时支持实时指标和历史对比分析
决策: 采用Kappa架构(Kafka + Flink统一处理),使用ClickHouse作为分析存储
理由:
- 单一代码库,降低维护成本(双11前紧急修bug只改一处)
- Flink同时处理实时和回填任务(Savepoint → 重放Kafka)
- ClickHouse既支持实时写入又支持复杂OLAP查询
- 团队只需精通一套技术栈
权衡:
- 需要Kafka保留足够历史数据(7天),存储成本较高
- 超大历史分析(月/年级)仍需离线数仓补充
- Flink集群规模需要为峰值设计(或使用K8s弹性伸缩)
AI增强实践
1. AI驱动的实时异常检测
# 基于Flink + AI模型的实时异常检测
class AnomalyDetectionFunction(KeyedProcessFunction):
def __init__(self):
self.model = None
self.feature_buffer = []
def open(self, runtime_context):
# 加载预训练的异常检测模型(定期从MLflow同步)
self.model = load_model("s3://models/anomaly-detector/latest")
def process_element(self, value, ctx):
# 实时特征提取
features = extract_features(value)
# 模型推理(<5ms延迟)
anomaly_score = self.model.predict(features)
if anomaly_score > THRESHOLD:
# 输出异常告警到侧流
yield TaggedOutput("anomalies", AnomalyEvent(
event=value,
score=anomaly_score,
detected_at=ctx.timestamp()
))
2. AI辅助的Flink作业自动调优
# AI Agent自动优化Flink配置
ai_tuning:
metrics_source: prometheus
optimization_targets:
- metric: "checkpoint_duration_p99"
target: "<10s"
- metric: "backpressure_ratio"
target: "<0.1"
- metric: "throughput"
target: ">1M events/sec"
tunable_parameters:
- "taskmanager.memory.managed.fraction" # 0.1-0.9
- "state.backend.rocksdb.block.cache-size" # 64MB-4GB
- "execution.checkpointing.interval" # 10s-300s
- "taskmanager.numberOfTaskSlots" # 1-16
strategy: "bayesian_optimization"
evaluation_window: "30min"
3. LLM驱动的实时数据质量监控
- 自然语言描述异常:"过去5分钟GMV同比下降40%,主要集中在华东区域,可能是支付系统故障"
- 自动根因分析:关联多个指标流,用LLM推理异常原因
- 智能告警分级:基于历史模式判断告警严重程度
与Web3/DeFi的关联
DeFi中的实时数据需求
| 传统零售实时场景 | DeFi对应场景 | 技术差异 |
|---|---|---|
| 实时GMV大屏 | 实时TVL/交易量Dashboard | 数据源从数据库→链上事件 |
| 实时库存预警 | 实时流动性监控 | 链上状态查询 vs CDC |
| 实时风控 | 实时MEV检测/清算预警 | 需要Mempool监控 |
| 用户行为分析 | 链上地址行为分析 | 公开数据但地址匿名 |
Web3实时数据架构
链上数据 → Indexer(The Graph/Goldsky) → Kafka → Flink → Dashboard
↓
事件解析(ABI decode)
↓
标准化事件流
关键差异
- 数据源:Web3数据全公开但需要解析(ABI decode),传统零售数据在内部系统
- 时效性:以太坊出块12秒,Solana 400ms,不同链的实时性不同
- 重组风险:链上数据可能因区块重组(reorg)而回滚,需要确认块数
- Mempool:DeFi交易在上链前可在Mempool中被发现,这是MEV的基础
今日思考
问题1:为什么很多公司的"实时"其实是"准实时"?
真正的毫秒级实时处理对基础设施要求极高——需要独立的Flink集群、足够的Kafka分区、低延迟网络、实时存储(Redis/ClickHouse)。大多数业务场景用秒级或分钟级延迟就够了(如GMV大屏、报表刷新),过度追求低延迟反而增加系统复杂度和成本。真正需要毫秒级的场景:风控拦截、高频交易、实时竞价。
问题2:当Flink作业挂了,如何保证数据不丢不重?
核心机制是Checkpoint + Exactly-Once:Flink定期做分布式快照(Chandy-Lamport算法),记录算子状态和Kafka偏移量。恢复时从最近的Checkpoint恢复状态,Kafka Consumer从记录的偏移量重新消费。配合事务性Sink(如Kafka事务、两阶段提交),可以实现端到端的Exactly-Once语义。
问题3:实时计算和批处理如何共存?
现代趋势是"批流一体"——同一套代码逻辑,流处理跑实时,批处理跑历史补偿。Flink SQL天然支持这种模式:同一张SQL既可以查流表(实时),也可以查批表(历史)。ClickHouse/Apache Doris这类OLAP引擎也同时支持实时写入和批量导入,作为统一的服务层。
面试题准备
面试题1:Flink和Spark Streaming如何选?
30秒版本: Flink是原生流处理引擎,延迟更低(毫秒级)、状态管理更强、支持精确的Event Time处理;Spark Streaming是微批处理,延迟较高(百毫秒级)但与Spark生态集成好。如果团队已有Spark技能且延迟要求不苛刻,选Spark;否则Flink是2025年新系统的默认选择。
2分钟版本:
- 处理模型:Flink逐事件处理,Spark按微批处理。这不仅影响延迟,还影响窗口语义的精确性
- 状态管理:Flink的RocksDB状态后端支持TB级状态,配合增量Checkpoint,恢复时间短。Spark状态管理相对薄弱
- CDC支持:Flink原生集成Debezium,Spark需要额外组件
- 生态:Spark在机器学习(MLlib)、图计算(GraphX)方面更成熟
- 运维:Spark集群通常已存在(共享ETL/ML),Flink需要独立部署和运维
- 我的经验:在零售场景中,实时库存同步、风控特征计算用Flink(需要毫秒级延迟和精确Event Time),离线报表用Spark。两者互补而非替代
追问准备:
- Q: Flink的Checkpoint对性能有什么影响? → Checkpoint期间会有短暂的吞吐下降(全量Checkpoint较明显),增量Checkpoint影响更小。建议Checkpoint间隔10s-60s,配合RocksDB增量模式
- Q: 什么场景下Kafka Streams比Flink更合适? → 当处理逻辑简单(过滤、转换、简单聚合)且数据完全在Kafka中时,Kafka Streams无需额外集群,部署在应用JVM中即可
面试题2:实时计算如何处理乱序数据?
30秒版本: 通过Event Time + Watermark机制。每条数据携带事件时间,系统根据Watermark判断"哪些数据已经全部到齐",在此基础上触发窗口计算。迟到的数据可以通过Allowed Lateness或Side Output处理。
2分钟版本:
- Event Time:使用数据产生时间而非处理时间作为计算基准
- Watermark:系统对"数据到齐程度"的估计,通常是max_event_time - allowed_delay
- 窗口触发:当Watermark超过窗口结束时间,触发计算
- 迟到处理三策略:丢弃(简单)、Side Output(补偿处理)、Allowed Lateness(更新结果)
- 实战经验:在零售订单场景中,移动端SDK的事件延迟通常在1-5秒,设置5秒Watermark延迟即可覆盖99%的场景。对于跨境场景(网络延迟大),可能需要30秒甚至更长
- 权衡:Watermark延迟越大,处理越准确但实时性越差。需要根据业务容忍度在准确性和实时性之间取舍
学习资源
- Apache Flink官方文档 — 最权威的Flink学习资源
- Confluent Kafka文档 — Kafka深度学习
- ClickHouse实时分析资源 — 2026年实时分析数据库选型指南
- Kappa vs Lambda架构对比 (2026) — 最新架构趋势分析
- Flink vs Spark vs Kafka Streams对比 — 流处理引擎全面对比
明日预告
Day 92: 数据治理 — 从"管数据"到"治数据"。将深入DAMA-DMBOK2/3.0框架、数据质量管理、元数据管理、数据血缘追踪、数据目录(DataHub/Atlas)、主数据管理等核心主题,并设计完整的数据治理平台架构。数据治理是大规模实时数据系统可持续运营的基石。