第4章 环境搭建:Spark + Delta Lake + Kafka集群
说实话,环境搭建这块,看着简单,但坑是真不少。我见过太多人花了两天时间搭环境,最后发现是版本不兼容。所以这一章,咱们把版本、配置、踩坑点一次性说清楚。
4.1 版本兼容性——先看这张表
为什么先讲版本?因为Delta Lake和Kafka的版本匹配,是很多新手翻车的地方。我刚开始用Delta Lake 1.0配Spark 3.0,结果跑起来各种报错,查了半天才发现是API不兼容。
下面这张表,是我在实际项目中验证过的组合,直接照着来就行:
| 组件 | 推荐版本 | 最低版本 | 备注 |
|---|---|---|---|
| Apache Spark | 3.3.2 | 3.2.0 | Delta 2.x 必须用 Spark 3.x |
| Delta Lake | 2.3.0 | 2.0.0 | 与 Spark 3.3 完美配合 |
| Apache Kafka | 3.4.0 | 3.0.0 | 建议用 Confluent 发行版 |
| Kafka Connect | 3.4.0 | 3.0.0 | 与 Kafka 版本一致 |
| Scala | 2.12.17 | 2.12.10 | Spark 3.x 默认 Scala 2.12 |
| Java | 11 | 8 | 推荐 OpenJDK 11 |
4.2 集群搭建步骤
我个人习惯用 Docker Compose 来搭建测试环境,这样干净、可重复。生产环境当然要用物理机或云集群,但开发阶段,Docker 足够了。
4.2.1 启动 Kafka 集群
先写一个 docker-compose.yml:
version: '3.8'
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.4.0
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka:
image: confluentinc/cp-kafka:7.4.0
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
然后执行:
docker-compose up -d
嗯,这里要注意:KAFKA_ADVERTISED_LISTENERS 这个配置,如果你是在容器内访问,要改成容器内地址。我曾经因为没改这个,折腾了半小时连不上。
4.2.2 配置 Spark 与 Delta Lake
Spark 这边,需要把 Delta Lake 的 jar 包加进去。有两种方式:
- 启动时指定(推荐开发用)
- 放到 Spark 的 jars 目录(生产环境用)
启动命令示例:
spark-shell \
--packages io.delta:delta-core_2.12:2.3.0 \
--conf "spark.sql.extensions=io.delta.sql.DeltaSparkSessionExtension" \
--conf "spark.sql.catalog.spark_catalog=org.apache.spark.sql.delta.catalog.DeltaCatalog"
--conf "spark.sql.adaptive.enabled=false",Delta Lake 在某些场景下和自适应查询有冲突。
4.3 常用配置项详解
配置项这东西,说白了就是「调优」。我刚开始做实时写入时,默认配置跑起来,延迟高得吓人。后来一点点调,才找到感觉。
4.3.1 Delta Lake 核心配置
| 配置项 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
spark.databricks.delta.retentionDurationCheck.enabled |
true | false | 开发环境关掉,避免频繁报错 |
spark.databricks.delta.autoCompact.enabled |
false | true | 自动合并小文件,写入频繁时建议开启 |
spark.databricks.delta.optimizeWrite.enabled |
false | true | 优化写入布局,减少小文件 |
spark.sql.adaptive.coalescePartitions.enabled |
true | false | 与 Delta 合并操作冲突时关闭 |
4.3.2 Kafka 生产者配置
实时写入 Kafka,生产者配置是关键。我一般这样配:
# 核心配置
bootstrap.servers=localhost:9092
acks=all
retries=3
batch.size=16384
linger.ms=10
buffer.memory=33554432
key.serializer=org.apache.kafka.common.serialization.StringSerializer
value.serializer=org.apache.kafka.common.serialization.StringSerializer
为什么 acks=all?因为实时写入不能丢数据。虽然延迟会高一点,但数据一致性更重要。你想想看,如果丢了数据,后面查起来多麻烦。
4.3.3 Spark Streaming 与 Kafka 集成配置
用 Structured Streaming 读 Kafka 时,这些配置要记住:
val kafkaParams = Map(
"kafka.bootstrap.servers" -> "localhost:9092",
"subscribe" -> "delta-topic",
"startingOffsets" -> "latest",
"maxOffsetsPerTrigger" -> "1000",
"failOnDataLoss" -> "false"
)
failOnDataLoss 建议设为 false。为什么?因为 Kafka 日志清理策略可能导致 offset 丢失,设为 true 的话,作业会直接挂掉。我曾经在生产环境吃过这个亏,凌晨三点被电话叫醒……
4.4 整体架构图
下面这张图,把整个环境的关系画清楚了。你看一眼,心里就有数了:
4.5 验证环境是否正常
环境搭好了,怎么知道能不能用?我一般跑两个测试:
4.5.1 测试 Delta Lake 写入
// 创建 Delta 表并写入数据
val data = spark.range(0, 100).toDF("id")
data.write.format("delta").mode("append").save("/tmp/delta-test")
// 读取验证
val df = spark.read.format("delta").load("/tmp/delta-test")
df.show()
如果能看到 0 到 99 的数据,说明 Delta Lake 没问题。
4.5.2 测试 Kafka 连通性
# 创建测试 topic
kafka-topics --bootstrap-server localhost:9092 --create --topic test-topic --partitions 3 --replication-factor 1
# 生产消息
echo "hello delta" | kafka-console-producer --bootstrap-server localhost:9092 --topic test-topic
# 消费消息
kafka-console-consumer --bootstrap-server localhost:9092 --topic test-topic --from-beginning
KAFKA_ADVERTISED_LISTENERS 配置,这是最常见的坑。
4.6 常见问题与避坑
最后,分享几个我实际踩过的坑:
- Delta Lake 版本与 Spark 不匹配:Delta 2.x 必须用 Spark 3.x,Delta 1.x 才支持 Spark 2.4。我见过有人用 Delta 2.0 配 Spark 2.4,编译都过不了。
- Kafka 连接超时:检查防火墙和
advertised.listeners。我曾经在云服务器上部署,忘了配安全组规则,结果一直连不上。 - Delta 表路径权限:Spark 写 Delta 表时,需要读写权限。如果用的是 HDFS,记得检查目录权限。
- OOM 问题:如果数据量大,记得调大
spark.executor.memory和spark.driver.memory。默认 1G 肯定不够。
环境搭好了,后面的事情就顺了。记住,版本匹配是第一位的,配置调优是第二位的。别急着跑大任务,先把小测试跑通。