调试技巧

调试技巧#

调试挂起/崩溃问题#

当 vLLM 实例挂起或崩溃时,很难调试问题。但请稍等,vLLM 也可能正在执行一些确实需要很长时间的操作:

  • 下载模型: 你是否已将模型下载到磁盘?如果没有,vLLM 将从互联网下载模型,这可能需要很长时间。请确保检查互联网连接。最好先使用 huggingface-cli 下载模型,然后使用模型的本地路径。这样,你就可以隔离问题。

  • 从磁盘加载模型: 如果模型很大,从磁盘加载模型可能需要很长时间。请注意模型的存储位置。一些集群在节点之间共享文件系统,例如分布式文件系统或网络文件系统,这可能很慢。最好将模型存储在本地磁盘中。此外,请注意 CPU 内存使用情况。当模型太大时,它可能会占用大量 CPU 内存,这会降低操作系统速度,因为它需要频繁地在磁盘和内存之间交换内存。

  • 张量并行推理: 如果模型太大,无法放入单个 GPU,你可能需要使用张量并行来将模型拆分到多个 GPU 上。在这种情况下,每个进程都会读取整个模型并将其拆分成块,这会使磁盘读取时间更长(与张量并行的规模成正比)。你可以使用`提供的脚本 <https://docs.vllm.ai/en/latest/getting_started/examples/save_sharded_state.html>`_ 将模型检查点转换为分片检查点。转换过程可能需要一些时间,但之后你可以更快地加载分片检查点。模型加载时间应该保持不变,无论张量并行的规模如何。

如果你已经解决了上述问题,但 vLLM 实例仍然挂起,CPU 和 GPU 利用率接近零,则 vLLM 实例可能卡在某个地方。以下是一些帮助调试问题的技巧:

  • 设置环境变量 export VLLM_LOGGING_LEVEL=DEBUG 以开启更多日志记录。

  • 设置环境变量 export CUDA_LAUNCH_BLOCKING=1 以准确了解哪个 CUDA 内核导致了问题。

  • 设置环境变量 export NCCL_DEBUG=TRACE 以开启更多 NCCL 日志记录。

  • 设置环境变量 export VLLM_TRACE_FUNCTION=1。vLLM 中的所有函数调用都将被记录。检查这些日志文件,并确定哪个函数崩溃或挂起。

通过更多日志记录,希望你能找到问题的根本原因。

如果它崩溃,并且错误跟踪显示在 vllm/worker/model_runner.py 中的 self.graph.replay() 附近,则这是 cudagraph 中的 cuda 错误。要了解导致错误的特定 cuda 操作,你可以在命令行中添加 --enforce-eager,或在 LLM 类中添加 enforce_eager=True,以禁用 cudagraph 优化。这样,你就可以找到导致错误的确切 cuda 操作。

以下是一些可能导致挂起的问题:

  • 网络配置错误: 如果你的网络配置比较复杂,vLLM 实例可能无法获取正确的 IP 地址。你可以查看日志,例如 DEBUG 06-10 21:32:17 parallel_state.py:88] world_size=8 rank=0 local_rank=0 distributed_init_method=tcp://xxx.xxx.xxx.xxx:54641 backend=nccl。IP 地址应该正确。如果不是,可以通过设置环境变量 export VLLM_HOST_IP=你的 IP 地址 来覆盖 IP 地址。你可能还需要设置 export NCCL_SOCKET_IFNAME=你的网络接口export GLOO_SOCKET_IFNAME=你的网络接口 来指定 IP 地址的网络接口。

  • 硬件/驱动程序错误: 无法建立 GPU/CPU 通信。你可以运行以下健全性检查脚本,查看 GPU/CPU 通信是否正常工作。

# Test PyTorch NCCL
import torch
import torch.distributed as dist
dist.init_process_group(backend="nccl")
local_rank = dist.get_rank() % torch.cuda.device_count()
torch.cuda.set_device(local_rank)
data = torch.FloatTensor([1,] * 128).to("cuda")
dist.all_reduce(data, op=dist.ReduceOp.SUM)
torch.cuda.synchronize()
value = data.mean().item()
world_size = dist.get_world_size()
assert value == world_size, f"Expected {world_size}, got {value}"

print("PyTorch NCCL is successful!")

# Test PyTorch GLOO
gloo_group = dist.new_group(ranks=list(range(world_size)), backend="gloo")
cpu_data = torch.FloatTensor([1,] * 128)
dist.all_reduce(cpu_data, op=dist.ReduceOp.SUM, group=gloo_group)
value = cpu_data.mean().item()
assert value == world_size, f"Expected {world_size}, got {value}"

print("PyTorch GLOO is successful!")

# Test vLLM NCCL, with cuda graph
from vllm.distributed.device_communicators.pynccl import PyNcclCommunicator

pynccl = PyNcclCommunicator(group=gloo_group, device=local_rank)
pynccl.disabled = False

s = torch.cuda.Stream()
with torch.cuda.stream(s):
    data.fill_(1)
    pynccl.all_reduce(data, stream=s)
    value = data.mean().item()
    assert value == world_size, f"Expected {world_size}, got {value}"

print("vLLM NCCL is successful!")

g = torch.cuda.CUDAGraph()
with torch.cuda.graph(cuda_graph=g, stream=s):
    pynccl.all_reduce(data, stream=torch.cuda.current_stream())

data.fill_(1)
g.replay()
torch.cuda.current_stream().synchronize()
value = data.mean().item()
assert value == world_size, f"Expected {world_size}, got {value}"

print("vLLM NCCL with cuda graph is successful!")

dist.destroy_process_group(gloo_group)
dist.destroy_process_group()

小技巧

将脚本保存为 test.py

如果你在单节点上进行测试,请使用 NCCL_DEBUG=TRACE torchrun --nproc-per-node=8 test.py 运行它,将 --nproc-per-node 调整到你想要使用的 GPU 数量。

如果你在多节点上进行测试,请使用 NCCL_DEBUG=TRACE torchrun --nnodes 2 --nproc-per-node=2 --rdzv_backend=c10d --rdzv_endpoint=$MASTER_ADDR test.py 运行它。根据你的设置调整 --nproc-per-node--nnodes。确保 MASTER_ADDR:

  • 是主节点的正确 IP 地址

  • 可以从所有节点访问

  • 在运行脚本之前设置。

如果脚本运行成功,你应该看到消息 健全性检查成功!

如果问题仍然存在,请随时 在 GitHub 上打开一个问题,并提供问题的详细描述、你的环境和日志。

一些已知问题:

  • v0.5.2v0.5.3v0.5.3.post1 中,存在一个由 zmq 引起的错误,该错误可能导致低概率的挂起(大约 20 次出现一次,具体取决于机器配置)。解决方案是升级到最新版本的 vllm 以包含 修复

警告

找到根本原因并解决问题后,请记住关闭上面定义的所有调试环境变量,或者简单地启动一个新的 shell 以避免受到调试设置的影响。如果你没有这样做,系统可能会很慢,因为许多调试功能被打开了。