CDN:CDN自动化管理
发布时间:2026-04-23 15:01
一、前言
搞过的人都清楚,线上出bug第一反应是清CDN缓存,结果发现后台刷新要排队等半小时,批量预热更是做梦。手动操作几十个域名试试?手酸眼瞎还容易点错。本文解决的就是这个痛点:用API把CDN刷新、缓存预热、节点查询全自动化,脚本一跑全搞定。
二、操作步骤
第1步:确认API访问凭证
登录CDN控制台,找到API密钥或AccessKey。别用永久密钥,生产环境必须用临时Token,丢了谁都担不起这个责。
# 以阿里云CDN为例,查看环境变量配置
$ env | grep -i aliyun
ALIYUN_ACCESS_KEY_ID=LTAI5tXXXXXXXXXXXXX
ALIYUN_ACCESS_KEY_SECRET=YOUR_ACCESS_KEY_SECRET
ALIYUN_REGION=cn-beijing
第2步:安装SDK或命令行工具
别自己造轮子写HTTP请求,官方SDK都给你封装好了,直接pip装。
# Python环境
$ pip install aliyun-python-sdk-cdn==2.0.0
# 或者用阿里云CLI工具
$ curl -sL https://aliyuncli.alibaba.com/download/aliyun-cli-linux-latest-amd64.tgz | tar -xz -C /usr/local/bin/
$ aliyun configure set --mode Key --access-key-id ${ALIYUN_ACCESS_KEY_ID} --access-key-secret ${ALIYUN_ACCESS_KEY_SECRET}
# 验证安装
$ aliyun cdn DescribeCdnService
{
"InternetChargeType": "PayByTraffic",
"OperationLocks": [],
"RequestId": "75c378b8-c4a6-4e2a-9c1a-8b3d9e0f1234"
}
第3步:编写批量刷新脚本
核心脚本来了,支持按目录刷新和按URL刷新两种模式。目录刷新会自动带上通配符,比逐个URL靠谱。
#!/usr/bin/env python3
# cdn_refresh.py - CDN批量刷新脚本
import os
import time
from aliyunsdkcdn.request.v20180510 import RefreshObjectCachesRequest
def refresh_urls(client, url_list, refresh_type='File'):
"""刷新URL或目录"""
request = RefreshObjectCachesRequest.RefreshObjectCachesRequest()
request.set_ObjectPath('\n'.join(url_list))
request.set_ObjectType(refresh_type)
response = client.do_action_with_exception(request)
return response
def batch_refresh(client, urls, batch_size=100):
"""分批刷新,防止请求超限"""
total = len(urls)
for i in range(0, total, batch_size):
batch = urls[i:i+batch_size]
result = refresh_urls(client, batch, 'Directory' if batch[0].endswith('/') else 'File')
print(f"[{i//batch_size + 1}] 提交成功: {len(batch)}条")
time.sleep(1) # 限速1秒
return total
if __name__ == '__main__':
# 示例URL列表
test_urls = [
'https://www.example.com/css/main.css',
'https://www.example.com/js/bundle.js',
'https://www.example.com/api/v1/data',
]
print(f"准备刷新 {len(test_urls)} 个URL")
第4步:创建缓存预热脚本
刷新是把旧内容干掉,预热是把新内容提前推到边缘节点。上线前跑一遍,用户体验直接提升一个档次。
#!/usr/bin/env bash
# cdn_preload.sh - 缓存预热脚本
set -e
API_ENDPOINT="https://cdn.aliyuncs.com"
ACCESS_KEY="${ALIYUN_ACCESS_KEY_ID}"
ACCESS_SECRET="${ALIYUN_ACCESS_KEY_SECRET}"
preload_urls() {
local urls_file=$1
local task_count=0
while IFS= read -r url; do
[[ -z "$url" || "$url" =~ ^# ]] && continue
response=$(curl -s -X POST "${API_ENDPOINT}"
-H "Content-Type: application/x-www-form-urlencoded"
-d "AccessKeyId=${ACCESS_KEY}"
-d "Action=PushObjectCache"
-d "ObjectPath=${url}"
-d "ObjectType=File"
-d "SignatureMethod=HMAC-SHA1"
-d "SignatureVersion=1.0"
-d "Timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
-d "Format=JSON"
-d "SignatureNonce=$(uuidgen)"
-d "Version=2018-05-10")
echo "[$(date '+%H:%M:%S')] 预热: ${url}"
((task_count++))
sleep 0.5
done < "$urls_file"
echo "总计提交 ${task_count} 个预热任务"
}
# 使用示例
# echo -e "https://www.example.com/static/app.js\nhttps://www.example.com/images/logo.png" > urls.txt
# ./cdn_preload.sh urls.txt
第5步:验证刷新状态
提交刷新任务后别干等着,得查状态确认完成没。CDN服务商的任务状态有时候延迟较大,耐心点。
$ aliyun cdn DescribeRefreshTasks --TaskId "123456789" --OwnerId "123456789"
{
"Tasks": {
"Task": [
{
"TaskId": "123456789",
"ObjectPath": "https://www.example.com/index.html",
"Status": "Complete",
"Process": "100%",
"CreationTime": "2024-01-15T10:30:00Z",
"CompletionTime": "2024-01-15T10:30:45Z"
},
{
"TaskId": "123456790",
"ObjectPath": "https://www.example.com/api/*",
"Status": "Running",
"Process": "45%",
"CreationTime": "2024-01-15T10:30:00Z",
"CompletionTime": ""
}
]
},
"RequestId": "a8f2d3c4-e5b6-4789-a012-3d4e5f678901"
}
第6步:配置定时任务和告警
手动跑脚本不是长久之计,得上cron。再配上钉钉/企业微信通知,刷新失败第一时间知道。
# crontab -e 配置定时任务
# 每天凌晨2点执行缓存预热
0 2 * * * /opt/scripts/cdn_preload.sh /opt/scripts/production_urls.txt >> /var/log/cdn_preload.log 2>&1
# 每周一、三、五刷新静态资源
0 3 * * 1,3,5 /usr/bin/python3 /opt/scripts/cdn_refresh.py --type directory >> /var/log/cdn_refresh.log 2>&1
# 告警脚本 - 检查任务失败并发送通知
#!/usr/bin/env python3
# check_cdn_status.py
import subprocess
import json
import requests
WEBHOOK_URL = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_WEBHOOK_TOKEN"
def check_failed_tasks():
result = subprocess.run(
['aliyun', 'cdn', 'DescribeRefreshTasks', '--TaskType', 'refresh', '--Status', 'failed', '--PageSize', '10'],
capture_output=True, text=True
)
data = json.loads(result.stdout)
failed = data.get('Tasks', {}).get('Task', [])
if failed:
message = f"⚠️ CDN刷新失败 {len(failed)} 个任务\n"
for task in failed[:5]:
message += f"- {task['ObjectPath']}: {task.get('ErrorMessage', '未知错误')}\n"
requests.post(WEBHOOK_URL, json={
"msgtype": "text",
"text": {"content": message}
})
if __name__ == '__main__':
check_failed_tasks()
第7步:集成到CI/CD流水线
代码发布后自动触发CDN刷新,这才是正经姿势。Jenkins和GitLab CI都支持,Pipeline里加个步骤就行。
# Jenkinsfile 示例
pipeline {
agent any
stages {
stage('Deploy') {
steps {
echo '部署应用到服务器...'
sh 'ansible-playbook -i inventory/prod.yml playbooks/deploy.yml'
}
}
stage('CDN Refresh') {
steps {
script {
def urls = readFile('/var/jenkins_home/cdn_urls.txt').trim().split('\n')
sh """
for url in ${urls.join(' ')}; do
aliyun cdn RefreshObjectCaches --ObjectPath "$url" --ObjectType File
sleep 1
done
"""
}
}
}
}
post {
always {
echo '清理工作目录...'
}
failure {
dingTalk accessToken: 'YOUR_DINGTALK_TOKEN',
message: 'CDN刷新失败,请检查!'
}
}
}
三、常见问题FAQ
Q:刷新请求被限流了怎么办?
别慌,CDN厂商都有QPS限制,阿里云单用户默认200次/秒,刷新Quota用完只能等第二天重置。解法是提前规划,把刷新任务分散到业务低峰期,比如凌晨2-5点。另一个思路是减少无效刷新,新旧URL没变化就别刷,用CDN的304协商缓存能省不少Quota。
Q:目录刷新和URL刷新有什么区别?
目录刷新会自动匹配该路径下所有资源,URL刷新只针对指定的具体链接。实际用下来,目录刷新成功率更高,但耗时更长(可能30分钟才全部生效),URL刷新快但容易漏掉关联资源。我的经验是:首屏页面用URL刷新保证即时生效,全站静态资源用目录刷新批量处理。
Q:CDN节点IP被源站封了怎么排查?
先用describeCdnRegionAndIsp查询各地区节点的IP段,然后去源站Nginx看日志,找到访问异常的那批IP。常见原因是CDN回源IP段不在源站白名单里,或者触发了源站CC防护。解法是把CDN的IP段加到白名单,或者在Nginx设置连接限速和IP限制规则。
Q:多CDN厂商怎么统一管理?
别指望一个脚本搞定所有厂商,API协议完全不同。实用方案是用Terraform的CDN Provider做配置管理,状态文件记录各厂商的配置。刷新和预热这类高频操作,建议各厂商单独写脚本,用统一的入口脚本调度。再往上一层,可以用多云管理平台比如Cortex或山云,但投入成本较高。
四、总结
CDN自动化管理的核心就三点:API是基础、脚本化是手段、监控是保障。手动操作的时代早就该翻篇了,每次上线前手动清缓存这种事,干一次是经验,干十次就是浪费生命。
核心要点:
- 用SDK封装好的API,别自己写签名逻辑,容易踩坑
- 批量操作必须分批限速,否则触发风控直接封禁
- 刷新和预热是两个概念,上线用刷新,日常维护用预热
- 定时任务配合告警,失败及时通知,别等用户报障
- CI/CD集成是标配,代码即交付,交付即生效
延伸阅读:
- 阿里云CDN API文档:RefreshObjectCaches
- Cloudflare API v4:批量刷新和自定义缓存规则
- Nginx变量$upstream_cache_status:精准判断缓存命中状态