低延迟流处理系统设计:别再迷信“又快又准”,工程从来都是妥协的艺术
低延迟流处理系统设计:别再迷信“又快又准”,工程从来都是妥协的艺术
大家好,我是 Echo_Wish。
做流处理这些年,我发现一个特别有意思、也特别“坑新人”的现象:
一提实时系统,大家张嘴就是——低延迟、高吞吐、强一致、零丢失。
听着是不是很爽?
但真干过的人都知道一句话:
这玩意儿,最多只能同时满足两到三个。
今天咱就不讲那些“教科书正确”,就聊一个工程里绕不开的话题:
低延迟流处理系统,本质就是在吞吐和准确性之间反复横跳。
一、先把话说明白:你追的“低延迟”,到底是啥?
很多人一说低延迟,其实自己都没想清楚。
我一般会先反问一句:
你说的延迟,是 端到端延迟,还是 计算延迟?
常见三种“延迟”,别混了
-
事件时间延迟
- 数据真实发生 → 系统处理完成
-
处理时间延迟
- 数据进入系统 → 算完
-
可见性延迟
- 算完 → 下游/用户能看到
很多系统“看起来很快”,其实只是 处理时间快,
但 事件时间慢得一塌糊涂。
👉 这是后面“准确性翻车”的根源。
二、吞吐 vs 准确性:你不选,它也会替你选
我们先说个大实话:
高吞吐,天然就对准确性不友好。
为什么?
1️⃣ 为了吞吐,你一定会做这些事
- 批量处理(micro-batch)
- 异步 IO
- 缓冲 + 合并
- 延迟 checkpoint
- 放宽一致性
这些操作 每一项都在赌一件事:
“数据不会乱序 / 不会丢 / 不会晚到太多”
赌赢了,系统飞起
赌输了,数据对不上,老板找你
三、一个最真实的例子:窗口统计里的“慢数据”
假设我们做一个实时 PV 统计,5 秒一个窗口。
天真的写法(吞吐优先)
from collections import defaultdict
import time
window_size = 5
counts = defaultdict(int)
window_start = int(time.time())
def process(event):
global window_start
now = int(time.time())
if now - window_start >= window_size:
print("window result:", dict(counts))
counts.clear()
window_start = now
counts[event["page"]] += 1
这个代码:
- ✅ 快
- ✅ 简单
- ❌ 准确性靠运气
问题在哪?
- 网络抖一下,数据晚到
- 上游 GC 一下,事件乱序
- 某个节点慢了 1 秒
结果就是:
窗口已经算完了,数据才姗姗来迟
四、为了“准一点”,系统开始变复杂
于是你开始补救。
1️⃣ 引入事件时间 + watermark
def should_close_window(event_time, watermark):
return event_time <= watermark
你开始等:
- 等慢数据
- 等乱序
- 等系统“确定不会再来了”
👉 延迟就上来了
2️⃣ 加 allowed lateness
allowed_lateness = 3 # seconds
- 多等 3 秒
- 准确性 ↑
- 延迟 ↑
- 状态存储 ↑
- 内存压力 ↑
这时候你已经站在十字路口了:
再准一点,还是再快一点?
五、工程真相:你必须“人为制造不准确”
这话可能刺耳,但我说得很负责任:
所有大规模低延迟系统,都是“可控的不准确”。
常见工程妥协手段
1️⃣ 近似计算(Approximation)
- HyperLogLog
- Bloom Filter
- Count-Min Sketch
# 伪代码:近似去重
uv_estimate = hll.add(user_id)
结果是:
- 误差 0.5% ~ 1%
- 延迟和内存直接降一个量级
2️⃣ 分级准确性
- 实时结果:给看板用
- 离线回算:给财务用
我见过太多公司:
实时报表 ≠ 对账结果
但 KPI 只盯实时的
3️⃣ 牺牲少量数据完整性
- 超时就丢
- 超出 watermark 就忽略
- 单点异常直接跳过
工程上有句话很现实:
宁可算得不全,也不能一直不出结果
六、为什么我越来越不迷信“Exactly Once”
老实说,我现在看到“Exactly Once”,心里是警惕的。
不是它不好,而是:
- 状态重
- 协调复杂
- 性能成本高
- Debug 成本爆炸
很多业务其实只需要:
- At Least Once + 幂等
- 最终一致
def process(event):
if processed(event.id):
return
handle(event)
mark_done(event.id)
这套方案:
- 系统简单
- 延迟低
- 出问题也好修
👉 比追求“绝对正确”更工程友好。
七、我自己的一个判断标准(送你)
如果你正在设计一个低延迟流系统,我建议你先问自己这 3 个问题:
- 这个数据,错 1% 会死人吗?
- 这个结果,是给人看,还是给系统算钱?
- 延迟 1 秒,和错 1 条数据,哪个更不能接受?
只要你老老实实回答完,
架构方案基本就出来了。
八、最后说点掏心窝子的
做流处理这么多年,我最大的感受是:
系统设计不是炫技,而是为业务兜底。
真正成熟的系统,不是参数全开、语义拉满,
而是:
- 能跑
- 跑得稳
- 出问题兜得住
低延迟流处理,从来不是“我全都要”,
而是:
我知道自己放弃了什么,也知道为什么放弃。
- 点赞
- 收藏
- 关注作者
评论(0)