Omni代码分析 ‐‐ Global Proxy - MozhiJiawei/Personal-Wiki GitHub Wiki

部署视图

Global_Proxy

说明:

  • 整体支持xPyD部署模式,y当前仅支持1,多个主机组成一台Decode模型实例,对外提供服务
  • 910C上,一台服务器有8卡16die,可以满足一个P节点的部署
  • Global_Proxy与Prefill首节点共部署

容器镜像与依赖

代码中有两个docker_file以及相应的构建脚本。

image
📦 容器镜像层次:
├─ 🏠 基础镜像: registry-cbu.huawei.com/omni_infer_v1/base_py311
│   ├─ openEuler 22.03-LTS (ARM64)
│   ├─ Python 3.11.4 (源码编译)
│   ├─ 华为昇腾CANN 7.7套件
│   ├─ 科学计算包(numpy, scipy, torch等)
│   └─ 系统依赖和开发工具
│
└─ 🚀 应用镜像: registry-cbu.huawei.com/omni_infer_v1/omni_infer
    ├─ 基于上述基础镜像
    ├─ vLLM推理引擎(昇腾优化版)
    ├─ OmniInfer核心代码
    ├─ Nginx全局代理(7个负载均衡模块)
    └─ PyTorch-NPU 2.5.1

基础环境镜像

操作系统基础:

FROM registry-cbu.huawei.com/openeuler/openeuler-aarch64:22.03-lts

系统包依赖:

  • 开发工具: git, vim, wget, Development Tools
  • 网络工具: net-tools, openssl-devel
  • 系统库: bzip2-devel, libffi-devel, sqlite-devel, pcre, libuuid-devel
  • 硬件相关: pciutils, kmod, systemd, systemd-udev

Python环境:

  • Python 3.11.4: 从源码编译安装,启用优化选项
  • 基础Python包: pip, setuptools, wheel

华为昇腾CANN套件 (完整HPC高性能计算包):

  • CANN-compiler*.run - 编译器组件
  • CANN-toolkit*.run - 工具包
  • CANN-runtime*.run - 运行时环境
  • CANN-opp*.run - 算子包
  • CANN-hccl*.run - 集合通信库
  • CANN-aoe*.run - 自动算子优化
  • CANN-ncs*.run - 网络控制服务
  • CANN-fwkplugin*.run - 框架插件
  • Ascend-aicpu*.run - AI CPU运行时
  • Ascend910_93-opp_kernel*.run - 910芯片算子内核
  • Ascend-cann-nnal_8.1.RC1 - 神经网络加速库

Python科学计算依赖:

# 核心科学计算包
numpy<2.0.0, scipy, sympy, numba
# 深度学习基础
attrs, decorator, cffi, pyyaml, protobuf
# 分布式和服务
ray, tornado, requests, absl-py
# 工具包
psutil, pathlib2, setuptools_scm, typing_extensions

Omni_Infer服务镜像

基础环境:

ARG BASE_IMAGE
FROM ${BASE_IMAGE}  # 继承上面的基础镜像

深度学习框架:

  • PyTorch 2.5.1: 主要深度学习框架
  • torch-npu: 华为NPU适配的PyTorch版本
  • ml-dtypes: 机器学习数据类型支持

推理引擎核心:

  • vLLM: 高性能大语言模型推理引擎 (卸载原版,安装定制版)
  • vllm_ascend: 华为昇腾适配的vLLM版本
  • compressed-tensors==0.9.4: 模型压缩和量化支持

OmniInfer核心组件:

  • omni_infer源码: 项目主要代码,以开发模式安装
  • 推理引擎: bash bash_install_code.sh 安装推理引擎

容器运行时资源配置

容器实例规格:
  Prefill容器:
    命名: omni_infer_prefill_p{node_rank}
    资源限制:
      NPU: 0-16 NPU卡专用
      内存: 500GB共享内存
      CPU: 16-32核心
    网络: host模式(高性能)
    存储挂载:
      - 模型目录: /data/models (只读)
      - 日志目录: /var/log/omni_infer
      - 配置目录: /etc/omni_infer

  Decode容器:
    命名: omni_infer_decode_d{node_rank}
    资源限制:
      NPU: 0-16卡专用
      内存: 500GB共享内存
      CPU: 8-16核心
    网络: host模式(高性能)
    存储挂载: (同Prefill)

  Proxy容器:
    命名: omni_infer_proxy_c{node_rank}
    资源限制:
      CPU: 4-8核心
      内存: 8-16GB
    网络: host模式
    端口映射: proxy_port + node_rank

