同步与异步发送的关键在于业务节奏适配而非技术高低;异步靠batch.size(16kb~64kb)和linger.ms(5~20ms)激活批量压缩,吞吐可达同步百倍,但需警惕回调线程耗时操作及异常漏检风险。

同步发送和异步发送不是“选哪个更高级”,而是“在哪种业务节奏里更合适”。关键不在代码多一行少一行,而在你愿不愿意让业务线程为一次网络往返买单。
吞吐量:异步天然占优,但靠配置激活
异步发送默认走内存缓冲(RecordAccumulator)+ 批量压缩路径,吞吐量可轻松达到同步模式的百倍级。但这优势不会自动生效——它依赖两个核心参数协同工作:
- batch.size:建议设为 16KB~64KB,太小导致频繁发包,太大增加端到端延迟
- linger.ms:设为 5~20ms(非 0),给缓冲区一点“攒单”时间,尤其在低频写入场景下能显著提升批次命中率
同步发送无法利用批量机制,每条消息都触发独立请求,TPS 很难突破 500(无重试、局域网环境)。若业务每秒产生上千条订单事件,硬用 .get() 就等于主动给线程池上锁。
延迟感知:同步“显性高”,异步“隐性稳”
同步调用的延迟 = 网络 RTT + Broker 处理时间 + 序列化开销,波动大且直接拖慢业务响应;异步调用返回延迟通常
对用户操作类链路(如下单后实时通知),应优先保障接口响应快——用异步发消息,再通过状态机或数据库字段驱动后续动作;对风控拦截等强依赖消息即时性的环节,可结合 send().get() + timeout 控制(如 200ms 超时抛异常),避免阻塞太久。
可靠性不是发送方式决定的,而是配置+兜底共同保障的
很多人误以为“同步=不丢”,“异步=可能丢”。实际上:
- 同步发送若没配 retries > 0 和 delivery.timeout.ms,遇到瞬时网络抖动照样失败且不重试
- 异步发送只要设置 acks=all + 合理 retries,并在回调中检查 exception 是否为空,其持久化语义与同步完全一致
- 真正风险点在于:异步回调运行在 Sender 线程,不能做耗时操作(如远程调用、DB 写入);同步模式则天然在业务线程,便于统一事务管理
错误处理粒度:同步直抛异常,异步需主动捕获
同步模式下,TimeoutException、ClusterAuthorizationException 等直接向上冒泡,适合配合 Spring 的 @Retryable 或 try-catch 做即时降级;异步模式下,所有结果(成功 metadata 或失败 exception)都在 Callback 里,必须显式判断:
- exception 为 null → 消息已提交,可记录 offset 或更新状态
- exception 非 null → 需区分是可重试异常(如 NetworkException)还是不可重试(如 SerializationException),前者可重新构造 record 再 send,后者应告警并人工介入
漏掉回调里的异常检查,是线上丢消息最常见的原因——比选错模式更危险。











