Python
悠悠
2025年10月16日

CDN优化实战:从命中率30%到95%的血泪史,AWS CloudFront踩坑全记录

最近客户cdn命中率异常,让我优化下缓存策略。经过一番折腾,总算把命中率提上来了!!!今天就把这些年踩过的坑和一些实用的经验分享给大家。

其实CDN优化这事儿,说简单也简单,说复杂也复杂。很多人以为接入个CDN就万事大吉了,结果发现命中率低得可怜,钱花了不少效果却不明显。我之前就遇到过这种情况,CDN命中率只有30%多,简直是在烧钱。

先说说CDN的那些关键指标

做CDN优化,你得先知道怎么看数据。就像开车要看仪表盘一样,不然怎么知道车子跑得怎么样?

命中率(Hit Ratio)
这个是最重要的指标,没有之一。命中率就是CDN直接返回缓存内容的请求占总请求的比例。一般来说,静态资源的命中率应该在90%以上,如果你的命中率只有50-60%,那肯定有问题。

在AWS CloudFront里查看命中率很简单,进入CloudFront控制台,选择你的分发,然后点击"Monitoring"标签页。这里会显示Cache hit rate的图表,可以看到不同时间段的命中率变化。

image-20251016214904572

回源率(Origin Request Rate)
这个和命中率是相对的,回源率高说明CDN经常要去源站拿数据,这样就失去了CDN的意义。正常情况下回源率应该控制在10%以下。

响应时间
包括CDN响应时间和回源响应时间。CDN响应时间一般应该在100ms以内,如果超过这个数值就要检查是不是节点选择有问题。

我记得有次优化一个电商网站,发现图片加载特别慢。一查监控发现CDN响应时间居然有2秒多,后来才发现是缓存策略配置错误,每次都要回源验证。

带宽使用情况
这个主要是看成本,CDN的费用很大一部分就是带宽费用。通过监控带宽使用情况,可以了解流量分布,优化成本。

在AWS CloudFront的监控面板里,你还能看到:

  • Origin latency(回源延迟)
  • Error rate(错误率)
  • Requests(请求数)
  • Bytes downloaded(下载字节数)

这些数据都很有用,特别是错误率,如果突然飙升可能是源站出问题了。

命中率低的常见原因和解决方案

说到命中率低,我遇到过各种奇葩的情况。

缓存策略配置不当
这是最常见的问题。很多人图省事,直接用默认配置,结果发现很多本该缓存的内容都没有缓存。

比如说,有些动态参数会导致URL不同,CDN就认为是不同的资源。像这种情况:

https://example.com/image.jpg?timestamp=1234567890
https://example.com/image.jpg?timestamp=1234567891

CDN会认为这是两个不同的文件,实际上内容是一样的。解决办法是在CloudFront的Behavior设置里配置Query String参数处理,可以选择忽略某些参数或者只转发特定参数。

TTL设置太短
Time To Live设置太短会导致缓存频繁过期。我见过有人把图片的TTL设置成5分钟,这不是瞎搞吗?静态资源的TTL至少要设置几个小时,甚至几天。

在CloudFront里可以设置三种TTL:

  • Minimum TTL:最小缓存时间
  • Maximum TTL:最大缓存时间
  • Default TTL:默认缓存时间

一般我会这样设置:

  • 图片、CSS、JS等静态资源:24小时到7天
  • HTML页面:1-6小时
  • API接口:根据业务需求,可能几分钟到几小时

源站响应头配置问题
有时候源站返回了不合适的Cache-Control头,比如no-cache或者max-age=0,这会导致CDN不缓存内容。

我之前遇到过一个案例,开发在Nginx配置里给所有静态资源都加了no-cache,结果CDN命中率惨不忍睹。后来改成这样:

location ~* \.(jpg|jpeg|png|gif|css|js)$ {
    expires 7d;
    add_header Cache-Control "public, immutable";
}

预热不充分
新上线的CDN或者清除缓存后,需要一段时间来"预热"。这期间命中率会比较低,这是正常现象。但如果长时间命中率都上不去,就要检查其他配置了。

CloudFront支持手动预热,可以通过Invalidation功能清除缓存,然后用脚本批量访问重要资源来预热缓存。

CDN优化策略详解

现在说说aws托管的缓存策略

AWS CDN托管的缓存策略详细说明

image-20251016215708610

