构建私有制品中心:huggingface模型权重缓存实践

序言

        随着模型权重的体积不断增大,HuggingFace镜像缓存在企业级应用中正成为一项关键需求。这主要基于三点考量:首先,镜像仓库是国内下载模型权重的主要来源,企业若以固定IP持续大量访问,可能面临速率限制的风险。其次,企业私有专线的带宽容量直接制约了下载速度,而专线成本日益攀升。带宽本身作为稀缺资源,在模型权重呈几何级数增长的背景下,将迅速被消耗殆尽。最后,智能体构建的速度是AI企业核心竞争力的体现,这高度依赖于模型权重的快速获取与部署。

        为应对上述挑战,本文将引入DingoSpeed作为构建HuggingFace私有镜像服务的核心底座,旨在优化资源利用,保障获取效率,从而为后续的实践部署奠定基础。

1 DingoSpeed简介

        DingoSpeed本质上是一个可以部署在私有环境的Hugging Face镜像加速服务。把它想象成给团队或实验室内部搭建的一个专属“模型下载中转站”——所有人访问HF仓库的流量都先经过它。

        这个方案的运作机制很好理解,核心是解决两个常见问题:一是从外网直接下载大型模型时速度缓慢且不稳定;二是同一模型在团队内被多人重复下载时,造成的带宽浪费和时间消耗。

        它的工作流程分为两步:

        第一次有人请求某个模型时,DingoSpeed会代理这次下载,从上游(官方HF或已配置的镜像站)获取文件,并在返回给用户的同时,把文件保留在本地服务器上形成缓存。

        之后任何人再需要同一个模型时,请求就会被直接导向本地缓存,不再需要访问外网。这意味着后续下载速度可以达到局域网带宽上限,同时显著降低对外部网络的依赖和流量开销。

        这个工具有两个比较实用的特点:

        第一是它完全兼容Hugging Face官方的客户端协议,使用起来非常简单,只需要在运行模型的机器上设置一个环境变量(HF_ENDPOINT),指向DingoSpeed的服务地址,原来的下载代码或命令就能直接生效,不需要做其他改动。

        第二是它设计时考虑了团队使用的场景,支持多台服务器组成集群来分摊负载,也提供了缓存空间管理、访问统计等适合多人协作的功能。

2 运行环境

        ·操作系统:BigCloud Enterprise Linux 8.2

        ·内核:5.10.0-200.el8_2.bclinux.x86_64

        ·docker: 24.0.9

        ·docker-compose: v2.26.1

3 dingospeed服务端镜像构建

3.1 下载源码

        git clone -b main https://github.com/dingodb/dingospeed.git

        git checkout d385f6d

3.2 修改Dockerfile

        dingospeed/docker/Dockerfile定义了服务端镜像的构建指令。为支持在构建过程中通过代理访问外部资源,我们对原始文件进行了关键修改,主要涉及代理环境变量的设置与清理,修改点已用注释标出。

# dingospeed/docker/Dockerfile

# 注意:需要拷贝该文件到源码根路径下构建:dingospeed/

FROM golang:1.23.0 AS builder

LABEL stage=gobuilder

ENV CGO_ENABLED=0

ENV GOPROXY=https://goproxy.cn,direct

ENV http_proxy=http://192.168.1.1:7890

ENV https_proxy=http://192.168.1.1:7890

ENV HTTP_PROXY=http://192.168.1.1:7890

ENV HTTPS_PROXY=http://192.168.1.1:7890

ENV GO111MODULE=on

WORKDIR /app

RUN git config --global http.proxy http://192.168.1.1:7890 && \

    git config --global https.proxy http://192.168.1.1:7890

# 【注意】当前docker不再支持COPY .. .的复制命令,会导致COPY failed: forbidden path outside the build context: .. (),试图复制构建上下文之外的父目录。Docker 的安全策略禁止该操作,同时应将当前Dockerfile拷贝到上级路径,也就是dingospeed源码根路径下再进行构建。

COPY . .

# Installation of dependency packages and environment preparation

RUN go install github.com/google/wire/cmd/wire@latest

RUN cd cmd/ && wire gen ./...

RUN go mod tidy

RUN go get github.com/google/wire/cmd/wire@latest

RUN go generate ./...

RUN mkdir "repos"