挂载目录配置

容器启动脚本:

docker run -it --shm-size=500g \
  # 环境变量设置
  -e OMNI_INFER_SCRIPTS=$OMNI_INFER_SCRIPTS \
  -e RANKTABLE_SAVE_PATH={{ ranktable_save_path }} \
  -e MODEL_PATH=$MODEL_PATH \
  -e LOG_PATH=$LOG_PATH \
  # 网络和权限设置
  --net=host \
  --privileged=true \
  -u root \
  -w /data \
  # NPU设备挂载
  --device=/dev/davinci_manager \
  --device=/dev/hisi_hdc \
  --device=/dev/devmm_svm \
  --entrypoint=bash \
  # 挂载目录配置
  -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
  -v /usr/local/dcmi:/usr/local/dcmi \
  -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
  -v /etc/ascend_install.info:/etc/ascend_install.info \
  -v /usr/local/sbin:/usr/local/sbin \
  -v /etc/hccn.conf:/etc/hccn.conf \
  -v /usr/bin/hccn_tool:/usr/bin/hccn_tool \
  -v /tmp:/tmp \
  -v /data:/data \
  -v $MODEL_PATH:$MODEL_PATH \
  -v $LOG_PATH:$LOG_PATH \
  -v $SCRIPTS_PATH:$SCRIPTS_PATH \
  -v $CODE_PATH:$CODE_PATH \
  -v {{ ranktable_save_path }}:{{ ranktable_save_path }} \
  -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \

挂载目录详细信息:

  • Ascend NPU 相关目录
宿主机路径 容器内路径 用途
/usr/local/Ascend/driver /usr/local/Ascend/driver NPU驱动文件
/usr/local/dcmi /usr/local/dcmi DCMI接口
/usr/local/bin/npu-smi /usr/local/bin/npu-smi NPU管理工具
/etc/ascend_install.info /etc/ascend_install.info Ascend安装信息
/usr/local/sbin /usr/local/sbin 系统管理工具
/etc/hccn.conf /etc/hccn.conf HCCL网络配置
/usr/bin/hccn_tool /usr/bin/hccn_tool HCCL工具
  • 数据和模型目录
宿主机路径 容器内路径 用途
/data /data 数据根目录
$MODEL_PATH $MODEL_PATH 模型文件目录
$LOG_PATH $LOG_PATH 日志文件目录
$SCRIPTS_PATH $SCRIPTS_PATH 脚本文件目录
$CODE_PATH $CODE_PATH 代码库目录
{{ ranktable_save_path }} {{ ranktable_save_path }} RankTable文件目录
  • 系统配置目录
宿主机路径 容器内路径 用途
/tmp /tmp 临时文件目录
/usr/share/zoneinfo/Asia/Shanghai /etc/localtime 时区配置文件

端口分配策略

端口规划 (基于配置参数):
  全局代理:
    端口: proxy_port + node_rank
    例如: 8080, 8081, 8082...

  Prefill服务:
    Master端口: global_port_base + port_offset.P + node_rank
    API端口: base_api_port + port_offset.P + node_rank
    例如: 8503, 9001 (P0), 8504, 9002 (P1)

  Decode服务:
    Master端口: global_port_base + port_offset.D
    API端口: base_api_port + port_offset.D + node_rank
    例如: 8603, 9101 (D0), 8603, 9102 (D1)

  内部通信:
    HCCL通信: 动态分配
    KV缓存: 5568 (ZMQ)
    健康检查: HTTP探针

开发视图

目录结构概览

