行业资讯

Vllm LINUX部署Qwen3.8-27B多模态支持视频图片模型全流程(8张L20卡)

发布时间:2026/8/26 18:40:42
Vllm LINUX部署Qwen3.8-27B多模态支持视频图片模型全流程(8张L20卡) 一.环境准备1.安装python虚拟环境,安装VLLMsudo dnf install -y gcc openssl-devel bzip2-devel libffi-devel xz-devel sqlite-devel sudo dnf install python3-devel libxml2-devel libxslt-devel zlib-devel pcre-devel openssl-devel sudo wget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz tar xvf Python-3.11.6.tgz cd Python-3.11.6 ./configure --enable-optimizations make -j$(nproc) sudo make install #验证 /usr/local/bin/python3.11 --version #创建虚拟环境 python3 -m venv vllm_env #激活虚拟环境 source vllm_env/bin/activate # #安装 vllm pip3 install vllm0.25.02.安装英伟达显卡驱动wget https://mirrors.tencentyun.com/install/GPU/NVIDIA-Linux-x86_64-580.82.07.run chmod x NVIDIA-Linux-x86_64-580.82.07.run ./NVIDIA-Linux-x86_64-580.82.07.run -x cd NVIDIA-Linux-x86_64-580.82.07 ./nvidia-installer #查看显卡 lspci | grep -i nvidia #查看驱动英伟达显卡 nvidia-smi #实时监控 watch -n 1 nvidia-smi #toolkit ✅ 安装到 /data 目录 步骤 1创建目标目录 bash sudo mkdir -p /data/cuda-root 步骤 2使用 --installroot 安装到 /data bash sudo yum install -y --installroot/data/cuda-root cuda-toolkit-12-5 步骤 3安装完成后CUDA 文件在 /data/cuda-root/usr/local/cuda-12.5 bash ls -la /data/cuda-root/usr/local/ 步骤 4创建软链接 bash sudo ln -sf /data/cuda-root/usr/local/cuda-12.5 /data/cuda-12.5 步骤 5设置环境变量 bash echo export CUDA_HOME/data/cuda-12.5 ~/.bashrc echo export PATH$CUDA_HOME/bin:$PATH ~/.bashrc source ~/.bashrc 步骤 6验证 bash /data/cuda-12.5/bin/nvcc --version3.模型下载#魔塔社区下载模型 pip3 install modelscope modelscope download --model Qwen/Qwen3.8-27B --local_dir /data/app/model/Qwen3.8-27B #huggingface下载模型 # 设置环境变量使用 HF 镜像 pip install -U huggingface_hub export HF_TOKENhf_your_token_here export HF_ENDPOINThttps://hf-mirror.com hf download tencent/Qwen3.8-27B \ --local-dir /data/app/model/Hy/Qwen3.8-27B4.启动脚本编写启动脚本(3卡实例不支持改模型)#!/bin/bash # # vLLM 生产级部署脚本 - v0.25.0 # 模型: Qwen3.8-27B # 使用: ./deploy.sh [single|dual|3card|4card|auto] # set -uo pipefail # 信号处理 trap log_info 收到退出信号正在清理...; kill $(jobs -p) 2/dev/null; exit SIGTERM SIGINT # 缓存目录设置 export VLLM_CACHE_ROOT/run/vllm_cache export TMPDIR/run/tmp mkdir -p /run/vllm_cache /run/tmp chmod 1777 /run/tmp SCRIPT_DIR$(cd $(dirname ${BASH_SOURCE[0]}) pwd) # CUDA 环境变量 export CUDA_HOME/data/cuda-12.5 export PATH$CUDA_HOME/bin:$PATH # 核心配置 MODEL_PATH/data/app/model/Qwen/Qwen3.8-27B SERVED_NAMEQwen3.8-27B VENV_PATH/data/app/vllm_env # 性能调优参数 MAX_MODEL_LEN102400 MAX_NUM_SEQS24 GPU_MEMORY_UTIL0.85 KV_CACHE_DTYPEfp8 ENABLE_CHUNKED_PREFILLfalse # MTP 配置 ENABLE_MTPtrue MTP_NUM_SPECULATIVE_TOKENS3 # 路径配置 LOG_DIR${SCRIPT_DIR}/vllm_logs PID_DIR${SCRIPT_DIR}/vllm_pids mkdir -p $LOG_DIR $PID_DIR # 颜色输出 GREEN\033[0;32m RED\033[0;31m YELLOW\033[1;33m BLUE\033[0;34m NC\033[0m log_info() { echo -e ${GREEN}[INFO]${NC} $1; } log_error() { echo -e ${RED}[ERROR]${NC} $1; } log_warn() { echo -e ${YELLOW}[WARN]${NC} $1; } log_model() { echo -e ${BLUE}[MODEL]${NC} $1; } # 获取部署模式名称 get_deploy_mode_name() { local tp$1 case $tp in 1) echo 单卡 ;; 2) echo 双卡 ;; 3) echo 三卡 ;; 4) echo 四卡 ;; *) echo ${tp}卡 ;; esac } # 解析部署模式 parse_deploy_mode() { local mode${1:-auto} case $mode in single) NUM_INSTANCES8 TENSOR_PARALLEL_SIZE1 BASE_PORT8000 log_info 部署模式: 单卡 (8实例 × 1卡, 端口8000-8007) ;; dual) NUM_INSTANCES4 TENSOR_PARALLEL_SIZE2 BASE_PORT8000 log_info 部署模式: 双卡 (4实例 × 2卡, 端口8000-8003) ;; 3card) NUM_INSTANCES2 TENSOR_PARALLEL_SIZE3 BASE_PORT8000 log_info 部署模式: 三卡 (2实例 × 3卡, 端口8000-8001) ;; 4card) NUM_INSTANCES2 TENSOR_PARALLEL_SIZE4 BASE_PORT8000 log_info 部署模式: 四卡 (2实例 × 4卡, 端口8000-8001) ;; auto|*) # 自动检测根据 GPU 数量决定 local gpu_count$(nvidia-smi --query-gpuname --formatcsv,noheader 2/dev/null | wc -l) if [ $gpu_count -ge 8 ]; then NUM_INSTANCES8 TENSOR_PARALLEL_SIZE1 log_info 自动检测: 8 GPU使用单卡模式 elif [ $gpu_count -ge 4 ]; then NUM_INSTANCES4 TENSOR_PARALLEL_SIZE2 log_info 自动检测: 4-7 GPU使用双卡模式 else log_error GPU 数量不足 (需要至少4张): $gpu_count exit 1 fi BASE_PORT8000 ;; esac local total_gpus$((NUM_INSTANCES * TENSOR_PARALLEL_SIZE)) log_info 实例数: $NUM_INSTANCES log_info TP大小: $TENSOR_PARALLEL_SIZE log_info 总GPU: $total_gpus } # 激活虚拟环境 activate_venv() { if [ ! -d $VENV_PATH ]; then log_error 虚拟环境不存在: $VENV_PATH exit 1 fi source $VENV_PATH/bin/activate log_info 已激活虚拟环境: $VENV_PATH if ! command -v nvcc /dev/null; then log_error nvcc 未找到请检查 CUDA 安装 exit 1 fi log_info CUDA 版本: $(nvcc --version | grep release | awk {print $6} | sed s/,//) } # 等待服务启动 wait_for_service() { local port$1 local instance_name$2 local max_wait600 local wait_time0 local interval5 log_info 等待 $instance_name (端口 $port) 服务启动... while [ $wait_time -lt $max_wait ]; do if netstat -tln 2/dev/null | grep -q :$port; then local http_code$(curl -s -o /dev/null -w %{http_code} http://127.0.0.1:$port/v1/models 2/dev/null) if [ $http_code 200 ]; then log_info ✅ $instance_name 已就绪 (耗时 ${wait_time}s) return 0 fi fi sleep $interval wait_time$((wait_time interval)) [ $((wait_time % 30)) -eq 0 ] log_info 等待 $instance_name ... (已等待 ${wait_time}s) done log_error $instance_name 等待超时 (${max_wait}s) return 1 } # 启动单个实例 start_instance() { local instance_id$1 local port$((BASE_PORT instance_id)) # 计算 GPU 分配 local gpu_start$((instance_id * TENSOR_PARALLEL_SIZE)) local gpu_end$((gpu_start TENSOR_PARALLEL_SIZE - 1)) local gpu_list$(seq -s , $gpu_start $gpu_end) local LOG_FILE$LOG_DIR/instance_${instance_id}.log local PID_FILE$PID_DIR/instance_${instance_id}.pid log_model 启动实例 $instance_id: GPU$gpu_list, 端口$port log_info 日志: $LOG_FILE # MTP 参数 local MTP_ARG if [ $ENABLE_MTP true ]; then MTP_ARG--speculative-config {\method\:\mtp\,\num_speculative_tokens\:$MTP_NUM_SPECULATIVE_TOKENS} log_info MTP 已启用: num_speculative_tokens$MTP_NUM_SPECULATIVE_TOKENS fi # 启动进程 CUDA_VISIBLE_DEVICES$gpu_list \ vllm serve \ --model $MODEL_PATH \ --served-model-name $SERVED_NAME \ --tensor-parallel-size $TENSOR_PARALLEL_SIZE \ --max-model-len $MAX_MODEL_LEN \ --max-num-seqs $MAX_NUM_SEQS \ --enable-auto-tool-choice \ --tool-call-parser hermes \ --gpu-memory-utilization $GPU_MEMORY_UTIL \ ${KV_CACHE_DTYPE:--kv-cache-dtype $KV_CACHE_DTYPE} \ $( [ $ENABLE_CHUNKED_PREFILL true ] echo --enable-chunked-prefill ) \ --port $port \ --host 0.0.0.0 \ --enable-log-requests \ ${MTP_ARG} \ $LOG_FILE 21 local pid$! echo $pid $PID_FILE log_info PID: $pid sleep 2 } # 启动所有实例 start_instances() { log_info log_info 启动 $NUM_INSTANCES 个 vLLM 实例... log_info 模型: $SERVED_NAME log_info for ((i0; iNUM_INSTANCES; i)); do start_instance $i done log_info sleep 2 } # 验证所有实例 verify_instances() { log_info log_info 等待所有实例启动完成... log_info 注意: 首次启动可能需要 5-10 分钟进行 torch.compile log_info local all_readytrue for ((i0; iNUM_INSTANCES; i)); do local port$((BASE_PORT i)) if ! wait_for_service $port 实例$((i1)); then all_readyfalse log_error 实例 $((i1)) (端口 $port) 启动失败 log_info 查看日志: tail -100 $LOG_DIR/instance_${i}.log fi done echo if [ $all_ready true ]; then log_info log_info ✅ 所有实例已成功启动 log_info log_info log_model $SERVED_NAME log_info 部署模式: $(get_deploy_mode_name $TENSOR_PARALLEL_SIZE) log_info 实例数: $NUM_INSTANCES log_info TP 大小: $TENSOR_PARALLEL_SIZE log_info 总 GPU: $((NUM_INSTANCES * TENSOR_PARALLEL_SIZE)) 张 log_info for ((i0; iNUM_INSTANCES; i)); do local port$((BASE_PORT i)) local gpu_start$((i * TENSOR_PARALLEL_SIZE)) local gpu_end$((gpu_start TENSOR_PARALLEL_SIZE - 1)) log_info 端口 $port: GPU $gpu_start-$gpu_end done log_info log_info 测试命令: for ((i0; iNUM_INSTANCES; i)); do log_info curl http://127.0.0.1:$((BASE_PORT i))/v1/models done log_info return 0 else log_error log_error ❌ 部分实例启动失败请检查日志 log_error return 1 fi } # 主流程 main() { # 解析部署模式从命令行参数 parse_deploy_mode ${1:-auto} log_info log_info vLLM 0.25.0 单模型多实例部署 log_info 模型: $SERVED_NAME log_info 模式: $(get_deploy_mode_name $TENSOR_PARALLEL_SIZE) log_info 实例: $NUM_INSTANCES 个 (TP$TENSOR_PARALLEL_SIZE) log_info 端口: $BASE_PORT-$((BASE_PORT NUM_INSTANCES - 1)) log_info activate_venv start_instances verify_instances } # # 主进程保持运行等待所有子进程 # main $ JOBS$(jobs -p) if [ -n $JOBS ]; then log_info 脚本进入守护模式等待 $NUM_INSTANCES 个 vLLM 进程... log_info 子进程 PIDs: $JOBS wait log_warn 所有 vLLM 子进程已退出脚本结束 else log_error 没有后台子进程脚本退出 exit 1 fi停止脚本#!/bin/bash # # vLLM 生产级停止脚本彻底版 # set -e SCRIPT_DIR$(cd $(dirname ${BASH_SOURCE[0]}) pwd) PID_DIR${SCRIPT_DIR}/vllm_pids log_info() { echo -e \033[0;32m[INFO]\033[0m $1; } log_warn() { echo -e \033[1;33m[WARN]\033[0m $1; } log_error() { echo -e \033[0;31m[ERROR]\033[0m $1; } stop_instances() { log_info 正在停止所有 vLLM 实例... # 1. 通过 PID 文件停止主进程 if [ -d $PID_DIR ]; then for pid_file in $PID_DIR/*.pid; do if [ -f $pid_file ]; then PID$(cat $pid_file) if kill -0 $PID 2/dev/null; then log_info 停止主进程 PID: $PID # 先发 SIGTERM 让进程自己清理 kill -TERM $PID 2/dev/null || kill -9 $PID 2/dev/null else log_warn 进程 $PID 已不存在 fi rm -f $pid_file fi done fi # 2. 等待主进程退出 sleep 2 # 3. 清理所有 vLLM 相关进程关键 log_info 清理所有 vLLM 相关进程... # vLLM Worker 进程最常见残留 local worker_count$(ps aux | grep -c VLLM::Worker 2/dev/null || echo 0) if [ $worker_count -gt 0 ]; then pkill -9 -f VLLM::Worker 2/dev/null log_info ✅ 已杀死 Worker 进程 || true fi # EngineCore 进程 pkill -9 -f EngineCore 2/dev/null log_info ✅ 已杀死 EngineCore 进程 || true # multiprocessing resource_tracker pkill -9 -f resource_tracker 2/dev/null log_info ✅ 已杀死 resource_tracker || true # vLLM 主进程二次清理 pkill -9 -f vllm serve 2/dev/null log_info ✅ 已杀死 vLLM 主进程 || true # 其他 vLLM Python 进程 pkill -9 -f vllm_env.*vllm 2/dev/null log_info ✅ 已杀死其他 vLLM Python 进程 || true # 4. 等待进程退出 sleep 2 # 5. 检查残留 local remaining$(ps aux | grep -E vllm|VLLM::Worker|EngineCore|resource_tracker | grep -v grep | wc -l) if [ $remaining -eq 0 ]; then log_info ✅ 所有进程已清理干净 else log_warn ⚠️ 还有 $remaining 个残留进程: ps aux | grep -E vllm|VLLM::Worker|EngineCore|resource_tracker | grep -v grep fi log_info 所有实例已停止。 } # 强制停止模式 force_stop() { log_warn 执行强制停止... # 杀死所有相关进程 pkill -9 -f vllm serve 2/dev/null || true pkill -9 -f VLLM::Worker 2/dev/null || true pkill -9 -f EngineCore 2/dev/null || true pkill -9 -f resource_tracker 2/dev/null || true pkill -9 -f vllm_env.*vllm 2/dev/null || true rm -rf $PID_DIR 2/dev/null || true sleep 2 log_info ✅ 强制停止完成 # 检查残留 local remaining$(ps aux | grep -E vllm|VLLM::Worker|EngineCore | grep -v grep | wc -l) if [ $remaining -eq 0 ]; then log_info ✅ 所有进程已清理干净 else log_warn ⚠️ 还有 $remaining 个残留进程: ps aux | grep -E vllm|VLLM::Worker|EngineCore | grep -v grep fi } # 主逻辑 case $1 in -f|--force) force_stop ;; *) stop_instances ;; esac