2、开发环境搭建:JDK、Maven、Git、Docker、IDE配置、本地集群模拟
说实话,搭建开发环境这件事,很多新手觉得不值一提。但我在带团队时发现,环境不一致导致的问题,往往比业务逻辑bug更难排查。你想想看,一个推荐系统涉及实时流处理、离线训练、模型服务,每个组件都有自己的依赖版本。版本一乱,整个平台就崩了。
这一章,我带你把环境一次性搭好。咱们的目标是:任何一台新机器,照着这份指南,半小时内就能开始写代码。
核心原则:所有工具版本统一,路径规范,避免使用系统自带的旧版本。
2.1 JDK:选对版本,省一半的坑
实时推荐平台的核心组件——Kafka、Flink、HBase——都依赖Java。我个人习惯用JDK 8,虽然JDK 11和17已经普及,但很多大数据框架对JDK 8的支持最稳定。
我曾经在项目里试过用JDK 11跑Flink 1.13,结果遇到序列化兼容问题,排查了两天才发现是JDK版本导致的。从那以后,我老老实实回归JDK 8。
安装步骤
- 下载JDK 8u202(这是Oracle JDK 8的最后一个免费商用版本)
- 解压到
/usr/local/java/jdk1.8.0_202 - 配置环境变量
# 编辑 ~/.bashrc 或 ~/.zshrc
export JAVA_HOME=/usr/local/java/jdk1.8.0_202
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# 验证
java -version
# 输出应为:java version "1.8.0_202"
避坑指南:不要用系统包管理器(apt/yum)安装的OpenJDK,版本太旧。我曾经在Ubuntu上直接 apt install default-jdk,结果装了个1.8.0_252,和Flink的某些特性不兼容。
2.2 Maven:统一依赖管理
推荐平台依赖的第三方库少说也有几十个。Maven能帮你管理版本冲突,避免「在我机器上能跑」的尴尬。
我建议用Maven 3.6.3,这个版本稳定,兼容性好。3.8.x开始对镜像仓库有更严格的校验,容易导致私服配置失败。
配置要点
- 解压到
/usr/local/maven/apache-maven-3.6.3 - 配置环境变量
export MAVEN_HOME=...; export PATH=$MAVEN_HOME/bin:$PATH - 修改
conf/settings.xml,添加阿里云镜像
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
注意:国内网络环境下,不配镜像的话,第一次构建可能要等半小时。我见过同事等得怀疑人生,结果发现是Maven在下载依赖时超时了。
2.3 Git:版本控制与分支策略
推荐平台的代码通常分多个模块:数据接入、特征工程、模型训练、API服务。Git的分支管理直接影响团队协作效率。
我个人习惯用Git 2.30+,这个版本对 main 分支的默认命名支持更好。
分支策略建议
| 分支 | 用途 | 说明 |
|---|---|---|
main |
生产就绪代码 | 只允许从 release 分支合并 |
develop |
日常开发集成 | 所有 feature 分支合并到这里 |
feature/* |
新功能开发 | 命名如 feature/real-time-recall |
release/* |
发布前测试 | 只修bug,不加新功能 |
hotfix/* |
紧急修复 | 直接从 main 拉出,修复后合并回 main 和 develop |
我的经验:在 .gitignore 里一定要加上 target/、*.log、.idea/、*.iml。我曾经看到有人把编译产物提交到仓库,导致仓库体积膨胀到2GB,clone一次要10分钟。
2.4 Docker:环境一致性的终极方案
实时推荐平台依赖的中间件很多:Kafka、ZooKeeper、Redis、MySQL。如果每台机器都手动安装,配置差异会让你崩溃。
Docker能保证开发、测试、生产环境完全一致。我建议用Docker 20.10+,配合 docker-compose 一键启动所有依赖。
安装Docker
# Ubuntu
sudo apt update
sudo apt install docker.io docker-compose
# 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 将当前用户加入docker组(避免每次sudo)
sudo usermod -aG docker $USER
# 重新登录后生效
注意:将用户加入docker组相当于赋予root权限,生产环境不要这样做。但开发环境为了方便,我一般都这么配。
docker-compose 示例
在项目根目录创建 docker-compose.yml:
version: '3.8'
services:
zookeeper:
image: wurstmeister/zookeeper:3.4.6
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka:2.13-2.8.1
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_HOST_NAME: localhost
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_CREATE_TOPICS: "click-stream:3:1,rec-result:3:1"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
redis:
image: redis:6.2
ports:
- "6379:6379"
mysql:
image: mysql:5.7
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: rec_platform
启动命令:docker-compose up -d,所有中间件就都跑起来了。
2.5 IDE配置:IntelliJ IDEA 调优
我主力用IntelliJ IDEA,社区版就够用。但有几个配置必须调,不然开发体验会很差。
必装插件
- Lombok:减少样板代码,推荐平台的数据模型类特别多
- Maven Helper:可视化依赖树,排查冲突神器
- GitToolBox:在代码行尾显示最后提交信息,方便追责(开玩笑的)
- Rainbow Brackets:多层括号用不同颜色区分,写Flink的链式调用时特别有用
JVM参数调优
推荐平台的项目通常很大,IDEA默认的堆内存不够。修改 Help > Edit Custom VM Options:
-Xms2048m
-Xmx4096m
-XX:ReservedCodeCacheSize=512m
-XX:+UseG1GC
我的习惯:把 Build, Execution, Deployment > Build Tools > Maven > Runner 里的 Delegate IDE build/run actions to Maven 勾上。这样构建行为完全由Maven控制,避免IDEA和Maven的构建结果不一致。
2.6 本地集群模拟:用Docker搭一套迷你集群
实时推荐平台的核心是流处理。你不可能每次调试都连生产集群。我习惯在本地用Docker模拟一套迷你集群,包含Kafka、Flink、Redis、MySQL。
下面这张图展示了本地集群的架构:
启动集群
# 一键启动所有服务
docker-compose up -d
# 查看状态
docker-compose ps
# 验证Kafka
docker exec -it rec-platform_kafka_1 kafka-topics.sh --list --bootstrap-server localhost:9092
# 应该看到 click-stream 和 rec-result 两个topic
我的经验:第一次启动时,Kafka和ZooKeeper的启动顺序很重要。docker-compose虽然配置了 depends_on,但ZooKeeper完全就绪需要几秒钟。我习惯在启动后等5秒再操作Kafka,或者加一个健康检查脚本。
2.7 验证环境:跑一个Hello World
环境搭好了,咱们跑一个最简单的Flink程序验证一下:
import org.apache.flink.streaming.api.scala._
object HelloFlink {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
val stream = env.socketTextStream("localhost", 9999)
stream
.flatMap(_.split(" "))
.map((_, 1))
.keyBy(0)
.sum(1)
.print()
env.execute("Hello Flink")
}
}
启动后,在另一个终端执行 nc -lk 9999,输入一些单词,看控制台是否输出词频统计结果。能跑通,说明环境没问题。
注意:如果报错 java.lang.NoClassDefFoundError: scala/Product,说明Flink和Scala版本不匹配。Flink 1.13对应Scala 2.12,检查pom.xml里的scala.version是不是2.12。
好了,环境搭完了。你可能会觉得步骤有点多,但相信我——这一章花的时间,会在后续开发中十倍地省回来。环境一致了,bug就少了一半。接下来,咱们就可以真正开始写推荐系统的代码了。