{{i18nTranslate('_layout.t11')}} {{i18nGetLang()==='zh' ? 'EN' : '中文'}}

# 缓存

## 设置缓存

可以在网站”设置” – “缓存”中设置本服务是否开启缓存，以及缓存的条件：

如果想添加某个URL或者某个条件 不 缓存，可以点击”添加不缓存条件”进行添加。

## 缓存示例

### 缓存首页示例

1. 点击”添加缓存条件”按钮
2. 选择条件类型：”首页”
3. 点击表单底部的”确定”按钮

添加后的效果类似于：

### 缓存某个特定URL示例

比如要缓存 `/cms/index.html` 这个URL：

1. 点击”添加缓存条件”按钮
2. 选择条件类型：”URL精准匹配”
3. URL完整路径：`/cms/index.html`
4. 点击表单底部的”确定”按钮

添加后的效果类似于：

### 缓存某个目录下的所有文件

比如要缓存 `/cms/` 目录下的所有HTML文件：

1. “添加缓存条件”按钮
2. 点击”切换到复杂条件”
3. 点击”添加分组”
4. 添加子条件表单中：
   1. 选择条件类型：”URL前缀”
   2. URL前缀：`/cms/`
   3. 一路点击”确定”按钮
5. 再次添加”添加子条件”，在新的添加子条件表单中：
   1. 选择条件类型：”URL扩展名”
   2. 添加扩展名：`html`、`htm`

添加后的效果类似于：

### 缓存某些扩展名示例

比如要缓存 `png`、`jpeg`、`jpg`、`gif`、`webp` 等图片内容：

1. “添加缓存条件”按钮
2. 选择条件类型：”URL扩展名”
3. 添加扩展名：`png`、`jpeg`、`jpg`、`gif`、`webp`

添加后的效果类似于：

### 音视频缓存示例

音视频有其特殊性，因为播放器可以设置开始读取的文件位置，所以大部分情况下都是支持区间读取的（别的文件格式通常都是从头开始下载完整文件）。在区间读取的过程中，请求客户端（比如浏览器）通过`Range: bytes=from-to` 来发送要读取的内容区间，服务器端通过 `206 Partial Content` 发送客户端要读取的内容，并通过 `Content-Range: bytes from-to/total` 来告诉客户端返回的内容起始位置、结束位置。

以下以缓存 `mp3`、`mp4`、`m4a`、`ts` 等文件扩展名为例，讲述如何缓存区间缓存文件：

1. 点击”添加缓存条件”按钮
2. 选择条件类型：”URL扩展名”
3. 添加扩展名：`mp3`、`mp4`、`m4a`、`ts`
4. 添加缓存设置表单中 – “更多选项” – 选中”支持缓存区间内容” 并点击”确定”

添加后的效果类似于：

### 缓存gzip文件

通常情况下，是默认缓存 `gzip` 压缩后的内容的，如果你的某个URL没有缓存，请检查是否已经在缓存设置表单中 – “更多选项” – 选中了”支持分片内容”。

## 文件缓存性能指南

建议使用SSD硬盘可以显著提升文件的写入和读取速度。

使用文件缓存时，可以设置”内存最大容量”，如果此值大于0，则缓存在创建时会优先写入内存，然后再定期导入硬盘。如果设置了内存容量，系统也会定期将热点内容写入内存，以提升性能。

### 缓存文件句柄缓存

从v0.4.0开始，可以设置”缓存文件句柄缓存”来显著提升缓存文件的打开速度，设置了缓存文件句柄后，缓存文件打开后，会将句柄放入到缓存后，不立即关闭，等待下次需要打开时，直接使用即可。为了不消耗过多内存和影响系统其他应用运行，句柄数量不宜过多，通常可以设置为缓存文件总数的10%以内。此值不受系统`ulimit`的影响，但是会占用系统文件打开数量。

### Sendfile

> 此功能为商业版功能

从v0.4.7开始，可以在文件类型的缓存策略中设置`开启Sendfile`选项，来有效提升发送缓存文件的效率。开启后，节点将会在合适的时机使用系统sendfile指令发送文件，减少内存拷贝。

## 使用客户端缓存

可以在缓存条件中，设置”客户端过期时间”：

启用后，可以自动生成Expires Header，客户端浏览器识别后会自动将内容缓存在客户端，下次访问时无需发送请求到服务器即可获取内容，节省了服务器的流量。

