Laurenfrost's Blog.
今朝有酒今朝醉,明日愁来明日愁。
From Databricks to Dataproc
Spark 迁移之痛
Contents
成为班逼的第 5 个年头马上就要过去了,当年的萌新彻底成为了老油条。期间先是在 Azure 上折腾 Databricks 环境,后面一转 AWS 云架构开发。到了今年年初,老板大手一挥我干了大半年的 AWS 迁移就停了,开始 allin GCP。考了两个云的 Cloud Architect Professional,结果屁也用不上,属于是三大云厂商的浑水都趟了个遍。这个从入职开始就挂在我头上 Spark 黑锅也跟着我转战南北,直到前几个月开始的迁移+降本增效任务,这个 Spark 数据处理项目走到了 GCP 的 Dataproc 面前。
Dataproc 作为 GCP 提供的 ETL 环境,其实提供了两种解法:Dataproc Serverless 和 Dataproc Cluster。后者相当于传统的 Spark 集群构建思路,选择合适的 Compute Engine 实例在上面安装 Spark 之类的环境然后自己往里提交任务,GCP 另外再提供一套正常类似于 EC2 的 AutoScaling 机制协助你的集群扩容。
| 服务 | Dataproc Serverless | Dataproc Cluster |
|---|---|---|
| 处理框架 | Spark | Spark/Hive/Flink/Trino/Kafka |
| 无服务器 | 是 | 否 |
| 启动时间 | 60 秒 | 90 秒 |
| 基础架构控制 | 否 | 是 |
| 资源管理 | 基于 Spark | 基于 YARN |
| GPU 支持 | 是 | 是 |
| 交互式会话 | 是 | 否 |
| 自定义容器 | 是 | 否 |
| 直接 SSH 到虚拟机 | 否 | 是 |
| Java 版本 | Java 17、11 | 支持过往版本 |
** *这就是 2025 年 12 月时点上GCP 官方文档里的比较
Dataproc Serverless 就不似这种胭脂俗粉,你只要在随便哪个 Juypter Notebook 里 import 一下它的包,然后创建一个 SparkSession,云上自动就会为你分配好一个 Spark 计算资源。一看到 “Serverless” 我这个被云厂商调教成的巴普洛夫的狗就汪汪叫了:啊!彻底摒弃复杂的计算资源管理,计算 Worker 节点的大小还有它们之间的通信也不用操心了,一切都交给伟大的 Google,他会用神奇的魔法消弭一切伤痛。
# pip install dataproc_spark_connect
# 题外话:当然如果你直接在 BigQuery Notebook 的界面里直接运行就不用 install 了
# 不过那个环境本质是 Vertex Colab Enterprice 提供的 Notebook Runtime
from google.cloud.dataproc_spark_connect import DataprocSparkSession
from google.cloud.dataproc_v1 import Session
import pyspark.sql.functions as f
session = Session()
# 创建 Spark Session,就像往常一样
spark = (
DataprocSparkSession.builder
.appName("APP_NAME")
.dataprocSessionConfig(session)
.getOrCreate()
)
# 然后用就完了
df = spark.read.format("bigquery").option("table", "bigquery-public-data.samples.shakespeare").load()
df.show()
是的,当你执行完上面代码中 DataprocSparkSession.builder.getOrCreate() 的部分后,Jupyter 界面上会出现一个缓慢行走的进度条,告诉你它正在创建一个 DataprocSparkSession。是的,这个 Session 是实际存在于 GCP 的计算资源。每一次执行 getOrCreate() 都会创建一个 Session,然后你可以在 GCP 的管理界面看到它们:

在这个界面上点开你刚刚创建的 Session,你可以检视这个 Spark Session 的一切设置。 点开 Monitoring 你可以看到各个 Exector 的工作情况。 你甚至可以通过 Google Cloud Logging Query 查询整个项目的日志信息。

