Slurm环境下运行PCJ Java并行应用遇StartPoint未执行问题求助
在Slurm集群中运行PCJ Java并行应用的问题与解决方案
问题背景
在采用Slurm作为资源管理器的集群环境中运行基于PCJ的Java并行计算应用时,存在sbatch脚本、srun参数与Java代码的协调问题,PCJ自行启动从节点任务的逻辑可能与Slurm的启动流程冲突。提交指定2个从节点的sbatch脚本后,发现StartPoint接口的main()方法未执行,现提供基础可行示例及问题解决方法。
现有配置与输出
sbatch脚本
#!/bin/bash #SBATCH -N 2 # 节点数量 #SBATCH --ntasks-per-node 1 # 每个节点的任务数 #SBATCH --time=00:10:00 # 运行时长限制 srun -l java -jar test-pcj-slurm-0.0.1-SNAPSHOT.jar
Java代码
public class PcjSlurm implements StartPoint { public static void main( String[] args ) { String[] nodes = getStepNodes(); System.out.println( "node name " + getNodeName() ); if ( getNodeName().equals( "slave2" ) ) { PCJ.executionBuilder( PcjSlurm.class ).addNodes( nodes ).start(); } else System.out.println( "slave job" ); } private static String[] getStepNodes() // 返回 ["slave1", "slave2"] { return System.getenv( "SLURM_STEP_NODELIST" ).split( "," ); } private static String getNodeName() { return System.getenv( "SLURMD_NODENAME" ); } // StartPoint 接口实现 @Override public void main() throws Throwable { System.out.println( "PCJ id " + PCJ.myId() ); } }
运行输出(slurm-XXX.out)
1: node name slave1 1: slave job 0: node name slave2 0: 2024年3月4日 上午10:08:36 org.pcj.internal.InternalPCJ start 0: INFOS: PCJ version UNKNOWN
问题分析
- 启动流程冲突:Slurm的
srun已在所有分配节点启动Java进程,代码中又调用PCJ.executionBuilder().addNodes(nodes).start()让PCJ重复启动从节点进程,导致PCJ的主从机制无法正常初始化,StartPoint的main()无法执行。 - 节点逻辑错误:仅指定
slave2节点启动PCJ,未与Slurm分配的任务节点对齐,导致其他节点的进程仅执行了普通分支代码,未进入PCJ并行逻辑。
修正后的可行方案
方案1:复用Slurm启动的进程(推荐)
让PCJ直接使用Slurm通过srun启动的所有进程,无需手动启动从节点,通过系统参数传递集群配置。
修正后的sbatch脚本
#!/bin/bash #SBATCH -N 2 # 节点数量 #SBATCH --ntasks-per-node 1 # 每个节点的任务数 #SBATCH --time=00:10:00 # 运行时长限制 # 传递Slurm分配的节点列表给PCJ,指定主节点为第一个分配节点 srun -l java -Dpcj.nodes=$SLURM_STEP_NODELIST -Dpcj.master.node=$(scontrol show hostnames $SLURM_NODELIST | head -n1) -jar test-pcj-slurm-0.0.1-SNAPSHOT.jar
修正后的Java代码
import org.pcj.StartPoint; import org.pcj.PCJ; public class PcjSlurm implements StartPoint { public static void main( String[] args ) { // 直接初始化PCJ,使用系统参数传递的集群配置 PCJ.executionBuilder(PcjSlurm.class).start(); } @Override public void main() throws Throwable { System.out.println("节点: " + System.getenv("SLURMD_NODENAME") + " | PCJ id: " + PCJ.myId()); } }
方案2:仅主节点启动PCJ,由PCJ管理从节点
若需让PCJ自行启动从节点,需修改脚本仅在主节点运行Java进程,避免与Slurm的多进程启动逻辑冲突(需提前配置节点间免密SSH)。
修正后的sbatch脚本
#!/bin/bash #SBATCH -N 2 # 节点数量 #SBATCH --ntasks-per-node 1 # 每个节点的任务数 #SBATCH --time=00:10:00 # 运行时长限制 # 仅在Slurm分配的第一个主节点执行Java程序 MASTER_NODE=$(scontrol show hostnames $SLURM_NODELIST | head -n1) if [ "$SLURMD_NODENAME" = "$MASTER_NODE" ]; then java -jar test-pcj-slurm-0.0.1-SNAPSHOT.jar fi
修正后的Java代码
import org.pcj.StartPoint; import org.pcj.PCJ; public class PcjSlurm implements StartPoint { public static void main( String[] args ) { String[] nodes = System.getenv("SLURM_NODELIST").split(","); System.out.println("主节点: " + System.getenv("SLURMD_NODENAME")); // 启动PCJ并指定所有分配节点 PCJ.executionBuilder(PcjSlurm.class).addNodes(nodes).start(); } @Override public void main() throws Throwable { System.out.println("PCJ id " + PCJ.myId() + " 运行在节点: " + System.getenv("SLURMD_NODENAME")); } }
验证说明
- 方案1中,Slurm的
srun会在每个分配节点启动一个Java进程,PCJ通过系统参数自动识别集群节点,StartPoint的main()会在所有节点上执行并行逻辑。 - 方案2中,仅主节点启动Java进程,PCJ会通过SSH在其他节点启动从节点进程,适合需要自定义从节点启动逻辑的场景。
内容的提问来源于stack exchange,提问作者Fanfoue
相关产品推荐
相关产品推荐

