结论先说: 顺序消息的分区键选错,会把「单个买家」的流量集中到一个分区,导致该分区积压 2.3 亿条消息。真正治本的不是加机器,而是把分区键从 buyerId 换成 orderNo。
一、现象与背景:不是「整体积压」,而是「一个分区在流血」
压测时发现 partition-07 的 lag 从 0 涨到 2.3 亿条,单分区消费 TPS 被压到 800。影响很直接:凡是路由到 07 的订单,发货通知平均延迟 11 分钟,客服工单当天翻倍。
二、根因:顺序消息 = 单分区单线程,而分区键把「大买家」全灌进一个分区
- 顺序消息在 Kafka 里是靠「同一 key 落同一分区 + 消费者对该分区单线程」实现的。我们生产端用
orderNo的买家 ID 哈希做分区键(本意是「同一买家的订单有序」),但真正需要有序的是订单号维度,不是买家维度——这个语义错配是病根。 - 有个大客户(企业采购账号),一次压测灌了 40 万单,
hash(buyerId) % 12全落在 07。于是 07 的进水速率是其它分区的 30 倍,而消费端因为要保证顺序,07 只能 1 个线程串行处理。 - 串行 + 下游 DB 单条写(每条状态变更一次
UPDATE,平均 8ms)+ 偶发锁等待,把 07 的有效吞吐钉死在 800 TPS,远低于集群平均的 1.1w。
三、具体做法:改分区键 + 批量落库 + 死信兜底
1)把分区键从 buyerId 换成 orderNo(业务真正需要有序的维度)
// 生产端:用订单号做分区键,保证「同一订单」有序即可,不必「同一买家」有序
producer.send(new ProducerRecord<>(
"order-state-topic",
orderNo, // key = orderNo
JSON.toJSO
0赞
0收藏
0评论
3浏览