Spark 消费 Kafka 单节点耗时异常排查


1. 问题现象

Spark 消费 Kafka 时,大部分节点处理耗时都在 6 秒以内,但是有一个节点每次都要 22 秒左右,日志中没有明显异常。

草稿中记录的现象如下:

Spark 消费 Kafka 单节点耗时异常

这种问题比较麻烦,因为日志没有报错,任务也不是失败,只是某一个节点持续慢。

这类问题不能只看 Spark 应用日志,需要同时看:

  1. Spark UI 中 task 级别耗时。
  2. 慢节点所在 executor。
  3. executor 所在机器资源。
  4. Kafka partition 分布和 lag。
  5. 网络、磁盘、GC、CPU 等系统指标。

2. 先判断是节点慢还是数据慢

第一步不要直接怀疑 Kafka,也不要直接调 Spark 参数,先确认到底是“某台机器慢”,还是“某个 Kafka 分区数据量大”。

在 Spark UI 中查看对应批次的 Stage,重点看 Task 列表:

指标 重点
Executor 慢任务是否总在同一个 executor
Host 慢任务是否总在同一台机器
Duration 是否稳定比其他 task 高
Input Size / Records 是否读取数据量明显更大
GC Time 是否存在明显 GC
Scheduler Delay 是否调度等待时间高
Getting Result Time 是否结果回传慢

如果慢任务总在同一台机器,且数据量并不大,优先怀疑节点资源或网络问题。

如果慢任务不固定在同一台机器,而是固定在同一个 Kafka partition,优先怀疑 Kafka 分区数据倾斜。

3. 可能原因一:Kafka 分区数据倾斜

Spark 消费 Kafka 时,任务通常会按照 Kafka topic partition 拆分读取任务。如果某个 partition 的数据量明显比其他 partition 大,那么处理这个 partition 的 task 就会更慢。

查看 Kafka lag:

kafka-consumer-groups.sh \
  --bootstrap-server kafka01:9092 \
  --describe \
  --group your_group

重点看:

TOPIC
PARTITION
CURRENT-OFFSET
LOG-END-OFFSET
LAG
CONSUMER-ID
HOST

如果某个 partition 的 LAG 或每批读取记录数明显更大,就需要检查 Kafka 写入端的 key 分布。

常见原因:

  1. producer 使用固定 key,导致数据打到少数 partition。
  2. 某些业务 key 热点明显。
  3. topic partition 数量太少。
  4. Spark 每批读取上限设置不合理。

Structured Streaming 可以通过 maxOffsetsPerTrigger 控制每批读取量:

spark.readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "kafka01:9092")
  .option("subscribe", "topic_name")
  .option("maxOffsetsPerTrigger", "100000")
  .load()

4. 可能原因二:Executor 所在机器资源异常

如果慢任务总是落到同一个 host,优先检查这台机器。

4.1 CPU

top
mpstat -P ALL 1

看是否存在:

CPU 使用率过高
iowait 过高
单核打满

4.2 内存和 GC

Spark 官方调优文档中也提到,GC 会影响任务执行时间。可以给 executor 打开 GC 日志:

--conf "spark.executor.extraJavaOptions=-XX:+PrintGCDetails -XX:+PrintGCTimeStamps"

然后到慢节点查看 executor 日志:

yarn logs -applicationId application_xxx | grep -i "Full GC"

如果慢节点存在频繁 Full GC,就需要调整 executor 内存、并发数或代码中的对象创建方式。

4.3 磁盘

iostat -x 1
df -h

重点看:

%util
await
iowait
磁盘剩余空间

Spark 任务如果发生 shuffle spill,磁盘慢会明显放大 task 耗时。

4.4 网络

sar -n DEV 1
ping kafka01

也可以从慢节点测试访问 Kafka broker:

nc -vz kafka01 9092

如果慢节点到 Kafka broker 网络延迟高、丢包、带宽打满,也会导致消费慢。

5. 可能原因三:Kafka Broker 分布不均

如果某个 Spark 节点总是从同一个 Kafka broker 拉数据,而这个 broker 本身压力大,也会造成局部慢。

可以查看 topic partition 分布:

kafka-topics.sh \
  --bootstrap-server kafka01:9092 \
  --describe \
  --topic topic_name

关注:

Leader
Replicas
Isr

如果慢的 partition leader 集中在某个 broker,并且这个 broker 负载高,可以考虑:

  1. Kafka 分区重分配。
  2. 调整 partition leader 分布。
  3. 扩容 broker。
  4. 检查 broker 磁盘和网络。

6. 可能原因四:Spark 本地性和调度问题

Spark UI 中如果慢任务的 Scheduler Delay 很高,说明任务不一定是执行慢,也可能是调度等待慢。

可以看:

Locality Level
Scheduler Delay
Task Deserialization Time
Executor Run Time

如果是调度延迟,可以检查:

  1. executor 数量是否不足。
  2. 单个 executor core 是否设置太大。
  3. 是否有其他任务抢占资源。
  4. YARN 队列是否资源紧张。

Spark 官方文档也提到,Spark 程序的瓶颈可能来自 CPU、网络、内存等多个资源,不应该只从代码层面排查。

7. 推荐排查路径

我一般会按下面顺序排查:

7.1 在 Spark UI 定位慢 task

记录下面信息:

Stage ID
Task ID
Executor ID
Host
Duration
Input Records
GC Time
Scheduler Delay

7.2 判断慢是否固定在某台机器

如果每次都是同一台 host 慢,先查机器:

top
iostat -x 1
sar -n DEV 1
df -h

7.3 判断慢是否固定在某个 Kafka partition

查看 consumer group lag:

kafka-consumer-groups.sh \
  --bootstrap-server kafka01:9092 \
  --describe \
  --group your_group

7.4 检查 Kafka broker

kafka-topics.sh \
  --bootstrap-server kafka01:9092 \
  --describe \
  --topic topic_name

7.5 检查 GC

打开 GC 日志后观察慢节点:

yarn logs -applicationId application_xxx | grep -i "gc"

如果慢节点 GC 明显更高,就不是 Kafka 本身的问题。

8. 解决办法

不同原因对应不同解决方式:

原因 解决方式
Kafka partition 数据倾斜 调整 producer key、增加 partition、限制每批读取量
某台 executor 机器慢 修复机器 CPU、磁盘、网络、内存问题,必要时下线节点
Kafka broker 压力集中 重分配 partition,均衡 leader
GC 时间高 调整 executor 内存、core、序列化方式,减少对象创建
调度延迟高 增加资源,调整 executor 数量和 core 数

如果只是某一台节点持续慢,最直接的验证方式是临时把这台机器从 YARN NodeManager 或 Spark 可用节点中摘掉,再观察任务耗时是否恢复正常。

如果摘掉后耗时恢复,说明问题基本就在这台机器或它到 Kafka/HDFS 的链路上。

9. 总结

Spark 消费 Kafka 时,单个节点长期比其他节点慢,不应该只看应用日志。日志没有异常并不代表系统没有问题。

排查重点是先做归因:

是某台机器慢?
还是某个 Kafka partition 慢?
还是某个 broker 慢?
还是 Spark 调度或 GC 慢?

确认方向以后再处理,不要一上来就调 maxOffsetsPerTrigger 或 executor 参数。参数调整只能缓解问题,如果根因是节点网络、磁盘、GC 或 Kafka 分区倾斜,最终还是需要把这些基础问题修掉。


文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录