一、CDN概述
CDN(Content Delivery Network)内容分发网络,通过将内容缓存到离用户最近的节点来加速访问:
CDN的核心价值:
- 加速访问速度(减少物理距离)
- 减轻源站压力(扛住流量高峰)
- 提升用户体验(减少等待时间)
- 节省带宽成本(边缘节点分流)
二、CDN架构
1. 架构组件
用户请求 → DNS解析 → CDN边缘节点 → 缓存命中?
│
┌───────────────┼───────────────┐
▼ ▼ ▼
边缘节点 区域节点 源站
(Last Mile) (Middle Mile) (Origin)
└───────────────┴───────────────┘
│
缓存未命中时回源
2. 工作流程
1. 用户访问 www.example.com/logo.png
2. 本地DNS解析到CDN
3. CDN智能调度(选择最近节点)
4. 边缘节点检查缓存
├── 命中 → 直接返回
└── 未命中 → 回源获取 → 缓存 → 返回
三、主流CDN服务商
| 服务商 | 特点 | 价格 |
|---|---|---|
| 阿里云CDN | 节点多,生态完善 | 中等 |
| 腾讯云CDN | 国内访问快 | 中等 |
| Cloudflare | 全球覆盖,免费套餐 | 便宜 |
| Akamai | 全球第一 | 昂贵 |
| CloudFront | AWS生态集成 | 按量付费 |
四、CDN配置实战
1. 阿里云CDN配置
java
@Configuration
public class AliyunCDNConfig {
@Value("${aliyun.cdn.domain}")
private String cdnDomain;
@Value("${aliyun.cdn.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.cdn.accessKeySecret}")
private String accessKeySecret;
@Bean
public CdnClient cdnClient() {
return new CdnClientBuilder()
.build(accessKeyId, accessKeySecret);
}
}
@Service
public class CDNService {
@Autowired
private CdnClient cdnClient;
// 刷新缓存
public void refreshCache(String url) {
RefreshObjectCachesRequest request = new RefreshObjectCachesRequest();
request.setObjectPath(url);
request.setObjectType("File");
cdnClient.refreshObjectCaches(request);
}
// 预热缓存
public void preloadCache(String url) {
PushObjectCacheRequest request = new PushObjectCacheRequest();
request.setObjectPath(url);
cdnClient.pushObjectCache(request);
}
}
2. Nginx配置CDN回源
nginx
# nginx.conf
upstream origin {
server origin.example.com:8080;
}
server {
listen 80;
server_name cdn.example.com;
# 缓存配置
proxy_cache my_cache;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating;
# 回源配置
proxy_pass http://origin;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 缓存控制
add_header X-Cache-Status $upstream_cache_status;
}
五、缓存策略
1. 缓存Key设计
java
// 合理的缓存Key设计
public class CacheKeyBuilder {
// 基础Key
public static String buildProductKey(Long productId) {
return "product:" + productId;
}
// 带版本的Key(版本更新时自动失效旧缓存)
public static String buildProductKeyV(Long productId, String version) {
return "product:" + productId + ":v" + version;
}
// 带用户分组的Key(不同用户看到不同价格)
public static String buildProductPriceKey(Long productId, Long userGroupId) {
return "product:price:" + productId + ":g" + userGroupId;
}
}
2. 缓存失效策略
java
@Service
public class ProductCacheService {
@Autowired
private CdnClient cdnClient;
public void updateProduct(Product product) {
// 1. 更新数据库
productMapper.updateById(product);
// 2. 删除Redis缓存
redisTemplate.delete("product:" + product.getId());
// 3. 刷新CDN缓存
String cdnUrl = "https://cdn.example.com/product/" + product.getId() + ".html";
cdnClient.refreshObjectCaches(new RefreshObjectCachesRequest(cdnUrl));
// 4. 如果是大面积更新,使用刷新目录
if (isBigUpdate()) {
cdnClient.refreshObjectCaches(new RefreshObjectCachesRequest(
"https://cdn.example.com/product/list/"));
}
}
}
3. 缓存控制头
java
@Configuration
public class CacheControlFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String path = request.getRequestURI();
// 静态资源:长时间缓存
if (isStaticResource(path)) {
response.setHeader("Cache-Control", "public, max-age=31536000");
response.setHeader("Expires",
LocalDateTime.now().plusYears(1).format(DateTimeFormatter.RFC_1123_DATE_TIME));
}
// API接口:短时间缓存或不缓存
else if (isAPI(path)) {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
}
// 动态页面:短时间缓存
else {
response.setHeader("Cache-Control", "public, max-age=300");
}
chain.doFilter(req, res);
}
}
六、CDN安全
1. 防盗链
nginx
# Nginx防盗链配置
server {
location /images/ {
# 允许的域名
valid_referers none blocked server_names
~\.google\. ~\.baidu\. ~\.example\.com;
if ($invalid_referer) {
return 403;
}
}
}
2. IP限流
java
// CDN IP限流配置
public void configureIPLimit(CdnClient client) {
CreateIpFcRequest request = new CreateIpFcRequest();
request.setDomainName("cdn.example.com");
request.setConfigId("ip_limit_config");
// 限制单IP请求频率
request.setRules(Arrays.asList(
new IpAclRule()
.setIpList(Arrays.asList("1.2.3.4", "5.6.7.8"))
.setType("allow")
));
client.createIpFc(request);
}
3. HTTPS配置
java
// CDN HTTPS配置
public void configureHTTPS(CdnClient client, String domain) {
// 上传证书
SetCdnDomainSSLCertificateRequest certRequest = new SetCdnDomainSSLCertificateRequest();
certRequest.setDomainName(domain);
certRequest.setCertType("free"); // 免费证书
certRequest.setSSLProtocol("TLSv1.2");
client.setCdnDomainSSLCertificate(certRequest);
}
七、性能优化
1. 预热策略
java
@Service
public class PreloadService {
@Autowired
private CdnClient cdnClient;
// 秒杀开始前预热
public void preloadSeckillProducts(List<Long> productIds) {
for (Long productId : productIds) {
String url = "https://cdn.example.com/product/" + productId + ".html";
PushObjectCacheRequest request = new PushObjectCacheRequest();
request.setObjectPath(url);
cdnClient.pushObjectCache(request);
log.info("预热CDN: {}", url);
}
}
// 批量预热
public void batchPreload(String pattern) {
// 预热整个目录
PushObjectCacheRequest request = new PushObjectCacheRequest();
request.setObjectPath("https://cdn.example.com/products/");
cdnClient.pushObjectCache(request);
}
}
2. 访问日志分析
java
@Service
public class CDNLogAnalysis {
// 分析CDN访问日志
public void analyzeLogs() {
// 获取热门资源
String logPath = "/var/log/cdn/access.log";
try (Stream<String> lines = Files.lines(Paths.get(logPath))) {
Map<String, Long> topResources = lines
.map(this::parseLogLine)
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(
LogEntry::getUrl,
Collectors.counting()
))
.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(100)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(a, b) -> a,
LinkedHashMap::new
));
log.info("热门资源TOP10: {}", topResources);
} catch (IOException e) {
log.error("日志分析失败", e);
}
}
}
八、总结
CDN是提升访问速度的重要手段:
- 架构理解:边缘节点→区域节点→源站
- 缓存策略:合理设置缓存Key和失效策略
- 安全防护:防盗链、IP限流、HTTPS
- 性能优化:预热、缓存控制头
最佳实践:
- 静态资源使用CDN
- 合理设置缓存时间
- 使用版本号实现缓存更新
- 监控CDN命中率
个人观点,仅供参考