# Compile Go project and generate executable file

RUN mkdir -p bin/ && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$(VERSION)" -o ./bin/dingospeed dingospeed/cmd

# 清理git代理配置,避免代理被打入镜像中

RUN git config --global --unset http.proxy && \

    git config --global --unset https.proxy

# Expose the 8090 port of the container for external access

EXPOSE 8090

VOLUME /app/repos

VOLUME /app/log

# 设置健康检查

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \

  CMD wget --no-verbose --tries=1 --spider http://localhost:8090/health || exit 1

CMD ["./bin/dingospeed"]

3.3 镜像构建

        应确保docker运行时环境启用代理,以拉取构建所需的基础镜像,再执行构建:

docker build -t dingofs/dingospeed:2025 -f Dockerfile .

3.4 config.yaml配置文件

        采用standalone(单机)模式部署,关键配置如下:

# dingospeed/docker/config/config.yaml

server:

    mode: debug

    host: 0.0.0.0

    port: 8090

    pprof: false # 是否启用go语言的性能分析工具pprof,因前期发现漏洞已关闭

    pprofPort: 6060

    metrics: false # 指标收集

    online: true # true表示本地找不到,去hfNetLoc地址查找并下载模型数据,否则直接返回找不到

    repos: ./repos # 模型数据在本地存储的仓库路径

    hfNetLoc: hf-mirror.com # 主用模型镜像站地址

    bpHfNetLoc: hf-mirror.com # 备用模型镜像站地址

    hfScheme: https

    ssl:

        keyFile: ./config/ssl/client.key

        crtFile: ./config/ssl/client.crt

        caFile: ./config/ssl/ca.crt

scheduler:

    mode: standalone   # 运行的两种模式:standalone、cluster,默认为standalone

    addr: 192.168.1.2:19091 # 调度器地址,未使用

    strategy:

        minimumFileSize: 0 # 文件参与调度最小尺寸,单位字节,0表示无限制

        syncProcessInterval: 100 # 同步下载进度的间隔,默认是1个块同步1次。

    discovery:

        instanceId: hf-local-inst # 实例唯一标识

        host: 192.168.1.2 # 用于注册到服务发现

        port: 8090 # 用于注册到服务发现

        heartbeatPeriod: 5 # 向服务注册中心发送心跳周期,单位秒

    publicDomain: http://hf-mirror.local:8082 # 对外发布的域名,不使用

download:

    blockSize: 8388608 # 默认文件块大小为8MB(8388608),单位字节,1048576(1MB)

    reqTimeout: 0 # 远端请求超时时间,单位秒,默认为0,不超时。

    respChunkSize: 2048 # 默认对响应结果的读取大小8192,单位字节。

    respChanSize: 30 # 响应队列大小

    remoteFileBufferSize: 8388608 # 每个分区文件的结果Queue的缓存大小,即当前文件下载时,缓存8MB的数据

    remoteFileRangeSize: 0 # 按照这个长度分块下载,0为不切分,测试选项:8388608(8M),67108864(64M),134217728(128M),536870912(512M),1GB(1073741824)

    remoteFileRangeWaitTime: 0 # 每个分区文件下载任务提交时间间隔,单位(ms)。

    goroutineMaxNumPerFile: 8 # 远程下载任务启动的最大协程数量

cache:

    defaultExpiration: 30 # 缓存默认过期时间,单位分钟

    cleanupInterval: 40 # 缓存默认清理时间,单位分钟

    readBlock:

        enabled: false # 是否启用缓存

        collectTimePeriod: 5 # 定期检测内存使用量时间周期,单位秒(S)

        prefetchMemoryUsedThreshold: 90 # 当内存使用量达到该值,将不会预读取,不缓存数据块

        prefetchBlocks: 16 # 离线下载时,预先读取块的数量

        prefetchBlockTTL: 30 # 离线下载时,预先读取块的存活时间,单位秒(S)

    mountModelDir: /app/public

retry:

    delay: 1 # 重试间隔时间,单位秒,默认为1

    attempts: 3 # 重试次数,默认为3

log:

    maxSize: 20 # 日志文件最大的尺寸(MB)

    maxBackups: 10 # 保留旧文件的最大个数

    maxAge: 90 # 保留旧文件的最大天数

tokenBucketLimit:

    handlerCapacity: 50 # 提交处理任务的超时时间