策略名称缓存内容不缓存内容使用场景
Amplify缓存大多数静态资源和部分动态内容不缓存包含特定身份验证头的请求Amplify应用程序的通用缓存策略
Amplify-Default缓存静态资源和基于常用头部的内容,保留某些Cookie不缓存带有特定认证头的请求,某些动态API响应Amplify应用的标准配置,平衡缓存与个性化
Amplify-Default-V2与Amplify-Default类似,但有优化的TTL设置与Amplify-Default类似需要改进的缓存性能的Amplify应用
Amplify-DefaultNoCookies缓存静态资源和页面内容不缓存任何Cookie信息,不缓存认证请求不需要基于Cookie区分用户的Amplify应用
Amplify-DefaultNoCookies-V2与DefaultNoCookies类似,但有更长的TTL与DefaultNoCookies类似追求更高缓存命中率的静态Amplify应用
Amplify-ImageOptimization缓存图像文件(jpg, png, gif等),支持不同的图像格式不缓存非图像内容,不保留大多数请求头图像密集型网站,图片库,电商产品展示
Amplify-ImageOptimization-V2与ImageOptimization类似,增加了WebP等现代格式支持与ImageOptimization类似需要现代图像格式支持的应用
Amplify-StaticContent缓存JS, CSS, 字体, 图像等静态资源,长TTL不缓存HTML或动态内容,不保留Cookie静态资源的长期缓存,提高重复访问性能
Amplify-StaticContent-V2与StaticContent类似,但有更优化的压缩设置与StaticContent类似需要最佳静态资源性能的应用
CachingDisabled不缓存任何内容所有内容都直接从源站获取实时数据,个性化内容,需要实时源站响应的场景
CachingOptimized缓存大多数内容,启用压缩,优化TTL不缓存POST/PUT请求,特定动态API路径通用Web应用,需要平衡缓存与新鲜度的场景
CachingOptimizedForUncompressedObjects缓存未压缩的对象,自动应用适当的TTL不缓存已经压缩的内容,不处理某些动态请求源站不提供压缩的情况,CDN负责压缩
Elemental-MediaPackage缓存视频分段,流媒体清单文件不缓存用户特定的媒体请求,认证令牌视频流媒体,直播,点播视频服务
UseOriginCacheControlHeaders根据源站的Cache-Control头决定缓存行为如果源站指示不缓存,则不缓存;忽略查询参数源站已有完善缓存策略的情况
UseOriginCacheControlHeaders-QueryStrings根据源站Cache-Control头和URL查询参数缓存如源站指示不缓存则不缓存基于查询参数提供不同内容且源站控制缓存的场景

AWS CloudFront 源请求策略详细说明

image-20251016215729559

策略名称转发内容不转发内容使用场景
AllViewer转发所有查看者请求参数,包括查询字符串、标头和Cookie不限制任何参数的转发需要将所有客户端请求信息传递给源站的场景,适用于高度依赖客户端信息的动态内容
AllViewerAndCloudFrontHeaders-2022-06转发所有查看者请求参数和截至2022年6月的所有CloudFront标头不限制任何参数或CloudFront标头的转发需要完整客户端信息以及CloudFront添加的信息(如设备类型、地理位置)的场景
AllViewerExceptHostHeader转发除Host标头外的所有查看者请求参数不转发Host标头当源站需要使用不同的主机名处理请求,但仍需其他所有客户端信息的场景
CORS-CustomOrigin转发与CORS(跨源资源共享)相关的标头到自定义源不转发与CORS无关的其他标头需要支持跨域请求的自定义源站(非S3)场景,如API或Web应用
CORS-S3Origin转发与CORS相关的标头到S3源不转发与CORS无关的其他标头需要支持跨域请求的S3存储桶场景,如从浏览器直接访问S3资源
Elemental-MediaTailor-PersonalizedManifests转发Elemental MediaTailor个性化清单所需的标头不转发与媒体个性化无关的标头视频流媒体场景,特别是需要个性化内容或广告插入的流媒体服务
HostHeaderOnly仅转发Host标头到源站不转发任何其他查看者请求参数简单的静态内容分发场景,源站仅需要知道请求的主机名
UserAgentReferrerHeaders转发User-Agent(用户代理)和Referer(引用页)标头到源站不转发其他查看者请求参数源站需要了解访问者浏览器类型和来源网站的场景,如内容适配或引用统计

