Multi-Node LLM Training on Slurm: sbatch to Production

HS
Hemant Singh Tanwar

Product @ E2E Networks

15 min read
Share this article
Link copied to clipboard

Multi-node LLM training on Slurm means running one training job across several GPU servers at once. Slurm decides which servers to use and starts the work on all of them together. You describe the job in a short script, submit it with the sbatch command, and Slurm handles the rest.

Getting a job to start is the easy part. A run that can go on for days without losing work needs four more things: shared storage, a tested network between servers, regular checkpoints, and a way to catch failing hardware early. This post walks through each step in plain language, from your first script to a run you can trust.

Why does LLM training need more than one GPU server?

Bigger LLMs do not fit on one server, and even smaller ones can take too long to train there.

Training needs far more memory than the model itself. Besides the model's weights, the GPUs must also hold gradients and optimizer state. With the usual mixed-precision setup and the Adam optimizer, that comes to about 16 bytes per parameter. That is before counting the working data for each batch.

So a 7-billion-parameter model needs roughly 112 GB just for this. A 70-billion-parameter model needs about 1.1 TB. A typical GPU server has 8 GPUs, and eight 80 GB GPUs give you 640 GB in total. The bigger model does not fit.

Splitting the work across servers solves both problems. Each server holds a share of the model or the data, and all the GPUs work in parallel. The catch is that they must stay in sync, swapping results after every training step. That is why the network between servers, and the software that coordinates them, matter so much.

What is Slurm?

Slurm is free, open-source software that shares a group of computers among many users and jobs. It is widely used to schedule work on supercomputers and GPU clusters. By NVIDIA's own account, Slurm runs on more than half of the top 10 and top 100 systems in the TOP500 list of the world's fastest supercomputers.

Think of Slurm as the host at a busy restaurant. You tell the host how many seats you need and for how long. The host keeps a waiting list, seats your whole group together when enough tables are free, and clears the tables when you leave. Slurm does the same with GPUs. You ask for, say, 4 servers with 8 GPUs each for 24 hours, and Slurm starts your job only when all 32 GPUs are free at the same time.

That last part matters for training. A distributed job cannot start on half its GPUs and wait for the rest. Slurm starts every part together, or not at all.

Slurm is developed by SchedMD. NVIDIA acquired SchedMD in December 2025 and has said Slurm will stay open source and vendor-neutral.

Slurm terms you will see

TermWhat it means
NodeOne server in the cluster. In a training cluster, a worker node usually has 8 GPUs.
JobA piece of work you ask Slurm to run, such as a training run.
PartitionA named queue that covers a set of nodes, with its own rules such as time limits.
sbatchSubmits a job script to the queue. You get your terminal back straight away.
srunStarts a program on the nodes Slurm gave you. Inside a job script, it launches training on every node.
squeueShows the queue: which jobs are running and which are waiting.
sinfoShows the nodes and whether each is free, busy or out of service.

What does a Slurm training cluster look like?

A Slurm training cluster has five parts: a login node where you work, a controller that makes decisions, GPU worker nodes that do the training, a fast network between them, and storage that every node shares.

  • Login node. You connect here over SSH to edit scripts and submit jobs. It is not meant for training. Heavy work here does not use the GPUs and can slow the node down for everyone.
  • Controller. Runs the Slurm scheduler. It holds the queue, decides which job runs where, and keeps a history of past jobs.
  • Worker nodes. The GPU servers that run your training. Slurm hands them out to jobs.
  • Network fabric. A fast, low-delay network between workers, usually InfiniBand with RDMA. It lets GPUs on different servers swap data quickly, which multi-node training depends on.
  • Shared storage. A file system mounted at the same path on the login node and every worker, so all nodes see the same code, data and checkpoints.

Diagram of a Slurm training cluster. You connect to the login node over SSH to edit scripts and submit jobs, and sbatch sends the job to the controller, which holds the queue, picks the nodes and starts the job on every one of them. Four GPU worker nodes of 8 GPUs each are joined by an RDMA InfiniBand network on which the GPUs swap results after every step. Shared storage, holding code, data, container images, checkpoints and logs, is mounted at the same path on the login node and every worker.

Slurm training cluster: login node, controller, four GPU workers and shared storage.

The login node and every worker see the same shared storage, and the RDMA network links the workers to each other.

From sbatch to first run: how a multi-node job works