哇!这是现代计算设施的力量!这是云原生的胜利!荣誉归于伟大的 Google!
现在我要开始我的迁移了!把我那乱七八糟的 Notebooks 从昂贵的 Databricks 环境中抢救出来,让它们在 GCP 的自由空间中撒欢吧!
Dataproc Serverless 的苦痛
一切都是如此美好,就像刚刚结识的女友一样。等过了一开始的兴奋劲头,就会不断认识到她的各种缺点:Dataproc Serverless 什么都好,就是不好用。
SparkSession 启动缓慢,而且会因为网络问题失败
官方文档上说 “启动时间 60 秒”,实际上启动时间远不止这些。
而且这个 Python 库本质是创建了一个 SSH 代理,把本地 PySpark 客户端的网络请求送到 GCP 中,然后 GCP 再把数据包交给你刚创建的 Session。
依然是网络问题,访问外部数据库很麻烦
是的,哪怕是我想让我的 spark 去访问一个 PostgreSQL 数据库然后从里面读取一些数据都很费劲
df = spark.read \
.format("jdbc") \
.option("url", f"jdbc:postgresql://{host}:{port}/{database}") \
.option("driver", "org.postgresql.Driver") \
.option("user", username) \
.option("password", password) \
.option("dbtable", source_table) \
.load()
依赖库很难安装,装上去了也不会共享给 Executor
把之前在 Databricks 上运行的机器学习库搬过来,没有办法安装。
Docker?可能也不是一个好的选择
通过阅读 GCP 的官方文档,我们可以看到他提供了一个选项,可以让我们自己构建一个 Docker Image 提交上去运行。
Dataproc Cluster 的毛病
我受够了这一切。经过两三周的尝试后,我决定放弃 Serverless。 也许 Cluster 没有那么优雅,但至少一切都在用户的掌控之中,不是吗?
哈哈
我可能是被 Databricks 惯坏了。
如何访问 Spark?
- Cluster 自带的 Jupyter 难用
- local 的 Jupyter 没法直接访问
- Jupyter Kernal 莫名其妙断联
磁盘空间需要一开始自己分配,后续无法添加
工单处理缓慢
项目代码管理的迷思
- BigQuery Notebook 可以接入 GitHub(通过某个开发者自己的 ssh-key)
题外话:bigquery 的臭毛病
BigQuery 看起来眉清目秀,算起来飞一般快。而且按数据量收费,1TB 数据 7.5 美刀,讲道理不是特别贵。
但你休想从 GCP 这里薅羊毛!如果你的 SQL 占用的 CPU 时间过长,比如大量的 Geometry Polygon 的相交查询,它会直接停止计算:
Query exceeded resource limits. This query used 2400379 CPU seconds but
would charge only 2940M Analysis bytes. This exceeds the ratio supported
by the on-demand pricing model. Please consider moving this workload to
a capacity-based pricing model, which does not have this limit. 2400379
CPU seconds were used, and this query must use less than 752600 CPU seconds.
这种时候就必须把表拆分成一个个的小表然后分开计算了。
Hello? Internal Error
当讲道理这些都还能接受。都是生意嘛,反正花的是公司的钱,我这边只要有能说得过去的产出一切都好说。
但如果我报错 Internal Error 阁下又当如何应对?
An internal error occurred and the request could not be completed. This
is usually caused by a transient issue. Retrying the job with back-off as
described in the BigQuery SLA should solve the problem:
https://cloud.google.com/bigquery/sla. If the error continues to occur
please contact support at https://cloud.google.com/support. Error: 80038528
工单处理非常缓慢,是的,非常缓慢
当晚就有在线印度客服回答我的问题,非常热情,直到我给他展示我遇到的 Internal Error。然后他让我等邮件回复。两天后他们回复了:
Thank you for your patience as we continue to investigate your BigQuery ML model training issue. I’ve received an update from our internal team that I believe will be helpful.
Based on our analysis of the error logs, it appears the “internal error” you’re seeing is likely caused by memory constraints during the model training process. This can often happen with larger datasets or complex models.
To address this, we recommend that you please try running your BigQuery ML training job with a larger memory type.
We are confident that increasing the available memory for the job will help resolve this issue for you. Please do not hesitate to let us know if you have any further questions or if you require any assistance with this adjustment.
好的,让我重新用 “更大的内存” 重新训练我的 BigQuery ML。这他妈简直就是废话,我当然能猜到这是资源不够导致的,但你这是 BigQuery 诶! 你让我调整资源?我上哪去调整资源?你怎么不让我进数据机房搬设备插网线呢?
Thank you for your patience and understanding regarding your recent request.
We have consulted with our product engineering team regarding your concern, and they have confirmed that we will be increasing the training machine memory size as requested.
We will provide you with an update as soon as this change has been implemented. Please expect an update no later than 10:30 PM IST (UTC+5:30) xx-xxx-2025.
回复的邮件说让我等下一封邮件,一定会给我调整。然后下一封也是一模一样的内容。一共延期了四次,每次都说让我等三四天。前前后后总共折腾了 3 周多一点,最后终于调好了:
Thank you for your patience and understanding while we addressed this for you.
We have consulted with our product engineering team, and they have successfully increased the memory size for your training machine.
Please try running your process again at your convenience. Should you encounter any further issues, please do not hesitate to let us know, and we will be happy to assist you further.
Looking forward to your response.
哈哈哈,谢谢你们的辛勤工作,我早就放弃这个方案了。你们白调整了。
感想
每一次逃离 Databricks 环境的尝试,都是在进一步证明 Databricks 的伟大。
伟大,无需多言