序言
随着模型权重的体积不断增大,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生产力的有效基础设施。

656

被折叠的 条评论
为什么被折叠?