tools/
├── README.md                    # PD运行文档,包含详细的部署示例
├── scripts/                     # 核心脚本工具
│   ├── pd_run.sh               # PD分离服务启动脚本
│   ├── pd_ranktable_tools.py   # Ranktable生成和管理工具
│   ├── start_api_servers.py    # API服务器启动脚本
│   ├── global_proxy.sh         # 全局代理启动脚本
│   ├── test_start_api_servers_qwen.sh  # Qwen模型测试脚本
│   ├── result.json             # 测试结果文件
│   └── apiserverlog/           # API服务器日志目录
│       └── server_0.log        # 服务器日志文件
├── docker/                      # Docker容器化工具
│   ├── build_base_py311.sh     # Python 3.11基础镜像构建脚本
│   ├── build_vllm.sh           # vLLM镜像构建脚本
│   ├── Dockerfile.openEuler.py311.CANNdev.910c  # 华为昇腾环境Dockerfile
│   └── Dockerfile.vllm-omni.source  # vLLM-omni源码Dockerfile
└── ansible/                     # Ansible自动化部署工具
    ├── README.md               # Ansible部署文档
    ├── omni_infer_inventory_used_for_CI.yml      # CI环境清单配置
    ├── omni_infer_inventory_user_for_long_term_test.yml  # 长期测试环境清单
    ├── omni_infer_server_used_for_CI.yml        # CI环境服务器配置
    ├── omni_infer_server_used_for_long_term_test.yml    # 长期测试服务器配置
    └── template/               # 配置模板目录
        ├── README.md           # 模板使用说明
        ├── omni_infer_inventory_used_for_2P1D.yml  # 2P1D部署模板
        ├── omni_infer_inventory_used_for_4P1D.yml  # 4P1D部署模板
        └── omni_infer_server_template.yml         # 服务器配置模板

Docker目录相关说明已在部署视图页体现,本节不再赘述

Ansible

Ansible脚本基础知识

执行过程

  1. 连接各服务器
    1. SSH连接建立
      • 使用ansible_user指定的用户
      • 通过ansible_ssh_private_key_file指定的私钥进行认证
      • 使用ansible_ssh_common_args中的SSH参数
    2. 主机组管理
      • 根据inventory文件中的children定义主机组
      • 每个主机组(P、D、C)代表不同的角色
  2. Task执行
    1. 任务顺序
      • 任务按照在playbook中定义的顺序执行
      • 使用gather_facts: yes收集目标主机信息
    2. 错误处理
      • any_errors_fatal: true确保任何错误都会停止执行
      • max_fail_percentage: 0不允许任何失败
    3. 条件执行
      • 使用when条件控制任务执行
      • 使用run_once: yes确保任务只执行一次

这个Ansible脚本主要用于部署和管理一个分布式AI推理系统,包括Docker容器的管理、代码同步、服务器启动等操作。通过合理的标签管理和条件控制,可以灵活地执行不同的部署阶段。

启动流程概览

graph TD
    A[环境准备] --> B[容器管理]
    B --> C[Ranktable生成]
    C --> D[服务启动]
    D --> E[代理配置]
    
    A1[创建目录<br/>设置环境变量] --> A
    B1[停止旧容器<br/>启动新容器] --> B
    C1[生成prefill ranktable<br/>生成decode ranktable<br/>合并全局ranktable] --> C
    D1[启动decode服务<br/>等待80秒<br/>启动prefill服务] --> D
    E1[配置nginx代理<br/>启动负载均衡] --> E
Loading

详细启动过程

1. run_docker 阶段

执行主机: P组、D组、C组的所有主机

主要任务:

  • 生成容器名称(添加主机名后缀)
  • 检查并删除已存在的容器
  • 启动新的Docker容器

关键命令:

# 启动prefill容器
docker run -it --shm-size=500g [各种挂载参数] -d --name $DOCKER_NAME_P $DOCKER_IMAGE_ID

# 启动decode容器  
docker run -it --shm-size=500g [各种挂载参数] -d --name $DOCKER_NAME_D $DOCKER_IMAGE_ID

# 启动proxy容器
docker run -it --shm-size=500g [各种挂载参数] -d --name $DOCKER_NAME_C $DOCKER_IMAGE_ID

2. sync_code 阶段

执行主机: 所有主机

主要任务:

  • 获取执行器IP地址
  • 删除目标机器上的旧代码
  • 同步代码到所有实例
  • 在容器内更新代码
  • 下载vllm,对齐软件依赖

