2. Nextflow 基础入门:安装、核心概念与第一个示例

好,咱们正式开始动手。这一章,我会带你从零把 Nextflow 跑起来,顺便把它的三个核心家伙——进程(Process)、通道(Channel) 和 工作流(Workflow)——彻底搞明白。

我记得刚开始接触 Nextflow 时,第一反应是“这又是个要折腾半天的工具”。但跑完第一个示例后,我发现它比想象中清爽很多。咱们一步步来。

2.1 安装 Nextflow

安装之前,先确认你的机器上有没有 Java。Nextflow 是基于 JVM 的,没有 Java 寸步难行。

前置检查: 在终端里敲 java -version,看看是不是 Java 8 或更高版本(Java 11 或 17 更稳)。如果你的服务器是 CentOS 或 Ubuntu,一般自带 OpenJDK。

我个人习惯用 curl 直接装,干净利落:

curl -s https://get.nextflow.io | bash

这条命令会下载一个 nextflow 的可执行文件。然后把它放到 PATH 里:

chmod +x nextflow
sudo mv nextflow /usr/local/bin/

验证安装很简单:

nextflow -version

看到版本号就说明成了。我在一个内部服务器上装过,结果因为代理没配好,下载卡了半小时。如果你在公司网络环境,记得先配好 HTTP_PROXY 和 HTTPS_PROXY 环境变量。

安装方式 适用场景 注意事项
curl 官方脚本 个人开发、首次使用 需要外网访问 GitHub
conda 安装 已有 conda 环境的用户 版本可能滞后小版本
Docker 容器 生产环境、集群部署 需额外挂载数据卷

2.2 核心概念:进程、通道、工作流

这三个概念是 Nextflow 的基石。说实话,你只要理解了它们,后面学起来就会很顺。

进程(Process)

进程就是执行任务的最小单元。每个进程可以做一件事,比如:比对、定量、质控。它接收输入,执行一段脚本,然后产生输出。

举个例子,一个简单的 sayHello 进程:

process sayHello {
    input:
        val x

    output:
        stdout

    script:
    """
    echo "Hello, $x!"
    """
}

这里 input 和 output 定义了数据接口,script 里是实际要运行的命令。

通道(Channel)

通道是数据的管道,负责把数据从一个进程传到另一个进程。你可以把它想象成一个队列——数据在里面流,进程从里面读。

创建通道的方式有好几种,最常用的是 fromPath 从文件列表创建,或者 of 从值列表创建:

ch_sample = Channel.fromPath("data/*.fastq.gz")
ch_names  = Channel.of("sample_A", "sample_B", "sample_C")

我在项目中遇到过一个坑:直接把通道传给了不支持“多输入”的进程,结果进程只跑了一次。后来才发现通道需要用 .combine 或 .join 合并一下。

工作流(Workflow)

工作流把进程和通道串起来,定义执行顺序。它本身也是一个函数式的块:

workflow {
    sayHello(Channel.of("Alice", "Bob", "Charlie"))
}

运行这个工作流,每个名字都会触发一次 sayHello 进程。

三者的关系: 通道是“水源”,进程是“水龙头”,工作流是“水管工”,负责把水源接对龙头,让水流对方向。
Nextflow 三大金刚:数据流向 通道 Channel 进程 Process 工作流 Workflow 输入 输出 结果通道 汇总 通道驱动数据流动,进程执行具体任务,工作流编排整体顺序。 三者分离,让每个环节都可独立测试和替换。

2.3 运行第一个示例

空谈没用,咱们跑个真实的例子。创建一个文件,名字叫 hello.nf:

#!/usr/bin/env nextflow

params.greeting = "Hello"
params.names    = ["Alice", "Bob", "Charlie"]

process greet {
    input:
        val name

    output:
        stdout

    script:
    """
    echo "${params.greeting}, $name!"
    """
}

workflow {
    greet(Channel.of(params.names))
}

保存后,用一行命令启动:

nextflow run hello.nf

正常情况下你会看到类似这样的输出:

N E X T F L O W  ~  version 23.10.0
Launching `hello.nf` [angry_pasteur] DSL2 - revision: a1b2c3d4e5
executor >  local (3)
[6f/2a1b3c] process > greet (1) [100%] 1 of 1 ✔
[c4/8d5e6f] process > greet (2) [100%] 2 of 2 ✔
[ab/12cd34] process > greet (3) [100%] 3 of 3 ✔

每个 greet (1) 都是一个进程执行实例,后面的数字表示第几个。日志里的 16 进制字符串是任务的工作目录,你可以进去看中间文件。

注意: 如果你在 macOS 上用 echo,注意 echo 默认不加换行;不过这里加了双引号,没问题。另外,如果集群上没有 bash,记得在 script 块里指定 shebang 或用 shell 指令。

想换个问候语?直接改参数,不用动代码:

nextflow run hello.nf --greeting "你好"

输出就会变成中文。这就是 Nextflow 的参数化设计——抽离配置,保留逻辑,我跟你说,这在多项目切换时特别管用。

2.4 快速检查你的 Nextflow 环境

我建议你在跑正式分析前,做一次快速“体检”:

  1. 检查 Java 版本是否符合要求
  2. 确认 nextflow 命令在哪个路径
  3. 运行一次 nextflow info 看看配置文件位置
  4. 创建一个临时目录,跑上面的 hello.nf
  5. 查看 work/ 目录下是否生成了日志

如果你是为了做 RNA-seq 审计追踪,后面我们还会给每个步骤加上时间戳和参数快照。但在这之前,先把基础跑通。

一个小经验: 我习惯在项目根目录下建一个 env.sh,把 Nextflow 版本和 PATH 固定下来。团队合作时,谁都不会因为本地版本不同而出问题。