SparkStreaming 之 Direct 模式并行度设置与 offset 管理

摘要:Direct 模式上线前有两个问题绕不开:并行度怎么调,offset 怎么管。前者很多人栽在"executor 加了不少,吞吐还是上不去"上------因为 Direct 模式的并行度天花板是 Kafka 分区数;后者决定你能否做到 exactly-once。这篇把这两个问题一次讲清,各给一套能落地的配置和代码。

关键词:Spark Streaming, Direct 模式, 并行度, Kafka 分区, offset 管理, exactly-once


上篇:并行度设置

一、先记住一条铁律

Direct 模式下,RDD 的分区数 = Kafka 的分区数,每个 Kafka 分区对应一个 RDD 分区。这直接决定了并行度的上限。

所以一个最常见的误区是:executor 加了一堆、--executor-cores 调得很大,但 topic 只有 3 个分区------并行度还是 3,一个 batch 最多就 3 个 task 在跑,其余核全闲着。调并行度,先看 Kafka 分区数,别在 executor 数量上空转。

二、三个决定并行的因子

  1. Kafka 分区数:决定 RDD 分区数,是并行度的天花板。
  2. executor 核数:决定同时能跑多少 task。总核数要 ≥ 分区数,否则 task 排队。
  3. maxRatePerPartition:每个分区每个 batch 最多拉多少条,用来限流/反压。

三、调优目标和配置

调优目标就一句:一个 batch 的处理时间 < batchInterval。做不到,batch 就会堆积,端到端延迟越来越大。

处理跟不上时,按顺序三招:

  1. 增加 Kafka 分区数(提高并行度上限);
  2. 加 executor 核数(让 task 不排队);
  3. 调大 batchInterval(给每个 batch 更多时间)。
bash 复制代码
# 提交时设置 executor 核数
spark-submit --executor-cores 4 --num-executors 6 ...

# 限流:每分区每 batch 最多拉 10000 条
# kafkaParams 里加:
"spark.streaming.kafka.maxRatePerPartition" -> "10000"

# 配合反压(动态调整拉取速率)
"spark.streaming.backpressure.enabled" -> "true"

两个注意点:

  • 核数要给后续 stage 留余地。拉数据的 task 只占一部分核,shuffle、reduce 这些后续 stage 也要核。核数刚好等于分区数时,后续 stage 会没核可用。
  • Direct 模式没有 blockInterval 参数。那是 Receiver 模式切 block 用的,Direct 模式调了没效果,别搞混。

下篇:offset 管理

四、三种方式,选哪种

方式一:自动管理(默认,存 checkpoint)

什么都不用做,Spark 自动把 offset 存进 checkpoint,Job 成功自动提交。前提是开了 checkpoint 且 enable.auto.commit=false

局限:offset 和业务状态一起锁在 checkpoint 里,没法独立回放、迁移。适合简单场景。

方式二:手动管理(commitAsync)

scala 复制代码
stream.foreachRDD { rdd =>
  val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
  // ... 处理 rdd,写外部存储 ...
  stream.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges)  // 成功才提交
}

核心是"处理成功才提交",实现处理---提交的原子性,这是 exactly-once 的实现方式。上一篇文章说过:offsetRanges 只能在第一个转换里取,rdd.map(...) 之后类型就丢了。

方式三:外部存储(ZK / 数据库)

把 offset 存到 ZK 或数据库,独立于 checkpoint。典型做法是把处理结果和 offset 放进同一个事务------结果写成功,offset 才推进,实现端到端 exactly-once。这是最严格、也是生产上对一致性要求高时的选择。

五、指定 offset 回放

有时候需要从某个位置重新消费(比如补数据、事故回放),用 Assign 策略 + 显式 fromOffset:

scala 复制代码
val fromOffsets: Map[TopicPartition, Long] = Map(
  new TopicPartition("topic-a", 0) -> 1000L,
  new TopicPartition("topic-a", 1) -> 2000L
)

val stream = KafkaUtils.createDirectStream[String, String](
  ssc,
  PreferConsistent,
  ConsumerStrategies.Assign[String, String](
    fromOffsets.keys.toList, kafkaParams, fromOffsets)
)

fromOffsets 指定每个分区从哪个 offset 开始消费,配合外部存储的 offset 就能做精确回放。


六、总结

  • 并行度铁律:RDD 分区数 = Kafka 分区数,调并行度先加 Kafka 分区,别空加 executor。
  • 三个并行因子:Kafka 分区(上限)、executor 核数(不排队)、maxRatePerPartition(限流)。
  • 调优目标:一个 batch 处理时间 < batchInterval;核数要给后续 stage 留余地。
  • offset 三种方式:自动(存 checkpoint,简单)、手动(commitAsync,处理成功才提交)、外部存储(结果+offset 同事务,端到端 exactly-once)。
  • 需要回放时用 Assign + fromOffsets 指定起始位置。

作者 :大数据技术实践者

博客blog.starzy.cn

GitHubstarzy1990.github.io

专注 AI Agent · LangGraph · RAG · 大数据架构 · 数据工程实践

相关推荐
xiaoduo AI1 小时前
抖音小店客服机器人哪个好?选择AI客服主要看哪些功能?
大数据·人工智能·机器人
BYSJMG1 小时前
计算机毕业设计选题推荐|【基于大数据的植被光谱特征与环境因子关联分析及可视化】Spark+K-Means
大数据·python·信息可视化·数据分析·spark·kmeans·课程设计
Ai思想家2 小时前
一次模型调用会留下什么:聚合平台的日志留存与数据边界
大数据·服务器·网络·人工智能
亚古数据2 小时前
香港公司商业登记册内资料是什么?和商业登记证有何区别?跨境合作前必读
大数据
大力财经2 小时前
抖音生活服务品牌零售行业峰会在杭州举办,探索线下生意新增量
大数据·人工智能·区块链
code 小楊2 小时前
生产级 Agent 评测体系实战:从 12 指标框架到 CI/CD 质量门禁全链路落地
大数据·人工智能·ci/cd
姜穆澜2 小时前
OneID 从 0 到 1 完整生产案例( 六)
大数据
小五传输3 小时前
聚焦卫健数字化建设 文件传输服务器守护跨机构敏感医疗数据交换
大数据·运维·安全