关键命令:

# 同步代码
synchronize: src: "{{ ansible_env.CODE_PATH }}/omniinfer" dest: "{{ ansible_env.CODE_PATH }}/"

# 容器内更新代码
docker exec $DOCKER_NAME_P /bin/bash -c ' \
    cd /data/local_code_path/omniinfer/infer_engines && \
    git config --global --add safe.directory /data/local_code_path/omniinfer/infer_engines/vllm && \
    cd vllm && git checkout -f && \
    cd .. && \
    bash bash_install_code.sh && \
    pip uninstall vllm -y && \
    pip uninstall omniinfer -y && \
    cd vllm && \
    SETUPTOOLS_SCM_PRETEND_VERSION=0.9.0 VLLM_TARGET_DEVICE=empty pip install -e . && \
    cd ../../ && \
    pip install -e . && \
    pip uninstall numpy -y && \
    pip install numpy==1.26'

3. ranktable 阶段

执行主机: P组、D组主机

主要任务:

  • 生成prefill ranktable文件
  • 生成decode ranktable文件
  • 生成全局ranktable文件
  • 同步ranktable文件到所有实例

关键命令:

# 生成prefill ranktable
python ${CODE_PATH}/omniinfer/tools/scripts/pd_ranktable_tools.py \
    --mode gen \
    --prefill-server-list "${PREFILL_SERVER_LIST}" \
    --api-server \
    --save-dir ${PREFILL_RANKTABLE_SAVE_PATH}

# 生成decode ranktable
python ${CODE_PATH}/omniinfer/tools/scripts/pd_ranktable_tools.py \
    --mode gen \
    --decode-server-list ${DECODE_SERVER_LIST} \
    --save-dir ${DECODE_RANKTABLE_SAVE_PATH}

# 生成全局ranktable
python ${CODE_PATH}/omniinfer/tools/scripts/pd_ranktable_tools.py \
    --mode merge-all \
    --api-server-list ${api_server_files} \
    --prefill-server-list ${prefill_local_ranktable_merge} \
    --decode-server-list ${decode_local_ranktable_merge} \
    --save-dir ${RANKTABLE_SAVE_PATH}/global

4. run_server 阶段

执行主机: P组、D组主机

主要任务:

  • 杀死现有Python进程
  • 启动prefill服务
  • 启动decode服务

关键命令:

# 杀死Python进程
ps aux | grep "python" | grep -v "grep" | awk '{print $2}' | xargs kill -9

# 启动prefill服务
bash ${CODE_PATH}/omniinfer/tools/scripts/pd_run.sh \
    --global-rank-table-path "${RANKTABLE_SAVE_PATH}/global/global_ranktable_merge.json" \
    --rank-table-path ${LOCAL_RANKTABLE_FLIE} \
    --local-decode-server-ip-list "$SERVER_IP_LIST" \
    --global-decode-server-ip-list "$SERVER_IP_LIST" \
    --prefill-pod-num ${PREFILL_POD_NUM} \
    --gloo-socket-ifname ${SOCKET_IFNAME} \
    --tp-socket-ifname ${SOCKET_IFNAME} \
    --model-path ${MODEL_PATH} \
    --master-ip ${HOST_IP} \
    --role "prefill" \
    --kv-role "kv_producer" \
    --max-model-len ${MODEL_LEN_MAX_PREFILL} \
    --master-port ${MASTER_PORT} \
    --base-api-port ${API_PORT} \
    --tp ${PREFILL_TENSOR_PARALLEL_SIZE} \
    --ascend-rt-visible-devices "${PREFILL_SERVER_LIST}" \
    --kv-rank ${KV_RANK} \
    --kv-engine-id ${KV_RANK} \
    --kv-parallel-size ${KV_PARALLEL_SIZE} \
    --model-extra-cfg-path ${MODEL_EXTRA_CFG_PATH} \
    --gpu-util ${GPU_UTIL} \
    --vllm-enable-mc2 ${VLLM_ENABLE_MC2} \
    --extra-args "${EXTRA_ARGS}" \
    --hccl-buffsize "${HCCL_BUFFSIZE}" \
    --hccl-op-expansion-mode "${HCCL_OP_EXPANSION_MODE}" \
    --log-dir "${LOG_PATH}"

