Cromwell架构与组件归纳总结
刚接触Cromwell的时候,你可能觉得它就是个“跑工作流的黑盒子”。把WDL丢进去,出来结果就完事了?其实没那么简单。Cromwell内部拆得很清楚——每个组件各管一摊事,合起来才撑得起混合云这种跨平台的场景。
我个人习惯先从架构图入手,脑子里有了整体轮廓,再去看配置和代码就不会晕。下面这张图是我自己整理的Cromwell核心组件关系,你先扫一眼,后面咱们一个一个拆。
1. Cromwell Server——大脑
Cromwell Server是整个系统的调度核心。你通过HTTP API提交工作流描述(WDL或CWL),Server负责解析、拆解成一个个task,然后分发给后端执行。
我刚开始用的时候老觉得Server就是单点,万一挂了怎么办?其实Cromwell Server本身是无状态的,真正的状态全在Database里。你想想看,只要数据库不丢,换个Server实例一样能恢复所有工作流。
/engine/v1/status 端点,5秒探活一次。
2. Database——一切状态的归宿
Cromwell支持MySQL、PostgreSQL、H2(仅测试用)。工作流进度、输入输出、元数据、call cache索引……全存里面。
| 数据库类型 | 生产推荐 | 我踩过的坑 |
|---|---|---|
| MySQL 8.0+ | 推荐,支持事务 | 连接数设大些,默认150不够用 |
| PostgreSQL 13+ | 同样推荐 | 注意时区配置,否则时间戳对不上 |
| H2 | 仅开发测试 | 重启即丢数据,别问我是怎么知道的 |
我建议混合云场景下把数据库放在公网可达的云服务上(比如阿里云RDS、AWS RDS),这样不管Server跑在本地还是云上,都能连到同一个库——实现真正的状态共享。
3. Backend——干活的人
Backend是真正运行计算的地方。Cromwell内置了Local、HPC(PBS/LSF/Slurm)、Spark、Google Cloud、AWS Batch等。混合云迁移的核心就是配置多个Backend,让Server根据标签或资源需求动态选择合适的平台。
举个例子:
# application.conf 片段
backend {
providers {
local {
actor-factory = "cromwell.backend.impl.sfs.config.ConfigBackendLifecycleActorFactory"
config {
# 本地运行,适合小任务
}
}
gcp {
actor-factory = "cromwell.backend.impl.sfs.config.ConfigBackendLifecycleActorFactory"
config {
# 指向Google Life Sciences API
project = "my-project"
location = "us-central1"
}
}
}
}
4. Job Manager与Metadata Store
Job Manager负责与具体后端交互,比如提交任务、轮询状态、拉日志。Metadata Store记录工作流的每一步发生了什么——输入、输出、标准错误、执行时间等等。混合云场景下,Metadata Store特别有用,你可以通过它对比不同后端的执行效率,决定哪些任务丢到云上更划算。
我一般在工作流跑完后,直接查询Metadata API抓取数据:
GET /api/workflows/v1/{id}/metadata?expandSubWorkflows=true
返回的JSON里能看到每个task的start、end、executionStatus、stdout、stderr等字段。
5. Call Cache——别再算第二遍
Call Cache是Cromwell一个特别实用的特性。同输入同命令的任务,在Cache表中查得到结果就直接复用,不重新跑。混合云迁移时这个功能尤其重要:你在本地跑过一遍的任务,切到云上再跑,只要工作流定义不变、输入哈希一致,Cloud端直接拿结果,省时省力。
不过要注意,Cache默认只比较输入文件和命令,如果依赖了外部环境变量或镜像版本,最好显式声明runtime { docker: "…" },否则可能复用错误的结果。我记得有次迁移后一批样本的质控结果和前一天一模一样,后来发现是Cache把旧结果喂给了我——参数没变,但镜像已经更新了,差点造成事故。
call-cache-dir 为不同路径,避免跨环境串数据。
6. 组件间如何协作——一个简化的流程
- 用户通过REST API提交工作流描述(WDL/CWL)和输入。
- Server解析工作流,拆解成任务图,存入Database。
- Server把可执行任务交给Job Manager,Job Manager根据任务标签选择对应的Backend。
- Backend在目标环境(本地、集群或云)启动计算,实时更新状态回Database。
- 每个任务执行完毕,Metadata Store记录完整的执行信息。
- 如果开启Call Cache,Server在提交任务前先查Cache表,匹配则跳过执行,直接输出。
说白了,整个架构就是“Server管事,DB记账,Backend干活”。混合云部署要关注的就是让多个Backend能共享同一个Database和Metadata Store。
7. 部署时的配置要点
我通常把配置拆成三个文件:
cromwell.conf—— 全局设置(端口、并发、日志级别)database.conf—— 数据库连接backends.conf—— 各后端参数
然后在启动时通过 java -Dconfig.file=/path/to/cromwell.conf … 加载。这样以后改某个后端配置,只改一个文件,不会乱。
filesystems 和 docker 配置,因为本地和云上的文件路径习惯完全不同。有一次我把云上的共享存储路径写成了本地绝对路径,任务全挂了。