客户端缓存缺点是无法在服务器端直接刷新缓存，如果想要缓存失效，通常需要通过修改URL链接的方式。

## 使用过时缓存

> 此功能为商业版功能

从v0.3.7以后，可以在缓存设置中”设置”–“更多选项”–“过时缓存策略”中启用过时缓存，启用后，当源站无法访问时就可以使用已过时（已过期）的缓存：

其中：

- `有效期` - 缓存在过期之后，仍然保留一段时间不会被删除，用于在源站出错时使用；
- `状态码` - 通常的状态码可以为`500`、`502、`503`、`504`等；如果不设置，则包含这些常见的状态码；
- 支持`stale-if-error` - 选中后，源站的发送的响应的Header中可以通过Cache-Control设置过时缓存的有效期；如果一个URL不允许使用过时缓存，就可以设置：`Cache-Control: stale-if-error=0`

注意：开启过时缓存后，意味着缓存会被保留更长的时间，会占用更多的空间。

## 缓存状态

可以在浏览器端或者访问日志中查看响应Header中的`X-Cache`字段来确定缓存状态（前提是已经在服务缓存设置中选中了”添加X-Cache” Header）；如果使用浏览器查看的时候，需要禁用浏览器缓存，以便于更好地观察。

浏览器查看X-Cache示例：

日志详情示例：

下面我们列出常见的`X-Cache`值和对应的说明，方便用户排除问题：

- `HIT` - 命中缓存
- `STALE` - 正在使用过期的缓存（源站无法读取的时候使用过期缓存）
- `UPDATING` - 正在更新缓存
- `BUSY` - 服务器正忙，无法读取或写入缓存（GoEdge v1.3.7中加入）
- `BYPASS` - 跳过缓存设置，可能原因是：
  - 如果没有附加说明，则表示当前请求没有匹配到任何缓存条件；
  - `not supported partial content` - 不支持`206 Partial Content`内容，如果想启用对此内容的缓存，需要在对应的缓存条件中启用”支持缓存区间内容”；音视频、文件下载等内容最有可能遇到这种情况；
  - `ChunkedEncoding` - 不支持分块传输内容，如果想启用对此内容的缓存，需要在对应的缓存条件中启用”支持分片内容”
  - `Content-Length` - 内容长度过大或者过小，请检查缓存条件中对缓存内容尺寸的设置是否满足当前请求内容的尺寸要求
  - `Status: xxx` - 状态码不匹配，如果要支持此状态码，可以在对应的缓存条件中添加状态码列表（注意`304`是一个特殊的状态码，不要轻易添加，除非你对HTTP协议非常了解）
  - `Cache-Control` - 源站返回的`Cache-Control`设置不符合缓存条件，可以在对应的缓存条件中修改”跳过的Cache-Control值”
  - `Set-Cookie` - 源站返回了`Set-Cookie` Header导致无法缓存，可以在对应的缓存条件中修改”跳过Set-Cookie”设置
  - `ResponseConds` - 源站返回内容不满足其他响应条件
  - `Storage` - 无法找到缓存对应的存储引擎
  - `entity too large` - 要缓存的内容过大
  - `too many requests` - 当前并发缓存的内容过多，通常在硬盘性能不佳导致IO过高或者写缓存文件过慢时才会提示；如果内容是分段（`206 Partial Content`）发送给客户端的，为了避免瞬间写入硬盘的内容过快，同样也会出现这个提示
  - `the file is writing` - 有别的网络连接正在写入同一个缓存文件，忽略本次缓存更新；
  - `write cache failed` - 写入缓存失败，可以在节点运行日志中查询具体的错误描述

## 清除缓存

### 通过管理界面清除缓存

可以在网站”设置” – “缓存” – “清理”功能中清理一组URL对应缓存:

通常是每行一个URL。如果你在缓存条件中修改了Key的生成方式，也需要在这里做出对应的修改。

“根据前缀”的选项让我们可以轻松删除一组带有同样前缀的缓存URL：

这样以下URL缓存都会被自动清理：

    https://example.com/book/1.html
    https://example.com/book/2.html
    https://example.com/book/3.html
    https://example.com/book/4.html
    ...
    https://example.com/book/xxx.html

### 通过PURGE方法清除单个缓存

v0.3.3以后，可以通过PURGE方法清除单个URL对应的缓存：

1. 先在网站”设置” – “缓存”设置里选中”允许PURGE”，然后手工填入`PURGE Key`或者留空保存后自动生成；
2. 使用PURGE方法请求你要清除缓存的URL，并加入`X-Edge-Purge-Key` Header，值为步骤1中生成的`PURGE Key`：

       PURGE https://example.com/index.html HTTP/1.1
       X-Edge-Purge-Key: ...
       ...

   提交成功后，缓存就会被自动清除。

### 通过API批量清除缓存

v0.3.3以后，要想通过API清除缓存，需要：

1. 设置API节点支持REST方式调用：API节点设置
2. 获取访问令牌

然后调用API节点的 `/ServerService/PurgeServerCache` 在Header中加入获取到的令牌：

    POST http://192.168.1.100/ServerService/PurgeServerCache HTTP/1.1
    X-Edge-Access-Token: hGyDUHo9CiszUaTxf... THIS IS ACCESS TOKEN ...
    Content-Type: application/json
    ...

然后在内容中传递对应参数即可：

下面是使用Key清理示例：

    {
      "domains": [
    	"cdn.example.cn"
      ],
      "keys": [
    	"https://cdn.example.cn/html/hello.html",
    	"https://cdn.example.cn/images/world.jpg"
      ],
      "prefixes": []
    }

下面是使用前缀清理示例：

    {
      "domains": [
    	"cdn.example.cn"
      ],
      "keys": [],
      "prefixes": [
        "https://cdn.example.cn/html/",
        "https://cdn.example.cn/images/"
      ]
    }

其中：

- `domains` - 为要清除缓存的服务的域名列表，在v0.4.8以前需要，从v0.4.8及以后不再需要此字段
- `keys` - 要清除的缓存的Key，默认是完整的URL，和`prefixes`二选一
- `prefixes` - 要清除的缓存的Key前缀，和`keys`二选一

如果你有多个API节点，需要在每个API节点都调用这个API。

## L2节点缓存

从v0.4.7开始，如果边缘节点查找不到本地缓存时，可以使用L2节点回源，具体请参考L2节点。

## 节点缓存设置

可以在”节点设置”–“缓存设置”中定义节点专有的设置。

可以实现：

- 当前节点缓存硬盘容量限制；
- 当前节点硬盘主目录，不填的话表示使用缓存策略默认的目录；
- 当前节点其他硬盘缓存目录，如果当前节点硬盘有多个分区的话，可以考虑将其他分区填入到这里，以便支持更大的缓存空间（从v0.5.8开始）；
- 当前节点的内存缓存容量。

## 常见问题

### 文件缓存保存在那个目录？

默认保存在节点上 `/opt/cache` 目录下，单你在创建和修改 缓存策略 时可以更改这个目录。 另外，在某个节点设置–“缓存设置“中也可以单独指定当前节点缓存存放目录。

### 开启缓存后，网站中表单无法正常提交怎么回事？

可能你在配置缓存的时候，把提交表单的URL也设置成了匹配条件，所以被认为是可以缓存的，从而不会把提交的数据转发到源站。你可以：

1. 在缓存条件设置中排除这个URL；
2. 在缓存条件设置中，点击”更多选项”，填入请求方法限制，可以限制请求方法为HEAD和GET，这样通过POST方法提交的表单就不会被缓存干扰。

### 开启缓存后，节点上没有任何缓存文件生成

可以先查看节点日志，检查是否有报错信息；如果没有报错信息，通常没有缓存文件或者缓存内存使用的原因是还没有用户访问此节点上的网站，你可以模拟访问此节点上的网站进行测试。

### 可以预热某个扩展名的所有文件吗？

不可以，因为系统不知道完整的相关文件列表。

### 硬盘满了会自动清理吗？

会，会优先删除比较早期的缓存内容来保证系统一直有空间接纳新的缓存内容。

### 为什么我查看X-Cache一直是UPDATING？

如果同一个缓存内容的X-Cache状态一直是UPDATING，一般有以下几种可能的原因：

1. 你查看X-Cache时没有禁用浏览器缓存，导致看到的是浏览器缓存的结果，推荐用curl工具查看（`curl -v URL`）
2. 你每次查看X-Cache的URL不同或者含有`Range`报头而导致每次读取的内容范围不同
3. 你要下载的文件比较大，所以第一次访问时需要耐心等待下载完成，只有下载完成后，才能缓存成功，下一次再访问时才可能访问到缓存

{{i18nTranslate('_layout.t27')}}
{{i18nTranslate('_layout.t12')}}