diskClean:

    enabled: false

    cacheSizeLimit: 41781441855488 # 缓存目录的总大小限制(单位:字节),此处约为 38 TB

    cacheCleanStrategy: "LRU" # LRU,FIFO,LARGE_FIRST

    collectTimePeriod: 1 # 定期检测磁盘使用量时间周期,单位小时(H)

dynamicProxy: # 访问后端HF镜像站点时使用代理,务必启用

    enabled: true

    httpProxy: http://192.168.1.1:7890

    httpProxyName: "noname"

    timePeriod: 60

    maxContinuousFails: 5

    

3.5 docker-compose.yml部署清单

        修改docker-compose.yml文件,定义服务、卷挂载和网络。注意:当前方案中,dingospeed到上级HF镜像站点需要走代理。

# dingospeed/docker/docker-compose.yml

services:

  dingospeed:

    image: dingofs/dingospeed:2025

    container_name: dingospeed

    environment:

      - TZ=Asia/Shanghai

      - HTTP_PROXY=http://192.168.1.1:7890

      - HTTPS_PROXY=http://192.168.1.1:7890

      - NO_PROXY="localhost,127.0.0.1"

    ports:

      - "${ADDITIONAL_IP_1:-127.0.0.1}:8090:8090"

    volumes:

      - ./repos:/app/repos

      - ./config/config.yaml:/app/config/config.yaml

      - ${CERT_PATH:-/data/labs/certs}/tls.crt:/app/config/ssl/client.crt

      - ${CERT_PATH:-/data/labs/certs}/tls.key:/app/config/ssl/client.key

      - ${CERT_PATH:-/data/labs/certs}/ca.crt:/app/config/ssl/ca.crt

      - ./log:/app/log

      - ./public:/app/public

    restart: always

    cpus: '8'

    mem_limit: '50g'

    networks:

      - dingospeed

networks:

  dingospeed:

    driver: bridge

    ipam:

      config:

        - subnet: 172.90.38.0/24

          gateway: 172.90.38.1

          ip_range: 172.90.38.0/28

4 huggingface客户端镜像(用于测试)

4.1 修改Dockerfile

我们基于Alpine Linux构建一个轻量级测试客户端,预装huggingface-hub等必要工具。

# dingospeed/docker/Dockerfile-alpine

FROM alpine:3.20

ENV http_proxy=http://192.168.1.1:7890

ENV https_proxy=http://192.168.1.1:7890

ENV HTTP_PROXY=http://192.168.1.1:7890

ENV HTTPS_PROXY=http://192.168.1.1:7890

# 安装核心依赖(Alpine 包名与 Ubuntu 不同)

