从“能下载”到“能长期运行” #
前两篇介绍了 架构与原理 和 部署使用。实验能下载后,接下来要回答:数据能保留多久、谁能访问、哪里会成为瓶颈、失败时是否还有退路,以及如何证明节省了源站流量。
本文仍以 Chart 1.7.0、控制面 v2.5.0、客户端 v1.4.0 为学习基线。生产环境要使用经过自身验证的版本与配置,不能把实验中的单副本、临时存储和固定示例密码照搬过去。
一、先确认业务是否适合 P2P #
P2P 比较适合多台节点在一段时间内下载相同的大文件。它以节点磁盘、上传带宽和调度开销,换取更少的源站及跨网络重复传输。
如果源站很近、客户端带宽很低,或者下载时间主要花在解压和应用初始化上,收益就可能有限。因此要先测瓶颈,而不是默认安装 Dragonfly 后 Pod 一定启动更快。
跨机房流量昂贵时,还要考虑 Peer 之间是否跨机房传输。减少源站出口不代表一定减少跨区费用,需要合理安排 P2P 集群、位置配置与 Seed。
二、缓存不是文件的唯一存储 #
普通缓存会因为 TTL、磁盘压力、Pod 重建或磁盘故障而消失。storage.keep 只影响相应的重启保留行为,并不能代替持久卷,也不能阻止正常 GC。
例如,数据目录挂在 emptyDir 上,重建 Pod 后即使配置 keep,也不能指望旧缓存还在。改用 hostPath 或 PVC 后,还需要确认权限、节点归属和元数据恢复是否正常。
容量可以先按下面的思路估算:
缓存容量 ≈ 希望保留的热点内容
+ 新版本或预热的临时占用
+ 并发下载中的数据
+ GC 和故障处理所需余量
要看的是去重后实际内容和访问周期,而不是把所有镜像的显示大小简单相加。磁盘已满后才触发处理往往太晚,应提前观察使用率、写入延迟、inode 和 GC 情况。
TTL 也不是磁盘配额。 即使配置保留 30 天,磁盘压力回收仍可能更早删除缓存;反过来,保留时间较短也不保证磁盘始终有足够空间。
三、任务标识决定缓存能不能复用 #
预热成功却仍然回源时,先检查两次请求是否被识别为同一个任务:
- URL、tag、application、分片相关参数是否一致?
- 是否启用了相同的 blob digest 识别方式?
- 临时签名参数的过滤方式是否相同?
- 两个客户端是否进入同一个 P2P 集群?
- 原缓存是否已被回收,或者持有它的节点是否不可达?
不要为了提高命中率就删除所有 query 参数。例如,?version=1 和 ?version=2 可能就是不同内容;把它们忽略后会错误共享缓存。
也不要因为换一个输出文件名就认为创建了新任务:输出路径与内容身份不是同一件事。验证冷下载时,应使用明确的新内容身份或隔离测试环境。
四、区分三层认证与两段 TLS #
| 层次 | 控制什么 | 不能替代什么 |
|---|---|---|
| Registry / 源站认证 | 是否有权读取原始镜像或文件 | 不等于 P2P 内部服务已经隔离 |
| Manager 管理 API 认证 | 是否允许提交管理、预热等操作 | 不等于具有镜像仓库拉取权限 |
| Peer / 代理访问控制 | 谁能调用本地代理或节点服务 | 不能单靠 Kubernetes namespace 自动实现 |
同一个 P2P 网络里的节点可能共享内容,因此要根据实际信任边界设计网络和任务隔离。内容摘要用于判断字节是否匹配,不用于证明请求方有权限读取。
TLS 也有不同路径:客户端到本地代理、dfdaemon 到上游仓库、Peer 之间以及管理控制连接。某一段信任了 CA,不代表其他连接也自动信任。
遇到私有 CA 错误,应把 CA 配置到实际发起那段连接的进程。不要把长期关闭证书验证当成通用修复。若使用 HTTPS 代理拦截能力,还要明确代理 CA 的信任与密钥管理;它与普通 Registry mirror 接入不是同一个配置问题。
五、网络通了,不代表地址配置正确 #
组件通常既有监听地址,也有向其他节点公告的地址。监听在 0.0.0.0 表示接收连接,不表示别人应该连接 0.0.0.0;公告为 127.0.0.1 则会让远端节点连到它自己。
以本文客户端基线为例,需要按启用功能检查这些通信方向:
| 方向 | 用途 | 常见端口 |
|---|---|---|
| Client / Scheduler → Manager | 发现、注册、配置 | TCP 65003 |
| Client → Scheduler | 下载调度与状态报告 | TCP 8002 |
| Scheduler / Peer → Peer 或 Seed | 上传控制、元数据及相应 RPC | TCP 4000 |
| Peer → Parent | 分片字节传输 | TCP 4005;启用 QUIC 时另有 UDP 4006 |
| 本机运行时 → 本机代理 | Registry / HTTP 代理入口 | TCP 4001 |
| 回源方 → 源站 | 获取原始内容和认证相关请求 | 按源站协议,常见 80/443 |
端口以实际配置和渲染清单为准,不是所有功能都必须开启。只检查 Scheduler 的 Service 可达,不能证明 Peer 之间的分片传输可达;只开放 TCP,也不能证明启用的 QUIC 可用。
网络策略还要允许必要的 DNS、Registry Token 服务和重定向目标。预热接受外部 URL 时,应限制调用权限及可访问目标,避免下载服务被用于访问不应开放的内部地址。
六、带宽、磁盘和并发要一起看 #
一个 dfdaemon 可能同时从其他节点下载、向多个节点上传,并服务本机 containerd。它会与业务共享 NIC、磁盘和 CPU。
把并发提高一倍,不代表速度提高一倍。磁盘已经饱和时,更多分片可能增加排队;上传不设限时,也可能挤占业务出口。
推荐按这个顺序调整:
- 先测当前网络和磁盘吞吐,找出真正限制。
- 分开考虑下载、上传、回源和预取的限制。
- 每次只调整少数参数,保留前后对照结果。
- 看整体耗时及失败率,不能只看短时峰值带宽。
Seed 需要特别关注冷启动高峰:新版本第一次发布时,热点缓存尚未扩散,压力更可能集中在 Seed 和源站。预热应安排在业务高峰之前,并限制后台流量,避免预热反而影响线上请求。
七、多副本解决哪些问题 #
| 组件 | 多副本的价值 | 仍需考虑的事情 |
|---|---|---|
| Manager | 减少单个管理实例故障影响 | 共享数据库、Redis、管理入口和数据备份 |
| Scheduler | 提高调度服务可用性与处理能力 | 客户端重连、任务归属和状态恢复,不是自动同步全部普通任务内存 |
| Seed | 分摊回源和首次扩散压力 | 缓存分布、磁盘、拓扑和源站容量 |
| 每节点 Client | 服务本节点并参与内容交换 | 单节点磁盘和网络故障,本机代理故障对拉镜像的影响 |
Scheduler 的普通任务关系主要是实例内状态,故障后可能需要客户端重连和重新登记。不能把“三个副本”理解为每份任务状态都已经有三份同步副本。
同样,有回源配置也不等于任何故障都能无缝恢复:运行时直连回退和 Dragonfly 自身回源是两层机制,触发条件及超时不同。应该在测试环境实际演练,确认源站能否承受回退高峰。
八、怎样判断加速是否有效 #
至少分别测四种情况:
| 场景 | 测到什么 |
|---|---|
| 新任务、P2P 无缓存 | 首次获取和扩散成本 |
| 本机无缓存、其他节点有缓存 | 跨节点共享收益 |
| 本机已有 Dragonfly 缓存 | 本地缓存收益 |
| containerd 已有镜像层 | 可能根本不发生下载,不能当成 P2P 收益 |
每组测试保持内容、节点数量、并发和网络条件尽量相同,记录:
- 总耗时和尾部耗时,例如最慢一批节点需要多久完成。
- 下载成功率、重试和超时数量。
- 源站、Seed 和普通 Peer 的发送字节数。
- 节点 NIC、CPU、磁盘吞吐与延迟。
- 下载完成后的镜像解压时间和 Pod Ready 时间。
可以用“回源字节 / 总下载字节”帮助判断流量来源,但要统一统计窗口和口径:预热流量、历史缓存、重复尝试及控制请求都可能影响结果。
源站发出数据少了,但某些节点更慢,可能说明瓶颈转移到了 Peer 上传或磁盘;总拉取时间短了,但 Pod Ready 没变,则继续检查解压、init 容器和应用启动。
九、按请求阶段排障 #
不要一开始就调并发或重启全部组件。先确定请求在哪个阶段失败,再找对应日志。
| 现象 | 优先检查 |
|---|---|
| dfget 无法连接 dfdaemon | 进程是否运行、socket 路径和权限、调用者是否能访问 socket |
| containerd 没有进入本地代理 | 生效的 CRI 配置、hosts.toml、代理地址,以及镜像是否已在 containerd 缓存 |
| 找不到 Scheduler | Manager/本地动态配置、DNS、集群 ID、地址与证书 |
| 有候选父节点但读不到分片 | 公告地址、Peer 间端口、父节点状态、协议及防火墙 |
| 401 / 403 | 实际回源请求的凭据、权限与 Token 服务,不要只看管理 API 登录状态 |
| 404 | URL、上游 Registry、镜像路径、digest 和重定向 |
| 429 | 源站或代理限流,是否遵守退避;避免用更多重试放大压力 |
| 摘要不匹配 | 内容是否变动、任务标识是否冲突、来源和磁盘;不要继续信任错误缓存 |
| 预热成功但真实拉取回源 | 任务标识、集群、GC、真实请求入口是否一致 |
| 一开始快,随后持续卡顿 | 某些慢分片、热点父节点、磁盘排队和上传限速 |
| Pod Running 但应用未就绪 | 就绪探针和应用依赖,未必仍是 Dragonfly 下载问题 |
一条请求最好保留时间、URL(脱敏)、task ID、peer ID、节点、候选父节点和具体错误。不要把 Token、签名 URL、Authorization 头直接粘贴到公共日志或工单。
十、上线和升级时保留退路 #
先在少量节点验证,再扩大范围。保存运行时原配置、Chart 版本、镜像版本和实际 values,升级前检查发行说明与配置变更,不在同一次变更里同时改版本、拓扑、缓存策略和并发。
回退时不仅考虑 Helm release,还要考虑数据库迁移、客户端缓存格式和主机配置是否兼容。回退 Helm 不能保证回退已经执行的数据库或主机修改。
特别是 dfinit 接入后,应先验证如何恢复直接拉取,再进行全量推广。卸载前先解除运行时对本地代理的依赖,避免组件卸载后新的 Pod 反而无法拉镜像。