分发规则匹配逻辑详解
为什么需要理解匹配逻辑
在真实的业务场景中,一个虚拟服务往往承载多种流量分发需求。例如:
/api/*转发到后端应用服务器/static/*返回静态资源/admin/*需要跳转到管理后台- 特定域名的请求转发到特定服务器池
- 来自某个 IP 段的请求直接拒绝
这些需求共存于同一个虚拟服务中,靠的就是多条分发规则 + 优先级 + 分发策略的组合。理解匹配逻辑,才能避免"规则写对了但效果不对"的问题。
来⾃ NGINX 的概念对照
如果您熟悉 NGINX 配置,以下对照表可以帮助快速理解矩尺平台的模型:
| NGINX 概念 | 矩尺平台对应 | 说明 |
|---|---|---|
server { ... } | 虚拟服务 | 定义监听 IP:端口 |
location /api/ { ... } | 分发规则(含 URL 前缀匹配策略) | 按 URL 路径分发 |
if ($host = "abc.com") { ... } | 分发规则(含 HOST 匹配策略) | 按条件匹配 |
if ($remote_addr ~ "10.0.0.") { ... } | 分发规则(含源地址匹配策略) | 按客户端 IP 匹配 |
rewrite ... | 七层 HTTP 策略 → 请求更改 | URL 重写 |
proxy_pass http://backend; | 处理方式 → HTTP 代理 + 服务器池 | 转发到后端 |
root /var/www; | 处理方式 → 静态资源 | 静态文件服务 |
return 302 ...; | 处理方式 → 重定向 | 重定向响应 |
error_page 404 /404.html; | 应用失效保障页面 | |
server 块中的多个 location | 多条分发规则(按优先级 + 顺序执行) | 多规则共存 |
核心区别:NGINX 通过 location 在配置文件中的书写位置和修饰符(= ~ ^~)来决定匹配优先级。矩尺平台则通过显式的优先级(高/中/低)+ URL 类型优先级 + 先后顺序三条规则来决定。
基础概念:策略与规则
在深入匹配逻辑之前,先明确两个核心概念:
分发策略:一个"条件"(匹配什么)
↓ 一条策略可包含多个条件(条件之间是"或"关系)
分发规则:一个"动作"(匹配后干什么)
↓ 一条规则可包含多条策略(策略之间是"与"关系)
虚拟服务:多条规则的容器
↓ 请求到达后,按优先级 + 规则匹配,找到第一条命中的规则执行策略内的"或"关系
同一条分发策略中可以添加多个匹配条件,条件之间为**"或"**关系——只要满足其中一个即命中。
例: 源地址策略中添加了 192.168.1.0/24 和 10.1.1.0/24 两个地址段。客户端 IP 为 192.168.1.10 时命中该策略(满足第一个地址段),客户端 IP 为 10.1.1.100 时同样命中。
源地址策略:
├── 192.168.1.0/24 ← 命中!
└── 10.1.1.0/24
请求客户端 IP = 192.168.1.10 → 策略命中 ✓规则内的"与"关系
一条分发规则可以绑定多条分发策略(不同匹配维度),策略之间为**"与"**关系——必须同时满足所有策略才命中该规则。
例: 规则绑定了 URL 前缀策略(/api/v1/)和 HOST 策略(www.abc.com)。请求必须同时满足 URL 以 /api/v1/ 开头 且 HOST 为 www.abc.com 才会命中。
分发规则 A:
├── 策略1: URL前缀匹配 = /api/v1/
└── 策略2: HOST = www.abc.com
请求 URL = /api/v1/users,HOST = www.abc.com
→ 策略1 命中 ✓,策略2 命中 ✓ → 规则 A 命中 ✓
请求 URL = /api/v1/users,HOST = www.xyz.com
→ 策略1 命中 ✓,策略2 未命中 ✗ → 规则 A 未命中 ✗匹配优先级总览
当同一个虚拟服务中有多条分发规则,且一个请求可能命中多条规则时,按以下层级裁决:
第一层:规则优先级(高 > 中 > 低)
↓ 如果同优先级有多条规则命中
第二层:URL 类型优先级(正则 > 完全匹配 > 前缀匹配)
↓ 如果包含 URL 策略且同类型有多条命中
第三层:配置先后顺序(UI 顺序 / API order 值)默认分发规则:如果所有分发规则都未命中,请求将由虚拟服务的"默认分发规则"兜底处理。
下面逐层详解。
第一层:规则优先级
每条分发规则可以设置优先级:高 > 中 > 低。
请求到达
├── 高优先级规则组:按顺序逐一匹配
│ └── 命中? → 使用该规则的处理方式,结束匹配
│ └── 未命中? → 继续下一个
│
├── 中优先级规则组:按顺序逐一匹配
│ └── 命中? → 使用该规则的处理方式,结束匹配
│ └── 未命中? → 继续下一个
│
├── 低优先级规则组:按顺序逐一匹配
│ └── 命中? → 使用该规则的处理方式,结束匹配
│ └── 未命中? → 继续下一个
│
└── 全部未命中 → 使用默认分发规则关键结论:高优先级规则只要命中就立即执行,不会再去尝试低优先级规则。
即使低优先级规则匹配得更精确,只要存在一条命中的高优先级规则,就会用高优先级的。
第二层:URL 类型优先级
当同一优先级下有多条规则命中时,如果这些规则都包含 URL 类型的策略,则按 URL 策略的匹配类型决定优先级:
URL 正则匹配 > URL 完全匹配 > URL 前缀匹配
(最优先) (最靠后)例: 三条规则都是中优先级,且都命中了同一个请求:
规则 1:URL 完全匹配 = /api/v1/login
规则 2:URL 前缀匹配 = /api/v1/
规则 3:URL 正则匹配 = /api/.*请求 URL 为 /api/v1/login,三条规则都能命中。按 URL 类型优先级,正则 > 完全 > 前缀,所以规则 3(正则)生效。
设计建议
利用这个机制,可以将精确匹配的规则设置为较高 URL 类型优先级,宽泛匹配的规则靠后。例如:/api/v1/login 用完全匹配指向特定服务器池,/api/ 用前缀匹配指向通用服务器池,无需手动调整规则优先级。
第三层:配置先后顺序
当同一优先级、同一 URL 类型的多条规则都命中时,按照在 UI 中的先后顺序(或 API 中的 order 值,越小越先)决定:
规则 1(在前) URL前缀 = /api/ → 先匹配 ✓
规则 2(在后) URL前缀 = /api/ → 不执行(规则 1 已命中)不带 URL 策略的规则之间,同样按先后顺序。
例: 两条中优先级规则都不含 URL 策略:
规则 1(在前):HTTP 方法 = POST
规则 2(在后):HOST = www.abc.com请求同时满足 POST 方法和 HOST = www.abc.com,因为两条都不含 URL 策略,按先后顺序裁决,规则 1 生效。
NGINX 用户实战对照
场景一:多个 location
NGINX 配置:
server {
listen 80;
location = /api/v1/health {
proxy_pass http://health_check_pool;
}
location ~ /api/.*/search {
proxy_pass http://search_pool;
}
location /api/ {
proxy_pass http://api_pool;
}
location / {
proxy_pass http://default_pool;
}
}矩尺平台配置:
所有规则设为同一优先级(如中优先级),利用 URL 类型优先级自动裁决:
| 顺序 | 分发策略 | 处理方式 | 说明 |
|---|---|---|---|
| 1 | URL 完全匹配 = /api/v1/health | HTTP代理 → health_check_pool | 完全匹配优先于前缀 |
| 2 | URL 正则匹配 = /api/.*/search | HTTP代理 → search_pool | 正则优先于前缀 |
| 3 | URL 前缀匹配 = /api/ | HTTP代理 → api_pool | 前缀匹配兜底 |
| 默认规则 | (无策略) | HTTP代理 → default_pool | 对应 location / |
场景二:location + if
NGINX 配置:
server {
listen 80;
location /admin/ {
if ($remote_addr ~ "10.0.0.") {
proxy_pass http://internal_admin;
}
if ($host = "public.example.com") {
return 403;
}
proxy_pass http://admin_pool;
}
location / {
proxy_pass http://default_pool;
}
}矩尺平台配置:
| 优先级 | 分发策略 | 处理方式 | 说明 |
|---|---|---|---|
| 高 | URL 前缀 = /admin/ + 源地址 = 10.0.0.0/8 | HTTP代理 → internal_admin | 内网IP访问admin,最高优先 |
| 高 | URL 前缀 = /admin/ + HOST = public.example.com | 指定错误码 403 | 公网域名访问admin被拒 |
| 中 | URL 前缀 = /admin/ | HTTP代理 → admin_pool | 其余admin请求 |
| 默认规则 | (无策略) | HTTP代理 → default_pool | 对应 location / |
要点:将最具体的匹配条件(策略多、限制严)放在高优先级,通用匹配放在低优先级或默认规则。
场景三:多 server(多域名)
NGINX 配置:
server {
listen 80;
server_name api.example.com;
location / { proxy_pass http://api_pool; }
}
server {
listen 80;
server_name static.example.com;
location / { root /var/www/static; }
}
server {
listen 80;
server_name _;
location / { proxy_pass http://default_pool; }
}矩尺平台配置:
由于矩尺的虚拟服务对应 NGINX 的 server,多域名场景有两种做法:
做法一(推荐): 同一虚拟服务内用 HOST 策略区分
| 优先级 | 分发策略 | 处理方式 |
|---|---|---|
| 中 | HOST = api.example.com | HTTP代理 → api_pool |
| 中 | HOST = static.example.com | 静态资源 |
| 默认规则 | (无策略) | HTTP代理 → default_pool |
做法二: 创建多个虚拟服务,各自监听不同端口或 IP(等同于多个 server 块)。
完整实战案例
需求
某公司网站 www.example.com 需要以下流量分发:
/api/v2/→ 新版后端服务(灰度中)/api/→ 旧版后端服务/static/→ 静态资源(已上传的压缩包)/admin/→ 管理后台(仅限内网 IP10.0.0.0/8访问,其余返回 403)- 首页
/和其余路径 → 静态资源中的index.html(SPA 应用)
矩尺平台配置
| 优先级 | 顺序 | 分发策略 | 处理方式 | 说明 |
|---|---|---|---|---|
| 高 | 1 | URL 前缀 = /admin/ + 源地址 = 10.0.0.0/8 | HTTP代理 → admin_pool | 内网可访问管理后台 |
| 高 | 2 | URL 前缀 = /admin/ | 指定错误码 403 | 外网访问/admin/被拒 |
| 中 | 3 | URL 前缀 = /api/v2/ | HTTP代理 → api_v2_pool | 新版API |
| 中 | 4 | URL 前缀 = /api/ | HTTP代理 → api_v1_pool | 旧版API(兜底) |
| 中 | 5 | URL 前缀 = /static/ | 静态资源 → 去前缀 /static | 静态文件 |
| 默认 | — | (无策略) | 静态资源 → 完全映射 | SPA:所有未匹配路径返回 index.html |
关键技巧
规则 1 和 2 都是高优先级且都匹配 /admin/,通过策略的多少来区分:规则 1 多一个源地址条件,只有内网请求同时满足两个条件才命中;规则 2 没有源地址条件,任何来源的 /admin/ 请求都命中(但只有规则 1 未命中时才会轮到规则 2,因为同优先级下规则 1 先匹配)。
实际上这里规则 1 包含了 URL 策略,会先进行 URL 匹配。URL 前缀相同的情况下,按先后顺序裁决——规则 1 在前,内网 IP 请求命中规则 1(同时满足 URL 前缀 + 源地址);外网请求 URL 前缀命中但源地址未命中,规则 1 不命中,继续往下,规则 2 命中(只要求 URL 前缀)。
常见配置误区
| 误区 | 正确理解 |
|---|---|
| "我把精确匹配放低优先级,但它后面还有高优先级的宽泛匹配" | 高优先级一定先执行,与匹配精确度无关。精确匹配应当放在更高优先级 |
"URL 前缀 /api/ 在前,URL 完全匹配 /api/login 在后,应该后面的精确匹配生效吧?" | 不会。同优先级下先匹配到 /api/ 就停了。应该把完全匹配放在前缀匹配前面 |
| "我设了多条同优先级规则,为什么总是第一条生效?" | 可能是因为多条规则都命中了同一个请求。检查是否有多余的策略导致误命中 |
| "默认分发规则和普通分发规则有什么区别?" | 默认分发规则没有匹配条件,当所有普通规则都未命中时才执行。每个虚拟服务恰好有一条默认分发规则 |
调试技巧
- 从简到繁:先用一条规则验证单个策略是否生效,再逐步增加规则和策略
- 利用日志:开启虚拟服务的客户端访问日志(日志功能),通过日志查看请求实际命中了哪条分发规则
- 使用 curl 精确测试:
# 测试特定 URL 路径
curl -v http://10.1.9.117:80/api/v1/test
# 测试特定 HOST
curl -v -H "Host: www.abc.com" http://10.1.9.117:80/api/v1/test
# 测试特定方法
curl -v -X POST http://10.1.9.117:80/api/v1/test