这些源请求策略控制CloudFront将哪些信息从查看者(客户端)请求中转发到源站。选择合适的策略可以优化源站请求处理,减少不必要的信息传递,同时确保源站获得所需的上下文信息来正确响应请求。

AWS CloudFront 响应标头策略详细说明

image-20251016215946804

策略名称添加/修改内容不添加/不修改内容使用场景
CORS-and-SecurityHeadersPolicy添加CORS相关标头和安全标头到响应中不修改源站提供的其他标头需要同时支持跨域请求和增强安全性的Web应用,如需要跨域访问的API且需要防XSS、点击劫持等安全保护
CORS-With-Preflight添加CORS相关标头并支持预检(OPTIONS)请求不添加安全标头,不修改源站提供的其他标头需要支持复杂跨域请求的场景,特别是涉及非简单请求(如带自定义标头或使用PUT/DELETE方法)的API
CORS-with-preflight-and-SecurityHeadersPolicy添加CORS相关标头(含预检支持)和安全标头不修改源站提供的其他标头需要全面CORS支持(包括复杂请求)和安全增强的Web应用,如SPA(单页应用)与后端API交互
SecurityHeadersPolicy仅添加安全相关标头到每个响应不添加CORS标头,不修改源站提供的其他标头注重安全性但不需要跨域支持的网站,如企业内部应用或对安全有高要求的公共网站
SimpleCORS仅添加基本CORS标头,支持简单跨域请求不添加安全标头,不支持预检请求,不修改源站提供的其他标头只需基本跨域支持的简单场景,如只允许GET请求的公共API或静态资源

这些响应标头策略控制CloudFront如何修改从源站返回给客户端的HTTP响应标头。适当的策略可以增强Web应用的安全性,启用跨域资源共享功能,而无需修改源站配置。安全标头通常包括内容安全策略(CSP)、X-XSS-Protection、X-Frame-Options等,用于防止常见的Web安全威胁。

当然要是这些不满足还可以自定义!!

其他一些缓存策略

分层缓存策略
不同类型的资源用不同的缓存策略。我一般会创建多个Behavior,针对不同的路径模式设置不同的缓存规则:

