Nginx需通过map指令识别CDN回源IP段并标记类型,再结合Lua动态路由或多个静态upstream实现按CDN类型差异化权重;必须配合健康检查与自动降级机制保障稳定性。

要让 Nginx 根据不同 CDN 节点的来源 IP,动态调整回源请求的权重(比如优先走内网线路、降级处理异常 CDN),核心在于结合 map 指令识别 CDN 回源 IP 段,再用 upstream 的 weight + ip_hash 或 hash $cdn_key consistent 实现按源分流。纯靠 upstream 内置策略做不到“按 CDN 类型调权”,必须引入变量驱动。
识别并标记不同 CDN 的回源 IP 段
Nginx 本身不自动识别“这是阿里云 CDN 还是 Cloudflare”,需手动维护各 CDN 官方公布的回源 IP 段(如阿里云[文档](https://help.aliyun.com/document_detail/271609.html)、Cloudflare[IP 列表](https://www.cloudflare.com/ips/))。用 map 将真实客户端 IP($remote_addr)映射为 CDN 标识或权重系数:
- 在
http块中定义:
map $remote_addr $cdn_type {
default "unknown";
~^100\.64\.0\.[0-9]+ "aliyun";
~^104\.16\.[0-9]+\.[0-9]+ "cloudflare";
~^2a06:98c0::/32 "cloudflare_v6";
192.168.10.5 "self_test"; # 可用于本地验证
}注意:$remote_addr 是 Nginx 接收到的直连 IP;若 CDN 透传了真实用户 IP 到 X-Forwarded-For,而你又启用了 real_ip 模块,则应改用 $realip_remote_addr。
构建支持变量权重的 upstream(需 stream 模块或 Lua)
原生 Nginx upstream 不支持 weight 动态取变量值。有两种实用方案:
-
方案一:用 OpenResty + Lua(推荐)
在upstream块外用 Lua 计算目标 server 和权重,再用balancer_by_lua_block控制转发逻辑。例如:
upstream backend_pool {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
<p>server {
location / {
set $backend "";
access_by_lua_block {
local cdn = ngx.var.cdn_type
if cdn == "aliyun" then
ngx.var.backend = "10.0.1.10:8080"
elseif cdn == "cloudflare" then
ngx.var.backend = "10.0.1.11:8080"
else
ngx.var.backend = "10.0.1.12:8080"
end
}
proxy_pass <a href="https://www.php.cn/link/7c677ff4c58e458338c5f7e74556735d">https://www.php.cn/link/7c677ff4c58e458338c5f7e74556735d</a>;
}
}-
方案二:用多个静态 upstream + if(简单场景可用)
为每类 CDN 定义独立 upstream,用if判断后选择 proxy_pass 目标:
upstream backend_aliyun {
server 10.0.1.10:8080 weight=10;
server 10.0.1.11:8080 weight=5;
}
<p>upstream backend_cloudflare {
server 10.0.1.10:8080 weight=3;
server 10.0.1.12:8080 weight=10;
}</p><p>server {
location / {
proxy_pass_request_headers on;
if ($cdn_type = "aliyun") {
proxy_pass <a href="https://www.php.cn/link/6d6ababa05a025b3f8ffa1f4e765f6fe">https://www.php.cn/link/6d6ababa05a025b3f8ffa1f4e765f6fe</a>;
break;
}
if ($cdn_type = "cloudflare") {
proxy_pass <a href="https://www.php.cn/link/39e42960b233b6999d195eae85d7290b">https://www.php.cn/link/39e42960b233b6999d195eae85d7290b</a>;
break;
}
proxy_pass <a href="https://www.php.cn/link/6d6ababa05a025b3f8ffa1f4e765f6fe">https://www.php.cn/link/6d6ababa05a025b3f8ffa1f4e765f6fe</a>; # default
}
}⚠️ 注意:if 在 location 中慎用,仅限简单判断;避免嵌套或复杂条件。生产环境更推荐 Lua 方案。
配合健康检查与自动降级
差异化权重不是一劳永逸。当某 CDN 大量回源失败时,应临时降低其对应 upstream 的权重,甚至切流。可结合:
-
upstream_check_module(需编译添加)做 TCP/HTTP 健康检查,配合check fall=3 rise=2 - 用
lua-resty-healthcheck在 Lua 层统计错误率,动态修改balancer_by_lua_block中的目标 server 列表 - 配置
proxy_next_upstream error timeout http_502 http_503,让失败请求自动重试其他节点
例如:当检测到 Cloudflare 回源 5 分钟内错误率超 15%,Lua 脚本可将 $cdn_type 临时覆盖为 "fallback",触发备用 upstream。
验证与调试关键点
上线前务必验证链路是否真正按预期分流:
- 用
curl -H "X-Real-IP: 100.64.0.100" http://your-domain.com/test模拟阿里云 CDN 回源请求,检查access.log中$cdn_type和后端日志 IP 是否匹配 - 在 log_format 中加入
$cdn_type $upstream_addr,直观查看每次请求命中哪个 CDN 和哪个后端 - 对每个 CDN 回源 IP 段,在防火墙或后端服务上抓包,确认流量确实走指定服务器和端口
- 压测时观察各 upstream 的
ngx_http_upstream_module状态页(需开启stub_status)中 request 数与权重比例是否大致吻合


















