4. 配置Cromwell的数据库(H2/MySQL)
数据库配置,说白了就是给Cromwell找个“记事本”。
工作流跑到哪一步了?中间结果存哪了?这些都是靠数据库来记录的。我刚开始碰Cromwell的时候觉得这步无所谓,直接拿默认配置跑。结果工作流一中断,啥都找不回来。
嗯,从那以后我再也不敢跳过数据库配置了。
4.1 数据库到底管什么?
Cromwell自己不会“记住”任何东西。每一次任务调度、每一个输出路径,它都要往数据库里写一笔。万一数据库挂了,整个引擎就等于失忆。
我个人习惯把数据库分成两套场景,通俗点讲就是:
- H2(开发/尝鲜):本地文件型数据库,开箱即用,擦桌子就能跑。
- MySQL(生产/多人协作):独立服务,稳定、可控,适合团队或云端环境。
下面这张图可以帮你快速理清不同阶段该选哪个:
4.2 先聊聊 H2(开箱即用版)
Cromwell 默认就带 H2。你下载完 jar 包直接跑,它会在当前目录生成一个 cromwell.db 文件。
说实话,H2 对于练手和测试完全够用。
但这里有个坑:H2 是单机文件锁。如果你同时起了两个 Cromwell 进程指向同一个 .db 文件,后一个直接报错退出。我曾经在本地调试时,忘了关掉前一个窗口,又开了一个终端,结果浪费了十几分钟排查锁文件。
H2 的配置超级简单,在 cromwell.conf 里这样写:
database {
profile = "slick.jdbc.HsqldbProfile$"
db {
driver = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:file:${CROMWELL_ROOT}/cromwell.db;shutdown=false;hsqldb.tx=MVCC"
connectionTimeout = 5000
}
}
# 如果使用 H2,默认配置是这样:
database {
profile = "slick.jdbc.H2Profile$"
db {
driver = "org.h2.Driver"
url = "jdbc:h2:file:${CROMWELL_ROOT}/cromwell.db;MVCC=true;LOCK_TIMEOUT=10000"
connectionTimeout = 5000
}
}
LOCK_TIMEOUT 酌情调高到 10 秒以上。任务多了,H2 偶尔会锁住等一会儿才能释放。
4.3 切换到 MySQL(生产级配置)
一旦你的工作流开始变多,或者要跟别人共享 Cromwell 实例,H2 就不太稳了。我建议直接上 MySQL。
你想想看,H2 只是一个文件,万一磁盘满了或者文件损坏,所有正在跑的任务就全断了。MySQL 起码有主从、有备份、有事务回滚。
先得把 MySQL 服务准备好。我个人习惯用 Docker 来起一个测试用的 MySQL 实例,省得污染本地环境:
docker run --name cromwell-mysql \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=cromwell \
-e MYSQL_USER=cromwell \
-e MYSQL_PASSWORD=cromwell \
-p 3306:3306 \
-d mysql:8.0
然后修改 cromwell.conf,指向 MySQL:
database {
profile = "slick.jdbc.MySQLProfile$"
db {
driver = "com.mysql.cj.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/cromwell?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"
user = "cromwell"
password = "cromwell"
connectionTimeout = 5000
numConnections = 10
maxConnectionAge = 30 minutes
}
}
这里有几个参数我想重点说一下:
| 参数 | 说明 | 个人建议值 |
|---|---|---|
numConnections |
连接池大小。撑不满会报连接耗尽。 | 10 ~ 20(看并发量) |
maxConnectionAge |
连接最大存活时间。MySQL 8.0 默认 8 小时断开空闲连接。 | 30 分钟或 1 小时 |
connectionTimeout |
等待连接的超时时间(毫秒)。 | 5000(5秒够了) |
useSSL=false |
本地/内网可以不加密,省掉证书配置。 | 内网 false,公网必须 true |
配置好之后,启动 Cromwell 时会自动建表。我第一次切 MySQL 的时候,启动日志里看到一堆 CREATE TABLE 语句飞过,心里还挺踏实。
不过,如果你之前用过 H2,旧的元数据是不会自动迁移到 MySQL 的。你得手动搞一下,或者干脆接受“老任务记录丢失”,直接从新环境开始。
cromwell.conf 文件可以保留两份配置,通过环境变量切换。我经常这么干,省得来回改文件。
4.4 MySQL 连接中容易踩的坑
反正我遇到的坑,十有八九出在连接驱动和时区上。给你列几个常见问题:
- 驱动找不到:Cromwell 启动时如果报
ClassNotFoundException: com.mysql.cj.jdbc.Driver,代表你依赖没加全。用 Docker 镜像的话,得自己把 mysql-connector-java 的 jar 包放进 Cromwell 的 lib 目录下。 - 时区不对:MySQL 默认用系统时区。如果你服务器是 UTC,Cromwell 跑出来的时间戳就会差 8 小时。建议在 JDBC URL 里加
serverTimezone=UTC或Asia/Shanghai,保持两端一致。 - 连接数超限:并发一大,MySQL 报
Too many connections。我的经验是先把max_connections调到 200 以上,再配合 Cromwell 的连接池上限调整。
numConnections 设成了 100,但 MySQL 端的 max_connections 默认只有 151。高并发时 Cromwell 直接连不上去报 Connection refused。查了半天才发现是 MySQL 自己的连接上限被封了。
4.5 快速验证数据库是否生效
配置改完了,怎么知道 Cromwell 真的在用 MySQL 而不是 H2?
有一个最简单的办法:
# 启动 Cromwell
java -jar cromwell.jar server
# 观察启动日志
# 如果看到类似下面的内容,说明数据库配置加载了
[info] CromwellDatabase - Connecting to database with profile: slick.jdbc.MySQLProfile$
[info] CromwellDatabase - Database connection established successfully
# 然后进 MySQL 查表
mysql -u cromwell -p -h localhost cromwell
mysql> SHOW TABLES;
# 如果看到 WORKFLOW_METADATA_ENTRY、JOB_STORE 等系统表,就对了
如果启动后还是老样子,先检查 cromwell.conf 文件路径对不对。Cromwell 默认从当前目录加载这个文件。你可以通过 -Dconfig.file=/path/to/your/cromwell.conf 强制指定。
说白了,数据库配置就是 Cromwell 的“记忆体”。选 H2 还是 MySQL,不是靠感觉,而是看你项目到什么阶段了。我个人经验是: MVP 阶段 H2 完全够用,一旦要上协作、上生产,直接切 MySQL 别犹豫。