GCP Dataproc Spark作业日志如何路由导出至GCS存储桶
GCP Dataproc Spark作业日志持久化到GCS及作业通知实现方案
问题说明
- 日常在GCP平台运行Scala开发的Spark作业,需要实现作业结束后自动发送通知的能力
- 最初设计的方案是拉取作业日志,通过grep匹配特定完成标识触发通知,但发现作业日志仅在控制台作业详情页展示,没有持久化存储为文件
- 尝试直接将作业提交命令的输出重定向到GCS路径时,报错
grep:**-2022-07-08.log: No such file or directory,使用的提交命令如下:
gcloud dataproc jobs submit spark \ --project $PROJECT --cluster=$CLUSTER --region=$REGION --class=***.spark.offer.Main \ --jars=gs://**.jar\ --properties=driver-memory=10G,spark.ui.filters="",spark.memory.fraction=0.6,spark.sql.files.maxPartitionBytes=5368709120,spark.memory.storageFraction=0.1,spark.driver.extraJavaOptions="-Dcq.config.name=gcp.conf",spark.executor.extraJavaOptions="-Dlog4j.configuration=log4j-executor.properties -Dcq.config.name=gcp.conf" \ --gcp.conf > gs://***-$date.log 2>&1
- 核心疑问:
- 有没有方案能把这类日志路由存储到GCS存储桶,方便后续检索
- 是否需要修改log4j配置,直接给
log4j.appender.stdout = org.apache.log4j.ConsoleAppender配置项指定GCS存储桶路径作为输出位置
问题原因
首先明确两个基础认知:
- Shell的重定向符
>默认仅支持写入本地文件系统路径,无法直接识别gs://开头的GCS路径,这是你当前报错的直接原因 - Log4j原生的ConsoleAppender只负责输出到控制台标准输出流,不支持直接配置GCS路径作为输出目标,强行配置会触发路径非法、类找不到等错误,不需要在这个配置项上改GCS路径。
可行方案
方案1:本地临时文件中转+gsutil上传(改造成本最低,无需修改集群和作业配置)
不需要改任何作业代码或者log4j配置,调整提交流程即可:
- 先把作业的标准输出、错误输出重定向到运行gcloud命令的机器本地临时文件
- 等作业执行完成后,用gsutil把本地临时日志文件拷贝到目标GCS路径
- 直接对本地临时文件做grep匹配,命中作业完成标识就触发通知逻辑
修正后的提交命令参考:
# 定义本地临时日志路径 LOCAL_LOG="/tmp/spark-offer-job-${date}.log" # 提交作业,注意传给作业的自定义参数gcp.conf要放在--后面,之前的--gcp.conf写法是错误的,会被gcloud识别为自身参数触发异常 gcloud dataproc jobs submit spark \ --project $PROJECT --cluster=$CLUSTER --region=$REGION --class=***.spark.offer.Main \ --jars=gs://**.jar\ --properties=driver-memory=10G,spark.ui.filters="",spark.memory.fraction=0.6,spark.sql.files.maxPartitionBytes=5368709120,spark.memory.storageFraction=0.1,spark.driver.extraJavaOptions="-Dcq.config.name=gcp.conf",spark.executor.extraJavaOptions="-Dlog4j.configuration=log4j-executor.properties -Dcq.config.name=gcp.conf" \ -- gcp.conf > $LOCAL_LOG 2>&1 # 作业执行完成后上传日志到GCS gsutil cp $LOCAL_LOG gs://***-$date.log # 匹配日志标识触发通知 grep "你的作业完成专属标识" $LOCAL_LOG && # 此处拼接发送通知的命令即可
方案2:开启Dataproc平台自带的日志持久化(适合长期稳定运行的集群,无需每次提交改命令)
Dataproc本身自带日志持久化能力,创建集群时直接在日志配置项中指定GCS作为日志存储目标即可,后续集群上所有提交的Spark作业,Driver、Executor的全量日志都会自动按作业ID、运行节点分目录存储到指定GCS路径下,不需要修改作业内的任何log4j配置。
不建议自行在log4j中引入第三方GCS Appender,一方面需要额外把GCS连接器依赖打入作业包或者放到集群classpath,另一方面分布式运行的Executor节点容易出现权限校验失败、日志分片重复/丢失的问题,稳定性远不如平台原生的日志同步能力。
方案3:跳过日志匹配,直接用命令返回值判断作业状态(可靠性最高)
靠grep日志标识判断作业完成状态存在误判、漏判风险——比如日志打印格式调整、异常栈里刚好打印了匹配关键词都会触发逻辑异常。实际上gcloud dataproc jobs submit是同步阻塞执行的:作业运行成功时命令的退出码为0,运行失败、被kill时退出码为非0,直接判断命令退出码就能准确知道作业运行状态,触发对应成功/失败的通知,完全不需要依赖日志内容。
内容的提问来源于stack exchange,提问作者Yemane
相关产品推荐
相关产品推荐