RUN apk --no-cache add \

    python3 \

    py3-pip \

    py3-setuptools \

    ca-certificates \

    tzdata \

    git \

    && rm -rf /var/cache/apk/*

# 可选:设置时区

ENV TZ=Asia/Shanghai

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 安装 huggingface-hub(指定版本)

RUN pip3 install --no-cache-dir --break-system-packages huggingface-hub==1.2.3

RUN pip3 install --no-cache-dir --break-system-packages hf_transfer==0.1.9

RUN pip3 install --no-cache-dir --break-system-packages hf-xet==1.2.0

# 设置运行时环境变量(取消代理)

ENV http_proxy=""

ENV https_proxy=""

ENV HTTP_PROXY=""

ENV HTTPS_PROXY=""

# 验证安装

RUN hf version

CMD ["/bin/sh"]

4.2 构建客户端镜像

        docker build -t huggingface-hub:alpine-1.2.3 -f Dockerfile-alpine .

4.3 docker-compose.yml部署清单

        在docker-compose.yml中增加客户端服务,关键是将HF_ENDPOINT环境变量指向我们部署的DingoSpeed服务地址(http://<dingospeed-host>:8090)。

services:

  hfclient:

    image: huggingface-hub:alpine-1.2.3

    container_name: hf-client

    restart: unless-stopped

    environment:

      - HF_ENDPOINT=http://192.168.1.2:8090

      - HF_HUB_DISABLE_TELEMETRY=1 # 禁用遥测,不向Hugging Face发送使用统计信息

      - HF_HUB_OFFLINE=0 # 1:强制离线模式,只从本地缓存读取,0:在线模式,允许从远程下载

      # 控制是否自动创建符号链接来管理大型文件

      - HF_HUB_LOCAL_DIR_AUTO_SYMLINK_THRESHOLD=0

      - HF_HOME=/root/.cache/huggingface # 设置 Hugging Face 的根缓存目录

      # 专门设置 Transformers 库的模型缓存目录

      - TRANSFORMERS_CACHE=/root/.cache/huggingface/hub

      # 设置 Hugging Face Hub 客户端的缓存目录

      - HUGGINGFACE_HUB_CACHE=/root/.cache/huggingface/hub

      - TZ=Asia/Shanghai

    volumes:

      # 挂载本地缓存目录,避免重复下载

      - ./hf-cache:/root/.cache

      # 挂载数据目录,用于存储下载的模型

      - ./models:/models

      # 挂载脚本目录,方便执行自定义命令

      - ./scripts:/scripts

      # 挂载工作目录

      - ./workspace:/workspace

    working_dir: /workspace

    healthcheck:

      test: ["CMD", "python3", "-c", "import huggingface_hub; print('OK')"]

      interval: 30s

      timeout: 10s

      retries: 3

      start_period: 10s

    stdin_open: true  # 允许交互

    tty: true         # 分配伪终端

    logging:

      driver: "json-file"

      options:

        max-size: "10m"

        max-file: "3"

    deploy:

      resources:

        limits:

          memory: 2G

        reservations:

          memory: 512M

    command: ["/bin/sh"]

    networks:

      - dingospeed

networks:

  dingospeed:

    driver: bridge

    ipam:

      config:

        - subnet: 172.90.38.0/24

          gateway: 172.90.38.1

          ip_range: 172.90.38.0/28

5 验证

        启动所有服务后,进入客户端容器进行下载测试。

        1、首次下载:由于需要从上游(hf-mirror.com)拉取并缓存,速度受限于公网带宽,实测约为20MB/s。

        2、再次下载:文件已存在于DingoSpeed本地缓存中,下载速度达到内网极限,实测可稳定在200MB/s左右,加速效果显著。

/workspace # hf download --force-download stabilityai/stable-video-diffusion-img2vid-xt

Downloading (incomplete total...):  30%|██████████████████▍                                          | 9.84G/32.6G [00:52<01:57, 193MB/s]

Fetching 19 files:  37%|██████████████████████████████▏                                                   | 7/19 [00:45<01:42,  8.51s/it]

6 问题分析

        实践过程中遇到的问题大致如下:

        一、目前只验证通过了HTTP端口8090,虽然配置了证书但HTTPS端口不知如何启用。

【答】貌似已不再支持,套一层NGX解决。

        二、dingospeed容器的状态为unhealthy,经分析发现实际健康检查/health已失效:

docker inspect dingospeed --format='{{json .Config.Healthcheck}}' | jq

返回内容:

{

  "Test": [

    "CMD-SHELL",

    "wget --no-verbose --tries=1 --spider http://localhost:8090/health || exit 1"

  ],

  "Interval": 30000000000,

  "Timeout": 3000000000,

  "StartPeriod": 5000000000,

  "Retries": 3

}

【解决方案】在docker-compose.yml 中配置新的HealthCheck,以覆盖镜像中失效的HealthCheck

    healthcheck:

      test: ["CMD-SHELL", "pgrep dingospeed"]  # 检查进程是否存在

      interval: 30s

      timeout: 10s

      retries: 3

7 总结

        通过本文的实践,我们成功利用DingoSpeed在企业内部搭建了一套私有的HuggingFace镜像缓存服务。该方案有效解决了直接公网下载模型时面临的速度限制、带宽浪费、稳定性差三大核心痛点。

        对于中大型团队或需要频繁使用多种AI模型的场景,建议将DingoSpeed与对象存储(如S3兼容存储)结合,将缓存目录挂载至共享存储,实现缓存的持久化与跨节点共享。同时,可结合CI/CD流水线,将常用模型预缓存至服务中,进一步实现“开箱即用”。

        总而言之,DingoSpeed私有镜像方案是构建企业级AI制品中心的关键第一步,它以一种轻量化、非侵入的方式,优化了模型资产的管理与分发效率,是提升团队整体AI生产力的有效基础设施。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值