/api/* - TTL: 5分钟,转发所有参数
/images/* - TTL: 7天,忽略查询参数
/css/* - TTL: 1天,启用压缩
/js/* - TTL: 1天,启用压缩
/* - TTL: 1小时,默认行为

启用压缩
CloudFront支持自动压缩,可以显著减少传输数据量。在Behavior设置里开启"Compress Objects Automatically"就行了。不过要注意,压缩会消耗一些CPU资源,对于已经压缩过的文件(如图片)就没必要再压缩了。

合理使用Origin Shield
这是CloudFront的一个高级功能,相当于在CDN和源站之间加了一层缓存。对于回源比较频繁的场景很有用,可以减少源站压力。

我在一个视频网站项目中用过Origin Shield,效果很明显。因为视频文件比较大,用户分布又比较集中,开启Origin Shield后回源请求减少了60%多。

HTTP/2和HTTP/3支持
现在的CDN基本都支持HTTP/2了,CloudFront也不例外。HTTP/2的多路复用特性可以显著提升页面加载速度,特别是对于有很多小文件的网站。

智能路由
CloudFront会自动选择最优的边缘节点,但有时候你可能需要手动干预。比如某些地区的节点质量不好,可以通过地理位置限制来避免使用这些节点。

AWS CloudFront的一些实用技巧

用了这么久CloudFront,发现了一些比较实用的技巧。

Lambda@Edge
这个功能很强大,可以在CDN边缘节点运行代码。我用过几个场景:

  • 动态修改响应头
  • 根据用户地理位置返回不同内容
  • 简单的A/B测试
  • 图片格式转换(WebP支持检测)

比如这个检测WebP支持的例子:

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    
    const accept = headers.accept && headers.accept[0] && headers.accept[0].value;
    
    if (accept && accept.includes('image/webp')) {
        request.uri = request.uri.replace(/\.(jpg|jpeg|png)$/i, '.webp');
    }
    
    callback(null, request);
};

实时日志分析
CloudFront可以把访问日志实时推送到Kinesis Data Streams,然后用Lambda处理。我用这个功能做过实时监控,当错误率超过阈值时自动发送告警。

image-20251016220417877

多源站配置
CloudFront支持配置多个源站,可以实现负载均衡和故障转移。我一般会配置主源站和备用源站,当主源站出问题时自动切换到备用源站。

image-20251016220355301

自定义错误页面
通过配置Custom Error Pages,可以为不同的HTTP错误码返回自定义页面。这样用户体验会好很多,而且可以减少无效的回源请求。

image-20251016220454872

image-20251016220524718

监控和告警设置

CDN优化不是一次性的工作,需要持续监控和调优。

CloudWatch监控
CloudFront的所有指标都会推送到CloudWatch,可以设置各种告警:

  • 命中率低于阈值告警
  • 错误率超过阈值告警
  • 回源延迟过高告警
  • 带宽使用异常告警

我一般会设置这些告警规则:

命中率 < 85% 持续10分钟 -> 发送告警
4xx错误率 > 5% 持续5分钟 -> 发送告警  
5xx错误率 > 1% 持续5分钟 -> 发送告警
回源延迟 > 2秒 持续5分钟 -> 发送告警

第三方监控工具
除了CloudWatch,我还会用一些第三方工具来监控CDN性能,比如Pingdom、GTmetrix等。这些工具可以从用户角度测试网站性能,发现一些CloudWatch监控不到的问题。

成本优化

CDN的费用不便宜,特别是流量大的网站。

Price Class选择
CloudFront有三个价格等级,包含的边缘节点数量不同。如果你的用户主要在北美和欧洲,选择Price Class 100就够了,没必要选择包含全球所有节点的Price Class All。

缓存策略优化
提高命中率不仅能改善性能,还能降低成本。因为CDN的费用主要是按流量计算的,命中率高意味着回源流量少,总体费用就低。如果命中率低就会出现流量放大效应:
• 正常命中率80%:1GB实际需求 = 1.25GB CDN流量
• 当前命中率可能<20%:1GB实际需求 = 5GB+ CDN流量

压缩和格式优化
启用压缩可以减少传输数据量,WebP格式的图片比JPEG小30-50%。这些优化都能直接降低CDN费用。

我之前优化过一个图片网站,通过启用压缩和WebP转换,CDN费用降低了40%多。

常见问题排查

做CDN优化经常会遇到各种问题,分享几个排查思路。

缓存不生效
首先检查响应头,看看有没有Cache-Control、Expires等缓存相关的头。然后检查CloudFront的Behavior配置,确认TTL设置正确。

可以用curl命令测试:

curl -I https://your-domain.com/test.jpg

看响应头里的X-Cache字段,Hit表示命中缓存,Miss表示没有命中。

某些地区访问慢
可能是CDN节点选择有问题。用不同地区的VPS测试访问速度,确定是哪些地区有问题。然后检查是不是需要调整Price Class或者配置地理位置限制。

缓存穿透
如果某个资源一直无法缓存,可能是URL参数或者响应头有问题。检查是不是有随机参数,或者源站返回了no-cache头。

我遇到过一个奇葩问题,开发在图片URL后面加了随机数防止缓存,结果CDN命中率为0。后来改成用版本号,问题就解决了。

总结

CDN优化是个系统工程,需要从多个维度来考虑。命中率是最重要的指标,但不是唯一的指标。要结合业务特点,制定合适的缓存策略。

AWS CloudFront功能很强大,但配置也比较复杂。建议先从基础配置开始,逐步优化。不要一开始就搞得很复杂,容易出问题。

最重要的是要持续监控和优化,CDN不是配置好就不管了。用户行为会变化,业务需求也会变化,CDN策略也要跟着调整。

我现在维护的几个网站,CDN命中率都在95%以上,用户访问速度提升了3-5倍。虽然前期折腾了不少时间,但效果还是很明显的。

如果你也在做CDN优化,遇到问题可以多交流。这块水还是挺深的,大家一起学习进步。

如果这篇文章对你有帮助,别忘了点赞转发支持一下!想了解更多运维实战经验和技术干货,记得关注微信公众号@运维躬行录,领取学习大礼包!!!我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习,共同进步!

公众号:运维躬行录

个人博客:躬行笔记

文章目录

博主介绍

热爱技术的云计算运维工程师,Python全栈工程师,分享开发经验与生活感悟。
欢迎关注我的微信公众号@运维躬行录,领取海量学习资料

微信二维码