数据一多就卡?别急,先把“数据入口”修好
——聊聊如何构建高吞吐、低延迟的数据接入层(Kafka / Pulsar)
咱先说一句大实话:
很多系统慢,不是算不动,而是数据进得太慢、太乱。
我见过太多项目,一上来就聊 Flink 多强、Spark 多牛、ClickHouse 多快,
结果一上线:
- Kafka backlog 堆成山
- 延迟从毫秒飙到分钟
- 业务方一句话:“你们大数据怎么这么慢?”
其实问题往往不在计算层,而在数据接入层。
今天这篇文章,我不讲虚的,不堆概念,就聊一个非常现实的问题:
如何把 Kafka / Pulsar 这一层,真正打造成“高吞吐、低延迟、不拖后腿”的数据入口?
一、数据接入层,才是真正的“系统咽喉”
你可以把整个大数据系统想象成一条流水线:
业务系统 → 数据接入层 → 实时/离线计算 → 存储 → 应用
接入层就像高速公路的收费站。
- 你后面修了 8 车道
- 前面收费站只开 1 个窗口
那结局只有一个:堵死。
Kafka / Pulsar,本质上就是这个收费站。
它干的不是“存数据”,而是三件事:
- 削峰填谷(扛流量)
- 解耦上下游(谁慢都别拖死谁)
- 保证数据可靠、有序、可回放
所以,接入层的目标只有一句话:
在不牺牲稳定性的前提下,把数据尽可能快、尽可能稳地送进系统。
二、高吞吐≠堆机器,先把“写入姿势”摆正
很多人一说 Kafka 吞吐低,第一反应是:
“Broker 不够?那我加机器。”
结果钱花了,效果不明显。
1️⃣ Producer 端,才是吞吐的第一杀手
默认 Kafka Producer 配置,真的很保守。
一个最典型的反例代码:
Properties props = new Properties();
props.put("bootstrap.servers", "kafka:9092");
props.put("key.serializer", StringSerializer.class);
props.put("value.serializer", StringSerializer.class);
KafkaProducer<String, String> producer =
new KafkaProducer<>(props);
这段代码能跑,但吞吐通常感人。
想要高吞吐,三个参数一定要动:
props.put("linger.ms", 10); // 等一等,多攒点再发
props.put("batch.size", 65536); // 一批 64KB
props.put("compression.type", "lz4"); // 压缩换吞吐
我的经验是:
- 延迟容忍在 10~20ms 的场景
- 吞吐可以直接翻好几倍
- CPU 反而更省(少了网络 IO)
很多时候,不是 Kafka 慢,是你发得太“心急”。
2️⃣ 分区数:不是越多越好,是“够用就行”
这是另一个被玩坏的点。
- 分区太少 → 吞吐上不去
分区太多 →
- Controller 压力大
- Rebalance 像地震
- 运维噩梦
我常用一个非常土但有效的估算公式:
分区数 ≈ 峰值写入 QPS / 单分区稳定 QPS
比如:
- 单分区稳定 5MB/s
- 峰值写入 500MB/s
那 100 个分区就够了,
别一上来就 500、1000 个。
三、低延迟,靠的不是“快”,而是“稳”
很多人以为低延迟 = 配置调到最激进。
其实恰恰相反。
1️⃣ acks=all 不是敌人,乱 retry 才是
很多新手为了追求低延迟:
props.put("acks", "0");
结果:
- 延迟是低了
- 数据丢了
- 业务直接炸锅
我个人的态度很明确:
数据接入层,不允许“赌”。
正确姿势是:
props.put("acks", "all");
props.put("retries", 3);
props.put("max.in.flight.requests.per.connection", 1);
你会发现:
- 延迟并没有想象中高
- 抖动反而少了
- 下游更稳定
2️⃣ Kafka vs Pulsar:延迟稳定性这块,Pulsar 真有点东西
说句掏心窝子的感受。
Kafka:
- 极致成熟
- 社区庞大
- 吞吐王者
Pulsar:
- 天生计算存储分离
- Topic 多了也不慌
- 延迟抖动控制得更好
在多租户、Topic 爆炸的场景下,
Pulsar 的优势非常明显。
比如一个典型的 Pulsar Producer:
Producer<byte[]> producer = client.newProducer()
.topic("persistent://public/default/log-topic")
.batchingMaxPublishDelay(10, TimeUnit.MILLISECONDS)
.batchingMaxMessages(1000)
.enableBatching(true)
.create();
一句话总结我的感受:
Kafka 更像肌肉男,Pulsar 更像耐力型选手。
四、真正的高手,都在接入层“留后手”
一个成熟的数据接入层,一定不是只管“写进去”。
1️⃣ 一定要可回放
- Topic 保留时间不要太短
- 不要一上来就
cleanup.policy=delete - 关键数据建议支持回溯
因为你永远不知道哪天要补数。
2️⃣ 一定要限流 + 保护
我见过最惨的事故之一:
- 某业务 bug
- 1 秒发 10 倍流量
- Kafka 集群直接雪崩
- 所有实时链路一起陪葬
解决方案其实很朴素:
- Producer 侧限流
- Topic 级别限速
- Broker 级别配额
接入层不是“老好人”,
它得学会拒绝无理请求。
五、写在最后:数据入口修好了,系统自然就顺了
干了这么多年大数据,我越来越有一个感受:
真正决定系统上限的,往往不是最“高级”的那一层,而是最早的那一层。
数据接入层做得好:
- 计算层压力小
- 延迟自然低
- 故障也好排
反过来:
- 接入层一塌糊涂
- 后面全是补锅工程