A multi-node training job goes from a text file to 32 working GPUs in seven steps. The example below uses 4 nodes with 8 GPUs each.

  1. Connect to the login node. You SSH in. This is where you prepare and submit everything.
  2. Put your files on shared storage. Your code, dataset, container image and an empty checkpoint folder all go on the shared file system, so every node can reach them.
  3. Write a job script. This is a short shell script. The #SBATCH lines at the top tell Slurm what you need: how many nodes, how many GPUs, how long, and where to write logs.
  4. Submit it with sbatch. Slurm puts the job in the queue and gives you a job ID.
  5. Wait for resources. The job stays pending until 4 full nodes are free at once. squeue shows why it is waiting, such as Resources (not enough free GPUs) or Priority (another job is ahead).
  6. Slurm starts the job on every node. srun launches your container on all 4 nodes together. Inside each one, a launcher such as torchrun or DeepSpeed starts one training process per GPU, 32 in total.
  7. The GPUs train together. After each step they share results over the network using NCCL, NVIDIA's library for GPU-to-GPU communication. Logs and checkpoints are written to shared storage as the run goes.

What a job script looks like

Here is a simplified script for the example above. The table after it explains what each part does.

#!/bin/bash #SBATCH --job-name=llm-pretrain #SBATCH --nodes=4 #SBATCH --ntasks-per-node=1 #SBATCH --gpus-per-node=8 #SBATCH --exclusive #SBATCH --mem=0 #SBATCH --time=24:00:00 #SBATCH --output=/pfs/logs/%x-%j.out export MASTER_ADDR=$(scontrol show hostnames "$SLURM_JOB_NODELIST" | head -n 1) export MASTER_PORT=29500 export NCCL_IB_DISABLE=0 export NCCL_NET=IB export NCCL_SOCKET_IFNAME=eth0 # export NCCL_IB_HCA==mlx5_0:1,mlx5_3:1 # pin the exact adapters on your nodes srun --container-image=/pfs/images/pytorch.sqsh \ --container-mounts=/pfs:/pfs,/dev/infiniband:/dev/infiniband \ torchrun --nnodes=$SLURM_NNODES --nproc_per_node=8 \ --rdzv_id=$SLURM_JOB_ID --rdzv_backend=c10d \ --rdzv_endpoint=$MASTER_ADDR:$MASTER_PORT \ /pfs/project/train.py --checkpoint-dir /pfs/checkpoints/run-01 --save-every 500
Part of the scriptWhat it does
--nodes=4Asks for four GPU servers.
--ntasks-per-node=1Starts one copy of the launcher on each server. The launcher then starts one process per GPU.
--gpus-per-node=8Reserves all eight GPUs on each server.
--exclusiveKeeps other jobs off these servers.
--mem=0Gives the job all the memory on each server.
--time=24:00:00Stops the job after 24 hours. Always set a limit, or the job may inherit a partition's unlimited time.
--output=...Writes the log to shared storage. %x becomes the job name and %j the job ID.
MASTER_ADDR, MASTER_PORTPick the first server as the meeting point where all 32 processes find each other at start-up.
NCCL_IB_DISABLE, NCCL_NET, NCCL_SOCKET_IFNAMEKeep GPU-to-GPU traffic on InfiniBand. Without them NCCL can fall back to TCP, which is far slower.
srun --container-imageStarts the same container on every server, so the software is identical everywhere.
--container-mountsMakes shared storage and the InfiniBand devices visible inside the container.
torchrunPyTorch's launcher. It starts 8 training processes per server and connects all 32.
--save-every 500An option of the training script in this example: save a checkpoint every 500 steps.

You submit it with one command, sbatch train.sh. Check on it with squeue -u $USER and follow the log with tail -f.

What makes a run production-ready?

A production-ready run can survive a failed server, a missing file or a slow network without losing much progress. Six habits get you there.

1. Keep everything that matters on shared storage

Each node's local folders, such as /tmp and /dev/shm, are private to that node and get wiped on restart. Anything written inside a container is also thrown away when the job ends, unless that folder is mounted from shared storage. A run can look finished and still have saved nothing.

Put datasets, checkpoints, logs, container images and Python environments on the shared file system. Before a long run, write a test file from one node and read it from all the others.

2. Package your software in a container

Every node must run the same versions of Python, PyTorch, CUDA and NCCL. A container image makes sure of that. Import the image to shared storage once, then point every job at that file. This also stops dozens of nodes from downloading the same image at the same moment.

3. Test the network before the long run

When a multi-node job hangs, it is usually at the very start, while the GPUs are still trying to connect. Run a short NCCL all-reduce benchmark at your full node count before the real run.

Set NCCL_DEBUG=INFO and read the log. NET/IB means traffic is using InfiniBand. NET/Socket means NCCL fell back to ordinary TCP, which is far slower. The usual causes are InfiniBand devices not mounted into the container, wrong network adapter names in NCCL_IB_HCA, or a hard-coded start-up address. Our Megatron-LM benchmark post shows what a correct NCCL log looks like on H200 nodes, including why NCCL_IB_HCA needs a leading equals sign.

4. Save checkpoints often, and make your script resume

A checkpoint is a saved snapshot of the model and optimizer that lets training continue from that point. A well-run cluster keeps going when one server fails, but the job on that server ends. Your progress is only as recent as your last checkpoint.

