数据工程实战课程 · 流处理阶段
流处理是对无边界数据流进行实时处理的方法,与批处理的核心区别在于数据是持续到达的。
# 流处理引擎模拟
import time, random, json
from datetime import datetime
from collections import defaultdict
from dataclasses import dataclass, field
from threading import Thread
import queue
@dataclass
class StreamRecord:
key: str; value: dict; timestamp: str; offset: int
class StreamSource:
def __init__(self, name, rate=10):
self.name = name; self.rate = rate; self.offset = 0; self.running = False
def generate(self):
self.offset += 1
return StreamRecord(f"key_{random.randint(1,100)}",
{'event': random.choice(['click','purchase','view','search']),
'user_id': f"U{random.randint(1,1000)}", 'value': round(random.uniform(1,100),2)},
datetime.now().isoformat(), self.offset)
class StreamOperator:
def __init__(self, name, fn):
self.name = name; self.fn = fn; self.processed = 0
def process(self, record):
self.processed += 1
return self.fn(record)
class StreamSink:
def __init__(self, name): self.name = name; self.output = []
def write(self, record): self.output.append(record); return len(self.output)
class StreamingEngine:
def __init__(self, name):
self.name = name; self.operators = []; self.source = None; self.sink = None
self.metrics = defaultdict(int)
def set_source(self, source): self.source = source; return self
def add_operator(self, op): self.operators.append(op); return self
def set_sink(self, sink): self.sink = sink; return self
def run(self, num_records=100):
print(f"启动流: {self.name} ({num_records}条)")
start = time.perf_counter()
for _ in range(num_records):
record = self.source.generate()
for op in self.operators:
record = op.process(record)
if record is None: break
if record and self.sink:
self.sink.write(record)
elapsed = (time.perf_counter()-start)*1000
tps = num_records / (elapsed/1000) if elapsed > 0 else 0
print(f" 处理: {num_records}条, {elapsed:.1f}ms, {tps:.0f}条/秒")
for op in self.operators:
print(f" {op.name}: {op.processed}条")
if self.sink:
print(f" {self.sink.name}: {len(self.sink.output)}条输出")
return self.metrics
# 构建流处理管道
engine = StreamingEngine("用户行为流")
engine.set_source(StreamSource("events", 100))
engine.add_operator(StreamOperator("过滤", lambda r: r if r.value.get('event') != 'search' else None))
engine.add_operator(StreamOperator("增强", lambda r: StreamRecord(r.key, {**r.value, 'tier': 'VIP' if r.value['value'] > 50 else 'Normal'}, r.timestamp, r.offset)))
engine.set_sink(StreamSink("output"))
engine.run(500)
# 窗口聚合模拟
print("\n窗口聚合(5秒滚动窗口):")
window_size = 5
windows = defaultdict(list)
for i in range(50):
ts = i * 0.1 # 0.1秒间隔
window_id = int(ts / window_size)
event = random.choice(['click','purchase','view'])
windows[window_id].append({'ts':ts,'event':event,'value':round(random.uniform(1,50),2)})
for wid, events in sorted(windows.items()):
total = sum(e['value'] for e in events)
print(f" 窗口{wid}: {len(events)}事件, 总值{total:.1f}")
print("✅ 验证通过 - 流处理引擎运行正常")
🎁 下一课预告:Kafka入门!
| 维度 | Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 延迟 | 毫秒级 | 秒级(微批) | 毫秒级 |
| Exactly-Once | 原生支持 | 需配置 | 支持 |
| 状态管理 | 丰富 | 有限 | 本地Store |
| 窗口支持 | 全面 | 全面 | 基本 |
| 部署复杂度 | 高 | 中 | 低 |
在生产环境中,我们经常遇到教科书不会告诉你的问题。以下是常见的实战经验和解决方案:
| 指标 | 告警阈值 | 监控方式 |
|---|---|---|
| 管道延迟 | 超过SLA 120% | 端到端时间戳追踪 |
| 数据量偏差 | 日均偏差超过30% | 与历史同期对比 |
| 错误率 | 超过0.1% | 错误计数/总记录数 |
| 数据新鲜度 | 超过SLA 150% | 最新数据时间戳 |
| 资源利用率 | CPU持续>80% | 系统监控 |
A: 根据业务延迟要求决定:秒级用流处理、分钟级用微批、小时级用批处理。大部分场景批处理足够,流处理用于实时业务场景(风控、监控、推荐)。
A: 不会完全取代,但边界在模糊。湖仓一体(如Iceberg/Delta Lake)正在融合两者优势。未来趋势是统一存储+多引擎计算。
A: 先用云原生服务(BigQuery/Snowflake + Fivetran + dbt + Looker),验证业务后再考虑自建。过早优化是万恶之源。
A: 用钱说话:数据质量问题的直接经济损失(错误决策、合规罚款、重复劳动)远大于治理投入。量化问题是第一步。
| 角色 | 职责 | 交付物 |
|---|---|---|
| 数据工程师 | 管道开发与维护 | 数据管道、基础设施 |
| 数据分析师 | 数据分析与报表 | SQL查询、BI报表 |
| 数据科学家 | 模型与实验 | ML模型、实验报告 |
| 数据产品经理 | 需求与优先级 | PRD、数据产品规划 |
| 数据管家 | 数据质量与治理 | 质量规则、数据字典 |