# 启动decode服务
bash ${CODE_PATH}/omniinfer/tools/scripts/pd_run.sh \
	--global-rank-table-path "${RANKTABLE_SAVE_PATH}/global/global_ranktable_merge.json" \
	--rank-table-path ${LOCAL_RANKTABLE_FLIE} \
	--local-decode-server-ip-list "$SERVER_IP_LIST" \
	--global-decode-server-ip-list "$SERVER_IP_LIST" \
	--prefill-pod-num ${PREFILL_POD_NUM} \
	--gloo-socket-ifname ${SOCKET_IFNAME} \
	--tp-socket-ifname ${SOCKET_IFNAME} \
	--num-servers ${NUM_SERVERS} \
	--num-dp ${dp} \
	--server-offset ${config_dict[$HOST]:-0} \
	--model-path ${MODEL_PATH} \
	--master-ip ${HOST_IP} \
	--role "decode" \
	--kv-role "kv_consumer" \
	--max-model-len ${MODEL_LEN_MAX_DECODE} \
	--master-port ${MASTER_PORT} \
	--base-api-port ${API_PORT} \
	--tp ${DECODE_TENSOR_PARALLEL_SIZE} \
	--kv-rank ${PREFILL_POD_NUM} \
	--kv-engine-id ${PREFILL_POD_NUM} \
	--kv-parallel-size ${KV_PARALLEL_SIZE} \
	--model-extra-cfg-path ${MODEL_EXTRA_CFG_PATH} \
	--gpu-util ${GPU_UTIL} \
	--additional-config "$ADDITIONAL_CONFIG" \
	--vllm-enable-mc2 ${VLLM_ENABLE_MC2} \
	--extra-args "${EXTRA_ARGS}" \
	--hccl-buffsize "${HCCL_BUFFSIZE}" \
	--hccl-op-expansion-mode "${HCCL_OP_EXPANSION_MODE}" \
	--log-dir "${LOG_PATH}"

5. run_proxy 阶段

执行主机: C组主机

主要任务:

  • 杀死现有nginx进程
  • 下载并编译nginx
  • 启动全局代理服务

关键命令:

# 杀死nginx进程
ps aux | grep "nginx" | grep -v "grep" | awk '{print $2}' | xargs kill -9

# 下载nginx
wget --no-check-certificate "https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz"

# 编译nginx
bash build.sh

# 启动代理服务
bash global_proxy.sh \
	--listen-port "$PROXY_NODE_PORT" \
	--prefill-servers-list "$prefill_result" \
	--decode-servers-list "$decode_result" \
	--log-file /dev/shm/trace/logs/nginx_error.log \
	--log-level notice \
	--core-num 4 \
	--start-core-index 16

6. fetch_log 阶段

执行主机: 执行器主机

主要任务:

  • 创建日志目录
  • 从所有机器拉取日志到执行器

关键命令:

# 创建日志目录
mkdir -p "{{ ansible_env.LOG_PATH_IN_EXECUTOR }}/{{ inventory_hostname }}"

# 拉取日志
synchronize: mode: pull src: "{{ ansible_env.LOG_PATH }}" dest: "{{ ansible_env.LOG_PATH_IN_EXECUTOR }}/{{ inventory_hostname }}/"

启动脚本

├── scripts/                     # 核心脚本工具
│   ├── pd_run.sh               # PD分离服务启动脚本
│   ├── pd_ranktable_tools.py   # Ranktable生成和管理工具
│   ├── start_api_servers.py    # API服务器启动脚本
│   ├── global_proxy.sh         # 全局代理启动脚本
│   ├── test_start_api_servers_qwen.sh  # Qwen模型测试脚本
│   ├── result.json             # 测试结果文件
│   └── apiserverlog/           # API服务器日志目录
│       └── server_0.log        # 服务器日志文件

ranktable

执行脚本:

# 生成prefill ranktable
python ${CODE_PATH}/omniinfer/tools/scripts/pd_ranktable_tools.py \
    --mode gen \
    --prefill-server-list "${PREFILL_SERVER_LIST}" \
    --api-server \
    --save-dir ${PREFILL_RANKTABLE_SAVE_PATH}

