从EMR迁移到Databricks零故障——Hadoop生态迁移实战
先说结论
大规模Hadoop生态迁移的核心方法论是'双写双读灰度':不是一刀切换,而是让新旧系统并行运行一段时间,逐步迁移验证。关键步骤:① 评估兼容性差异;② 双写双读灰度方案;③ 分批迁移(按优先级排序);④ 数据一致性校验;⑤ 旧系统下线。整个过程花了约3个月。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
这篇是我职业生涯中最有成就感的项目之一。在某知名出海硬件品牌,我独立负责了从AWS EMR到Databricks的全链路迁移——100+个Spark作业、覆盖数仓全部ETL链路、零故障完成。这个项目不仅是技术挑战,更是方法论和风险控制的考验。面试大厂时讲这个项目经历,面试官通常会追问很多细节。今天把迁移的思路、方案和踩坑完整分享。
为什么要迁移?——EMR的痛点
| 痛点 | 具体问题 | Databricks怎么解决 |
|---|---|---|
| 运维复杂 | NameNode高可用、DataNode均衡、YARN队列调优 | 全托管,零运维 |
| 性能不够 | Hive on MR慢,即使用Spark也缺少AQE等优化 | Databricks Runtime内置优化 |
| 成本高 | 集群按峰值配置,低峰期浪费 | 自动集群、按使用量付费 |
| 协作差 | Notebook体验差,缺少版本控制 | Databricks Notebook+Repos |
| 数据湖弱 | Delta Lake支持有限 | Delta Lake原生支持ACID/Time Travel |
迁移方案:双写双读灰度
# 迁移方案的核心思路:双写双读
#
# 阶段一:双写(2周)
# ETL作业同时在EMR和Databricks上跑
# 两边都写入S3(不同目录)
# EMR写入: s3://data/warehouse/emr/
# Databricks写入: s3://data/warehouse/dbr/
#
# 阶段二:数据校验(1周)
# 对比两边的输出结果
# 行数、聚合值、抽样数据是否一致
# 不一致的作业单独排查修复
#
# 阶段三:切读(1周)
# 下游报表和API切换到读Databricks的输出
# EMR继续跑作为fallback
#
# 阶段四:下线EMR(确认稳定后)
# 停止EMR上的作业
# 保留集群1周做最后的数据备份
# 彻底关闭EMR集群
分批迁移策略
100+个Spark作业不可能同时迁移。我按优先级分了4批:
| 批次 | 作业类型 | 数量 | 迁移周期 | 风险 |
|---|---|---|---|---|
| 第1批 | 独立的数据清洗作业(无下游依赖) | 30个 | 1周 | 低 |
| 第2批 | DWD层ETL(有下游但可重跑) | 40个 | 2周 | 中 |
| 第3批 | DWS/ADS层聚合作业(影响报表) | 25个 | 2周 | 高 |
| 第4批 | 核心指标计算(影响业务决策) | 10个 | 1周 | 极高 |
原则:从风险低的开始,积累经验后再处理高风险的。第1批相当于练手——即使出问题也不影响下游。到第3、4批时方法论已经成熟了,处理起来更有信心。
SQL方言差异——最大的技术挑战
EMR用的是Hive SQL+Spark SQL,Databricks用的是Spark SQL+Delta Lake SQL。大部分SQL兼容,但约20%的作业需要修改:
-- 差异一:日期函数
-- EMR (Hive): date_sub('2024-01-15', 7)
-- Databricks: date_sub(DATE '2024-01-15', 7)
-- 或: current_date() - INTERVAL 7 DAY
-- 差异二:INSERT OVERWRITE
-- EMR (Hive): INSERT OVERWRITE TABLE t PARTITION (dt='2024-01-15')
-- Databricks (Delta): MERGE INTO 或 INSERT OVERWRITE(自动分区)
-- 差异三:维度表更新
-- EMR: UNION方式全量覆盖
-- Databricks: MERGE INTO(增量更新,更高效)
-- 我把原来的UNION改成MERGE INTO,代码量减少了70%
-- 差异四:Hive特有语法
-- LATERAL VIEW EXPLODE 在Spark SQL里用不同写法
-- Hive的UDF可能不兼容,需要改写成Spark UDF
-- 总结:100+作业中约20个需要修改SQL
-- 大部分是日期函数和INSERT语法的微调
数据一致性校验——迁移的质量保障
# 数据一致性校验脚本(简化版)
def validate_table(table_name, dt):
emr_df = spark.read.parquet(f's3://data/warehouse/emr/{table_name}/dt={dt}')
dbr_df = spark.read.parquet(f's3://data/warehouse/dbr/{table_name}/dt={dt}')
# 1. 行数校验
assert emr_df.count() == dbr_df.count(), f'Row count mismatch!'
# 2. 聚合值校验
for col in numeric_columns:
emr_sum = emr_df.agg({col: 'sum'}).collect()[0][0]
dbr_sum = dbr_df.agg({col: 'sum'}).collect()[0][0]
assert abs(emr_sum - dbr_sum) < 0.01, f'{col} sum mismatch!'
# 3. 抽样校验(随机抽1000行对比)
# ...
print(f'{table_name} dt={dt}: PASSED')
我对每一批迁移的每张表都跑了这个校验脚本。100+个作业总共校验了约300张表的数据。发现了3个不一致的问题——全是SQL方言差异导致的,修复后重跑通过。
迁移后的效果
| 维度 | 迁移前(EMR) | 迁移后(Databricks) | 提升 |
|---|---|---|---|
| ETL总执行时间 | 5-6小时 | 3小时 | 减少40% |
| 查询延迟 | 平均30秒 | 平均9秒 | 降低70% |
| 月成本 | ~5万美元 | ~3.5万美元 | 降低30% |
| 运维工作量 | 每周约10小时 | 每周约4小时 | 减少60% |
| 存储成本 | ~2万美元 | ~1.3万美元 | 降低35%(Delta压缩+Z-Ordering) |
面试高频追问
追问一:迁移过程中最大的风险是什么?
数据不一致。如果新旧系统产出的数据不一样,下游报表和业务决策就会出错。这比作业失败更可怕——作业失败会报错,数据不一致可能静默地产生错误结果。所以数据校验是迁移最重要的环节,我在每一批迁移中都投入了30%+的时间做校验。
追问二:有没有迁移失败回滚过?
有一次。第2批迁移中有一个作业因为Hive UDF在Databricks上不兼容导致输出结果少了一列。校验时发现后回滚到EMR版本,修复UDF兼容性后重新迁移。这就是双写双读的好处——EMR一直在跑作为fallback,随时可以切回去。
追问三:迁移需要停服吗?
不需要。双写双读方案的核心优势就是零停服——新旧系统并行运行,切换是渐进式的。下游业务方几乎感知不到迁移的发生,他们只是某一天开始从Databricks的输出目录读数据而已。
总结
Hadoop生态迁移面试讲清楚四个关键点:① 迁移动因(EMR的痛点和Databricks的优势);② 迁移方法论(双写双读灰度,分批迁移);③ 技术挑战(SQL方言差异、数据一致性校验);④ 量化效果(ETL减少40%、查询降低70%、成本降低30%)。这是一个能讲15-20分钟的完整项目故事,大厂面试非常喜欢。
下一篇聊存储选型:HDFS、S3、OSS到底该用哪个?存算分离是大趋势吗?
你们有做过大数据平台迁移吗?遇到了什么挑战?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长