在构建全球分发的Web应用时,AWS CloudFront作为边缘加速层,其缓存效率直接决定了源站负载与终端用户延迟。Cache Policy是CloudFront从2020年前后逐步推行的统一缓存控制机制,它将原本分散在Behavior与自定义头部的缓存逻辑收敛为可复用的策略对象。TTL决定了资源在边缘节点存活多久,Cache Key则决定了什么请求算作同一个缓存对象。二者若配置粗糙,就会出现重复回源或陈旧内容久不更新的问题。

CloudFront中TTL的三层控制逻辑
CloudFront的Cache Policy里,TTL并不是单一数值,而是由最小TTL(Minimum TTL)、默认TTL(Default TTL)和最大TTL(Maximum TTL)共同约束。最小TTL强制对象在指定秒数内不被重新校验,哪怕源站返回了很低的Cache-Control头。默认TTL则在源站完全没有缓存指示时生效,比如一些纯动态接口被误配进缓存行为后靠它兜底。最大TTL会截断源站传来的过大max-age,避免一年以上的死缓存。
这种三层结构的好处是运维可以对不同路径套用不同策略。例如图片类资源最小TTL设0、默认TTL设86400、最大TTL设31536000,而HTML页面最小TTL设0、默认TTL设60、最大TTL设300。当源站响应头里带有Cache-Control: max-age=3600时,边缘节点会采用3600秒,因为它介于最小与最大之间。若源站没返回任何缓存头,则落入默认TTL。理解这套优先级,才能避免“明明设了TTL却没生效”的困惑。
下面是一段通过AWS CLI创建缓存策略并显式声明TTL参数的示例,注意TTL都以秒为单位,且Min必须大于等于0:
aws cloudfront create-cache-policy
--cache-policy-config '{
"Name": "ImageCachePolicy",
"DefaultTTL": 86400,
"MinTTL": 0,
"MaxTTL": 31536000,
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true,
"HeadersConfig": { "HeaderBehavior": "none" },
"CookiesConfig": { "CookieBehavior": "none" },
"QueryStringsConfig": { "QueryStringBehavior": "whitelist", "QueryStrings": { "Items": ["v"], "Quantity": 1 } }
}
}'
Cache Key的构成与精简原则
Cache Key是CloudFront用来区分缓存对象的哈希输入。默认情况下,它包含域名、路径、以及你选择纳入的查询字符串、请求头和Cookie。很多团队为了“不出错”把全部查询参数都加进Key,结果用户每带一个utm_source参数就生成新缓存,命中率骤降。精细化控制的核心就是白名单思维:只把真正影响响应体的因素放进Key。
举例来说,版本化静态资源/static/app.js?v=1.2.3里的v参数必须进Key,否则新旧文件会混淆;但?utm_source=wechat这类营销参数与内容无关,应排除。请求头方面,除非用了边缘重写或A/B测试依赖Accept-Language,否则不需要纳入。Cookie更是缓存杀手,未登录态的会话Cookie一旦进Key,几乎让每个用户都回源。
在控制台或代码中配置时,QueryStringsConfig的Behavior可选none、whitelist、all,HeadersConfig与CookiesConfig同理。下面的Java片段演示如何用SDK读取已有策略并打印其Cache Key中的查询参数白名单,帮助排查命中率低的问题:
import com.amazonaws.services.cloudfront.AmazonCloudFront;
import com.amazonaws.services.cloudfront.AmazonCloudFrontClientBuilder;
import com.amazonaws.services.cloudfront.model.GetCachePolicyRequest;
import com.amazonaws.services.cloudfront.model.GetCachePolicyResult;
public class InspectCacheKey {
public static void main(String[] args) {
AmazonCloudFront cf = AmazonCloudFrontClientBuilder.defaultClient();
GetCachePolicyResult res = cf.getCachePolicy(
new GetCachePolicyRequest().withId("E2QWRUHAPOMQZL"));
var qs = res.getCachePolicy().getCachePolicyConfig()
.getParametersInCacheKeyAndForwardedToOrigin()
.getQueryStringsConfig();
System.out.println("QueryStringBehavior: " + qs.getQueryStringBehavior());
if (qs.getQueryStrings() != null) {
qs.getQueryStrings().getItems().forEach(System.out::println);
}
}
}
实战中的分层策略与命中率提升
把TTL与Cache Key结合起来,最常见的做法是按内容类型建立多个Cache Policy,再在Distribution的Behavior里按路径前缀绑定。比如/images/*绑长TTL加仅版本参数Key,/api/public/*绑短TTL加无参数Key,/html/*绑中等TTL加Accept-Encoding Key。这样各业务互不干扰,且能针对源站能力调整。
某次线上排查中,一个站点整体命中率仅18%,原因是QueryStringBehavior设成了all,而前端每次请求都带_t=时间戳防缓存。改为whitelist仅保留v后,命中率当周升至93%,源站CPU从70%降到20%。同时把最小TTL从0调到300,让边缘在源站抖动时仍能扛住,避免了雪崩。这证明精细化控制不是理论,而是直接省成本的手段。
最后需注意,Cache Policy与早年的Forwarded Values配置互斥,新建Distribution应统一用Cache Policy。若用Terraform管理,可把策略抽成module复用。下表列出两类典型资源的推荐初始值,实际应根据监控的Hit Rate逐步收紧:
| 资源类型 | MinTTL | DefaultTTL | MaxTTL | QueryString |
|---|---|---|---|---|
| 版本化静态文件 | 0 | 86400 | 31536000 | whitelist: v |
| 公开API列表 | 0 | 300 | 300 | none |
当策略调整完毕后,建议通过CloudFront的Cache Hit Rate指标观察两周,并结合实时日志中的x-cache头确认Miss与Hit比例。只有把TTL区间与Cache Key范围都压到刚好够用,才能在新鲜度与性能间拿到最佳平衡。
CloudFrontCache_PolicyTTL修改时间:2026-08-17 20:32:32