Save checkpoints to shared storage at a regular interval, for example every 500 steps, and keep the last few. Write your training script so it loads the latest checkpoint when it starts. Then a failed job only needs a restart.

5. Watch GPU health and take bad nodes out early

NVIDIA GPUs report hardware faults as XID errors. One faulty GPU can crash a job that spans 32 of them, sometimes hours in. When a node shows errors, drain it: Slurm lets current jobs finish and sends no new work there. Then reboot or repair it and return it to service.

You can automate part of this with a prolog, a script Slurm runs on each node before a job starts. If the script finds fewer GPUs than expected, it exits with an error and Slurm drains that node.

6. Monitor utilization and set limits

During training, GPU utilization should stay high and roughly even across GPUs. Near-zero utilization usually means the GPUs are waiting on data loading, or the code is running on the CPU. One GPU far below the rest can point to a stuck process.

Set alerts for low utilization and high temperature. Use partitions to keep short interactive jobs away from long training runs, and always set a --time limit.

Pre-flight checklist for a long training run

Run through this list before you start a job that will take hours or days.

  • Code, data, container image and checkpoint folder are on shared storage
  • A test file written on one node can be read on every node
  • A one-node test run shows the right number of GPUs and the right framework versions
  • An NCCL all-reduce test at full scale shows NET/IB, not NET/Socket
  • All nodes are healthy, with no XID errors and none drained
  • The script saves checkpoints regularly and resumes from the latest one
  • --time is set and logs go to shared storage
  • Alerts are on for low GPU utilization and high temperature

Running multi-node training on TIR Training Cluster

TIR Training Cluster, part of E2E Networks' TIR AI platform, gives you a Slurm cluster with the pieces above already in place. It is a standard Slurm installation, so sbatch, srun, squeue and sacct work as described in this post. TIR installs and patches the scheduler for you. Under the hood, it runs on Kubernetes using SchedMD's Slinky project.

What a production run needsWhat TIR Training Cluster provides
Fast links between serversGPU worker nodes connected by an RDMA fabric (InfiniBand) for NCCL traffic
Shared storageParallel File System and Shared File System, mounted at the same path on the login node and every worker
The same software on every nodeContainer jobs through Enroot and Pyxis: add --container-image to srun to run any Docker or OCI image, chosen per job
Catching bad hardwareA Nodes tab with per-GPU utilization, memory, temperature and power, XID error detection, and single-node reboot
MonitoringA job queue, GPU and scheduler charts, and controller and worker logs in the browser, plus alerts
Automatic health checksProlog and epilog scripts for workers and the controller, set from the console
Sharing with a teamUp to 20 custom partitions, per-user SSH logins and private home directories
Growing the clusterAdd worker nodes to a running cluster without disturbing running jobs
AutomationA REST API for every console action

The TIR documentation has a full walkthrough, including a 4-node PyTorch example, NCCL settings and a network test. Start with Submit your first job, then move to Multi-node container training.

One thing to keep in mind: on TIR, a node failure does not take down the controller or the other nodes, but the job on the failed node still ends. Checkpointing stays your job, so the habits in this post apply here as on any Slurm cluster.

To get started, see Model Training & Fine-tuning on TIR or talk to our team.

Disclosure: E2E Networks operates the TIR Training Cluster described in the closing section of this post.

Frequently Asked Questions

sbatch submits a job script to Slurm's queue. The #SBATCH lines in the script say what the job needs, such as nodes, GPUs and a time limit. Slurm returns a job ID straight away and runs the job when resources are free, even if you log out.

sbatch puts a whole script in the queue to run later. srun starts a program on allocated nodes right away. Multi-node training uses both: sbatch submits the job, and an srun line inside the script launches training on every node at once.

It depends on the model's size and how fast you need results. As a rough guide, mixed-precision training with the Adam optimizer needs about 16 bytes of GPU memory per parameter, plus room for each batch. Add nodes until the model fits, then add more to finish sooner.

Yes. Tools such as Enroot and Pyxis let Slurm run Docker or OCI images without root access. You add --container-image to your srun command, and the container starts on every allocated node with access to its GPUs.

Most hangs happen while NCCL connects the GPUs. Run with NCCL_DEBUG=INFO to see where it stops. Common causes are InfiniBand devices not mounted in the container, wrong adapter names in NCCL_IB_HCA, or a hard-coded master address instead of one taken from the job's node list.

Slurm is waiting for resources that match your request. Run squeue -u $USER and read the NODELIST(REASON) column. Resources means not enough free GPUs, Priority means another job is ahead, and PartitionTimeLimit means your --time is longer than the partition allows.

No. The cluster can keep running, but a job on a failed node ends. Your training script must save checkpoints to shared storage and resume from the latest one when you resubmit the job.

Slurm is built for batch jobs that need many GPUs to start together, which suits large training runs. Kubernetes is stronger for long-running services such as model inference. Many teams train on Slurm and serve on Kubernetes, and some run Slurm on top of Kubernetes.