按域名路由的精准流量分发,核心在于将DNS解析策略与反向代理层规则协同配合,通过“智能DNS按地域/线路解析到不同入口,再由Nginx等代理按Host头分发到对应后端集群”来落地实现。
基于DNS与代理层协作的分发体系
域名路由的本质是“入口分流”
用户访问一个域名时,首先经历DNS解析,随后建立TCP连接并发送HTTP请求,按域名路由就是在这两个环节做文章:DNS环节决定用户“连到哪个机房”,HTTP代理环节决定请求“交给哪组后端服务”,两者缺一不可,只做DNS分流失控粒度太粗,只做代理分流则所有流量先挤到同一入口。
域名路由与URL路由的核心差异
很多运维在配置初期会混淆这两个概念。URL路由发生在同一站点内部,根据/path路径转发请求,例如将/api转到接口服务、/static转到静态服务器。域名路由则发生在流量进入入口时,根据Host请求头(如a.example.com与b.example.com)区分业务归属,前者解决“一个域名下多个服务”的问题,后者解决“多个域名或复杂业务共用一套入口”的问题。
核心要点一:智能DNS按地域解析策略
为什么先从DNS层切入
DNS解析是流量分发第一步,它不关心HTTP内容,只解决“让哪里的用户访问哪里”,许多自建机房的团队会问“按域名分流nginx配置怎么弄”,但忽略上游DNS才是地基,如果所有用户都解析到同一机房,后端的Nginx规则再精确也无法应对跨地域延迟。
按地域解析的适用场景
- 业务覆盖华北、华东、华南三个区域,每个区域各自部署后端服务集群
- 国内与海外业务共用一套主域名,需要将海外用户调度至海外节点
- 通过云上多个可用区承载同城双活业务,期望实现就近访问
实操:以Bind9为例配置view分区解析
# 在/etc/named.conf中定义两个view
view "cn" {
match-clients { 202.106.0.0/16; 114.114.0.0/16; }; # 中国电信、114DNS地址段示例
recursion no;
zone "example.com" {
type master;
file "/var/named/cn.example.com.zone";
};
};
view "global" {
match-clients { any; };
recursion no;
zone "example.com" {
type master;
file "/var/named/global.example.com.zone";
};
};
国内解析记录指向北京或上海机房IP,海外解析记录指向香港或新加坡节点,这里的地址段仅为示例,线上需要根据运营商实际分配的IP段或者GeoIP库来维护,这考验的是地址数据的时效性,也是很多团队就“按域名分流 智能DNS 怎么选”产生分歧的根源。
简米云DNS与自建DNS的取舍
自建view分区解析具备高度可定制性,但需要自行维护IP库并确保高可用,当前企业更多选择云解析产品,在控制台“解析设置”中直接添加“地域解析”规则,例如将example.com的默认解析线路指到华北IP,将海外线路指到香港IP。
核心要点二:Nginx/OpenResty七层路由规则
虚拟主机是域名分发的最小单元
配置Nginx的server块,通过server_name区分域名,再在块内用location控制各自路由,OpenResty延续这一机制,在server块中可以使用lua_rewrite_by_lua_block等指令扩展路由逻辑,适合需要动态调整或融入灰度规则的场景。
基于域名分流的通用server配置模板
# 主业务域名
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://backend_web;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# API子系统域名
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# 静态资源域名
server {
listen 80;
server_name static.example.com;
location / {
root /data/static;
expires 30d;
}
}
listen指令后加default_server参数可以指定兜底虚拟主机,未匹配到任何server_name的请求会落入该规则,有效防止IP直连绕过路由策略。
同一域名下多业务的路由策略
如果只有一个域名,但内部存在多个独立子系统,则无法依赖server_name区分,这时在location块中按Host头加一级判断,通过Nginx的map指令将域名字面量与内部服务组建立映射关系,再将请求回源到不同upstream池:
# 根据域名映射到不同upstream组名
map $host $backend_pool {
hostnames;
default backend_default;
api.example.com backend_api_pool;
static.example.com backend_static_pool;
user.example.com backend_user_pool;
}
upstream backend_api_pool {
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
upstream backend_static_pool {
server 10.0.2.11:8080;
}
server {
listen 80;
server_name api.example.com static.example.com user.example.com;
location / {
proxy_pass http://$backend_pool;
proxy_set_header Host $host;
}
}
map指令在Nginx启动时加载,映射结果直接写入Nginx worker进程内存,性能开销极低,这种方案比堆叠大量if条件判断更整洁,也更方便通过配置中心管理。
用OpenResty Lua实现动态分流
当路由规则需要频繁变更时,Nginx静态配置无法热加载,OpenResty可以在access_by_lua_block阶段动态决策upstream:
access_by_lua_block {
local host = ngx.var.host
if host == "pay.example.com" then
ngx.var.upstream = "backend_pay"
elseif host == "open.example.com" then
ngx.var.upstream = "backend_open"
else
ngx.var.upstream = "backend_default"
end
}
Lua方案适合高频调整或数据驱动场景,但要求团队掌握Lua语法,且在网关层增加了解释执行开销,绝大多数中小团队将Nginx静态配置与配置中心下发结合使用,已达到稳定与灵活的平衡。
核心要点三:七层负载均衡与云原生网关的域名级路由
保留客户端真实IP的问题
用Nginx做七层分发后,后端服务看到的源IP来自Nginx内网地址,需要在Nginx server块添加proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,后端服务再解析X-Forwarded-For头最后一跳的IP即可,若上游还套了云负载均衡(如简米云SLB),需在SLB开启“获取客户端真实IP”开关,否则三次转发头信息易被截断。
为什么不建议用TCP四层负载均衡做域名分发
四层负载均衡(如LVS、Nginx stream模块)工作在传输层,只能看到IP和端口,无法读取HTTP请求头中的域名信息,不少团队最初尝试用四层转发按域名分流,最终发现所有域名都进了同一后端,再在网关层二次分发,这种做法徒增了一跳延迟,也不利于限流与监控维度拆分,旁路四层流量全量镜像分析可行,但分发逻辑必须向上挪到七层。
Kubernetes Ingress场景中的域名路由
在K8s集群内,Ingress Controller负责域名路由,常见实现是Nginx Ingress,通过Ingress资源文件中的host字段定义域名规则,将api.example.com指向Service api-service,将web.example.com指向web-service,K8s内置Service天然负责Pod的负载均衡,所以Ingress的域名路由只需正确绑定Service名称即可,配置难度集中在证书管理与多环境隔离维度。
云上网关产品的选择依据
- 简米云ALB支持基于域名和路径转发,适合中小规模集群一键接入,且兼容WebSocket协议
- 酷番云CLB七层监听同样支持
Host头做转发规则,但未开启HTTP/2时部分客户端访问会拆成多TCP连接 - 自建Kong/APISIX则是微服务网关方案,路由规则可动态下发,适合后端服务数量众多、需要精确灰度控制的场景
核心要点四:DNS远端解析与后端健康检查的联动设计
后端不可用时的调度黑洞
DNS服务器只负责域名到IP的映射,不感知后端服务健康状态,若某地域的入口Nginx全部宕机,但DNS解析记录仍指向其IP,该地域用户直接访问失败,行业共识认为,DNS层应只负责按地域或运营商线路调度,后端服务的健康监测必须交给入口代理层。
多级健康检查的机制
- 云负载均衡定期向Nginx节点的健康检查端口发起HTTP探测(如请求
/healthz路径,期望返回2xx状态码) - Nginx自身通过
proxy_next_upstream指令配置上游失败重试策略,例如proxy_next_upstream http_502 http_503;让单个后端节点故障时自动切换到同upstream池下一个节点 - 入口代理层将后端实例状态上报至DNS服务商(部分云解析支持定时拉取负载均衡的健康状态),实现故障机房间的自动摘除
实战排查:域名分发没有按预期生效时
现象:api.example.com请求一直落入默认Web服务,而非后端API集群。
排查顺序:
- 在客户端执行
dig api.example.com,确认解析结果是否指向Nginx所在IP,若解析到其他IP,说明流量根本没进当前网关。 - 在网关节点
curl -H "Host: api.example.com" http://127.0.0.1,观察返回内容,若能正确匹配,说明是外层DNS问题,若仍落入默认服务,则检查是否写错。server_name
- 使用
nginx -T查看实际加载的完整配置,排查是否被其他server块覆盖。多个server块中server_name的值包含通配符或正则且加载顺序滞后时,容易发生隐式抢占。 - 检查
map指令内的哈希键,确认$host为去掉端口的小写主机名,而非$http_host携带端口和原始大小写的值。
配置要点与性能取舍建议
避免高成本容器级域名路由
每个域名一个独立容器或独立Nginx进程,虽然隔离性好,但资源占用过高,连接数管理也复杂,更推荐单Nginx实例多server块方式,按域名将配置拆分成多个文件,通过include /etc/nginx/conf.d/.conf统一加载,配置下发时先执行nginx -t校验语法再reload,避免配置错误导致所有域名瞬时中断。
连接复用与长连接
按域名路由会增加代理层连接转发动作,如果每个请求都新建上游连接,性能损耗明显,Nginx配置中设置keepalive 32;(upstream块内指令)维持与后端的长连接池,HTTP/2场景下连接复用效果更佳。
Q&A:按域名路由的常见疑问
智能DNS按地域解析能实现用户完全无损切换吗?
不能直接实现,DNS解析记录具备TTL缓存机制,客户端和递归DNS均会缓存旧记录,切换A记录或CNAME后,全球生效时间通常需要数分钟到数小时,无法做到会话级别的即切即用,要追求无缝切换,需要配合负载均衡层的健康检查摘除故障节点,或采用DNS预推送策略降低TTL至30秒左右。
按域名分流nginx配置时,正则匹配和精确匹配的执行顺序是什么?
Nginx在server_name匹配优先级中,精确匹配优先级最高,其次是通配符起始匹配(.example.com),随后是通配符结束匹配(example.),最后才轮到正则匹配,若两个正则server_name同时命中请求域名,则先定义者生效,在location层面的分发规则中,精确匹配优先于^~前缀匹配,随后是正则匹配,最终为普通前缀匹配,建议核心业务域名尽量使用精确匹配,降低误命中概率。
HTTPS证书配置与域名路由存在冲突吗?
不存在冲突,Nginx按域名分发时,证书绑定在server块中,ssl_certificate指令指向该域名专属证书即可,但在同一IP上配置多个HTTPS域名,必须依赖SNI(Server Name Indication)扩展,Nginx根据server_name自动选择证书,老旧客户端不支持SNI时,默认加载第一个HTTPS server块的证书,这可能造成证书不匹配告警。
最终落地的核心思路很简单:DNS层管“近”,代理层管“准”,健康检查管“活”,DNS负责将用户调度到距离最近的接入点,Nginx/网关负责精确匹配域名并按规则分发给后端服务,健康检查机制保障后端故障时调度策略自动收敛,配置时从外到内逐层验证,先确认解析结果,再检查转发规则,最后验证后端连接,即可让按域名路由的精准流量分发稳定落地。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/650435.html





