# 缓存与用量

SparkCR 是 pull-through cache。首次请求通常需要回源，后续请求会逐步命中 Manifest 缓存和 Blob 缓存。[Dashboard](/dashboard)、[History](/history) 和响应头可以帮助判断当前请求是否走到了缓存。

## 缓存状态

拉取历史和响应头中的缓存状态通常有这些含义：

| 状态 | 含义 |
| --- | --- |
| `HIT` | 命中缓存。 |
| `MISS` | 首次回源或缓存中没有该对象。 |
| `EXPIRED` | 缓存已过期，已重新验证或回源。 |
| `BYPASS` | 未缓存，直接流式代理。 |

Manifest 通常比 Blob 更早命中。Blob 首次 miss 时会流式返回给客户端，并在满足大小、完整请求和缓存水位等条件时写入持久化缓存。

## 为什么第一次拉取较慢

第一次拉取一张镜像时，SparkCR 需要访问公共镜像仓库获取 manifest 和 layer blob。这个过程受上游网络、上游限流、镜像大小和当前缓存水位影响。

后续拉取可能更快，原因包括：

- Manifest 已在缓存中。
- 热 blob 已提升到持久化缓存。
- 命中缓存后可减少公共镜像仓库请求。
- 配置了交付策略时，已缓存 blob 可走更合适的下载路径。

## 预热

平台可对常用镜像启用预热。预热会提前拉取配置中的 manifest，减少首次解析镜像标签的延迟。

预热的边界：

- 预热主要写入 Manifest 缓存。
- 不会主动下载镜像的全部 blob layer。
- 不会为预热请求记录用户 Pull History。
- 不会扣减用户配额。

如果某张镜像已经在预热列表中，但首次拉取仍有 blob miss，这是正常现象。

## 配额与限流

SparkCR 会按匿名 IP、登录用户、来源组和套餐等维度应用配额。匿名拉取可用，但共享出口 IP 的 CI、NAT 或集群更容易触发匿名配额。

建议：

- 长期使用时登录 SparkCR 镜像仓库。
- CI 为每个项目或 runner 创建独立 [Access Token](/tokens)。
- 公共镜像只授予 `pull:public`。
- 私有镜像按需授予 `pull:private` 和 `push`。
- 降低同一时间的大规模并发冷拉取。

收到 `429 Too Many Requests` 时，检查 [控制台](/dashboard) 中的今日用量和响应里的 `X-RateLimit-*` 头。

## 查看用量

在控制台中优先查看：

| 页面 | 用途 |
| --- | --- |
| [Dashboard](/dashboard) | 当前配额、总请求、流量和缓存命中率。 |
| [History](/history) | 最近拉取记录、上游、镜像、状态码、缓存状态和字节数。 |
| [Private Registries](/settings/private-registries) | 私有上游的拉取和推送用量。 |

排查问题时保留这些信息：

- 完整镜像引用。
- runtime 类型和版本。
- SparkCR 访问模式：路径前缀或别名入口。
- HTTP 状态码和错误信息。
- `X-SparkCR-Cache`、`X-RateLimit-*` 响应头。
- 对应的 Pull History 或私有上游用量记录。