# 生成decode ranktable
python ${CODE_PATH}/omniinfer/tools/scripts/pd_ranktable_tools.py \
    --mode gen \
    --decode-server-list ${DECODE_SERVER_LIST} \
    --save-dir ${DECODE_RANKTABLE_SAVE_PATH}

# 生成全局ranktable
python ${CODE_PATH}/omniinfer/tools/scripts/pd_ranktable_tools.py \
    --mode merge-all \
    --api-server-list ${api_server_files} \
    --prefill-server-list ${prefill_local_ranktable_merge} \
    --decode-server-list ${decode_local_ranktable_merge} \
    --save-dir ${RANKTABLE_SAVE_PATH}/global

执行结果:Merge后的全局rankTable:

{
    "version": "1.0",
    "status": "completed",
    "server_group_list": [
        {
            "group_id": "0",
            "server_count": "1",
            "server_list": [
                {
                    "server_id": "host_ip",
                    "server_ip": "host_ip"
                }
            ]
        },
        {
            "group_id": "1",
            "server_count": "1",
            "server_list": [
                {
                    "server_id": "host_ip",
                    "server_ip": "host_ip",
                    "device": [
                        {
                            "device_id": "0",
                            "device_ip": "device_ip_0",
                            "rank_id": "0"
                        },
                        {
                            "device_id": "1",
                            "device_ip": "device_ip_1",
                            "rank_id": "1"
                        }
                        // ... 更多设备
                    ]
                }
                // ... 更多Server
            ]
        },
        {
            "group_id": "2",
            "server_count": "1",
            "server_list": [
                {
                    "server_id": "host_ip",
                    "server_ip": "host_ip",
                    "device": [
                        {
                            "device_id": "0",
                            "device_ip": "device_ip_0",
                            "rank_id": "0"
                        },
                        {
                            "device_id": "1",
                            "device_ip": "device_ip_1",
                            "rank_id": "1"
                        }
                        // ... 更多设备
                    ]
                }
                // ... 更多Server
            ]
        }
    ]
}

RankTable的作用:

  1. 用于初始化HCCL集合通信库
# 在pd_run.sh中使用ranktable配置分布式通信
--global-rank-table-path "${RANKTABLE_SAVE_PATH}/global/global_ranktable_merge.json" \
--rank-table-path ${LOCAL_RANKTABLE_FLIE}
  1. rankTable中的服务器信息通过命令行的方式传递给Global_Proxy(Ngnix),做上层负载均衡使用
# 在部署脚本中,ranktable信息被转换为服务器列表
prefill_result="{{ PREFILL_API_SERVER_LIST }}"
decode_result="{{ DECODE_API_SERVER_LIST }}"

# 然后传递给Global_Proxy
bash global_proxy.sh \
  --prefill-servers-list "$prefill_result" \
  --decode-servers-list "$decode_result"

Server启动(pd_run.sh脚本)

调用过程:pd_run.sh ==> start_api_server.py ==> 设置环境变量、生成vllm启动脚本并启动子进程 ==> 启动健康检查

vllm执行脚本示例(以环境实测为准):

vllm serve ${MODEL_PATH} \
    --trust-remote-code \
    --gpu-memory-utilization ${GPU_UTIL} \
    --block_size 128 \
    --tensor-parallel-size ${PREFILL_TENSOR_PARALLEL_SIZE} \
    --data-parallel-size 1 \
    --data-parallel-size-local 1 \
    --data-parallel-address ${HOST_IP} \
    --data-parallel-rpc-port ${MASTER_PORT} \
    --port ${API_PORT} \
    --served-model-name "deepseek" \
    --max-model-len ${MODEL_LEN_MAX_PREFILL} \
    --enable-mtp \
    --speculative_config '{"method": "mtp", "num_speculative_tokens": 1}' \
    --kv-transfer-config '${KV_TRANSFER_CONFIG}' \
    --additional-config '${ADDITIONAL_CONFIG}' \
    ${EXTRA_ARGS}

Global_Proxy负载均衡器

⚠️ **GitHub.com Fallback** ⚠️