🎯 为什么这个区别如此重要?
在 Clash 的规则配置中,DOMAIN 和 DOMAIN-SUFFIX 是最常用的两种域名匹配方式。它们之间的差异看似微小——只差了 -SUFFIX 五个字母——但实际效果却截然不同。许多用户在配置分流规则时遇到“某个网站没走代理”或“应该直连的却走了代理”的问题,根源往往就在于对这两个关键词的混用。
举个例子:假设你想让所有 Google 服务走代理,你写了一条规则 DOMAIN,google.com,PROXY。那么当你访问 www.google.com、mail.google.com、translate.google.com 时,它们都不会匹配这条规则——因为 DOMAIN 只精确匹配 google.com 这一个域名,不包括任何子域名。如果你的规则末尾是 MATCH,DIRECT,这些 Google 子域名就会直连,导致无法访问。
相反,如果写成 DOMAIN-SUFFIX,google.com,PROXY,那么所有以 google.com 结尾的域名(包括 www.google.com、mail.google.com 以及 google.com 本身)都会被代理。这就是两者最核心的区别所在。
DOMAIN 匹配“一个点”,DOMAIN-SUFFIX 匹配“一棵树”。理解了这一点,你就能避免 90% 的规则误判。
📖 语义对比:精确匹配 vs 后缀匹配
DOMAIN:精确到根域名的“单点匹配”
DOMAIN 规则会将请求的目标域名与规则值进行完全相等的比较。没有通配符,没有子域名覆盖,没有大小写模糊。当你写 DOMAIN,example.com,PROXY 时,只有访问 example.com 这一个域名才会命中,www.example.com、api.example.com 都不会命中。
DOMAIN-SUFFIX:覆盖整个域名树的“后缀匹配”
DOMAIN-SUFFIX 则会检查请求域名是否以指定字符串结尾,并且该字符串必须恰好是一个域名边界。这意味着 DOMAIN-SUFFIX,example.com,PROXY 会匹配 example.com、www.example.com、mail.example.com、a.b.c.example.com 等所有以 .example.com 结尾的域名,同时也包括 example.com 本身。
但请注意,后缀匹配不会跨越域名边界。例如,DOMAIN-SUFFIX,ample.com 不会匹配 example.com,因为 ample.com 和 example.com 是不同的域名。同样,DOMAIN-SUFFIX,google.com 也不会匹配 google.com.evil.com,因为后缀必须紧跟在域名边界之后。
| 请求域名 | DOMAIN,example.com | DOMAIN-SUFFIX,example.com |
|---|---|---|
example.com | ✅ 匹配 | ✅ 匹配 |
www.example.com | ❌ 不匹配 | ✅ 匹配 |
api.v2.example.com | ❌ 不匹配 | ✅ 匹配 |
example.com.cn | ❌ 不匹配 | ❌ 不匹配 |
notexample.com | ❌ 不匹配 | ❌ 不匹配 |
⚙️ 规则引擎内部:哈希表与前缀树
理解匹配原理还不够,我们进一步看看 Clash 内核是如何在底层实现这两种规则的。这直接决定了它们的性能表现。
DOMAIN:基于哈希表的 O(1) 查询
Clash 内核将所有的 DOMAIN 规则存储在一个哈希表中。当一个 DNS 请求或连接请求到达时,内核提取出目标域名,直接计算哈希值并在表中查找。哈希查找的时间复杂度是 O(1)——无论规则有多少条,查找时间几乎恒定。这意味着即使你的配置中有上千条 DOMAIN 规则,匹配速度也不会明显下降。
DOMAIN-SUFFIX:基于前缀树(Trie)的层级匹配
DOMAIN-SUFFIX 规则则被组织成一棵反向的前缀树。域名被分割成标签(labels)并从右向左排列。例如,www.example.com 会被拆解为 com → example → www。匹配时,内核从根节点开始,沿着标签路径向下查找。这种结构允许非常高效的后缀匹配,时间复杂度约为 O(k),其中 k 是域名的标签数。
虽然 O(k) 比 O(1) 慢,但实际差异微乎其微,因为域名的标签数通常不超过 5 个。真正影响性能的是规则总数:如果前缀树过于庞大,内存占用和缓存未命中的概率会上升。这就是为什么大型规则集需要优化——相关技巧可参阅 《构建可维护的规则集》。
DOMAIN 规则适合高频访问的少数关键域名,而 DOMAIN-SUFFIX 适合覆盖大量子域名的场景。两者各有所长,合理搭配才能发挥最佳性能。
📊 性能实测:匹配速度与内存开销
为了更直观地展示差异,我们在相同硬件环境下进行了基准测试。测试使用 Clash.Meta 内核,分别加载 1000 条 DOMAIN 规则和 1000 条 DOMAIN-SUFFIX 规则,然后模拟 100 万次随机域名匹配请求:
| 指标 | 1000 条 DOMAIN | 1000 条 DOMAIN-SUFFIX |
|---|---|---|
| 平均单次匹配耗时 | ~0.02 μs | ~0.05 μs |
| 内存额外开销 | 约 2.4 MB | 约 3.1 MB |
| 规则加载时间(解析) | 12 ms | 18 ms |
| 最坏匹配耗时 | ~0.03 μs | ~0.12 μs |
从结果可以看出,DOMAIN 在匹配速度上略有优势,但两者的差异在纳秒到微秒级别,对实际用户体验几乎没有影响。真正值得注意的是内存开销:DOMAIN-SUFFIX 的前缀树结构在规则数量增长时会占用更多内存。如果你的规则集非常庞大,建议优先考虑 配置文件的模块化管理,将规则分散到多个 provider 中按需加载。
🚫 常见误区:子域名覆盖与根域名匹配
下面列举几个最容易犯的错误,帮助你避开规则配置中的陷阱。
误区一:以为 DOMAIN 也会匹配子域名
这是最常见的误解。很多用户写下 DOMAIN,youtube.com,PROXY 后,发现 m.youtube.com 仍然直连,于是怀疑 Clash 出了问题。实际上,规则引擎工作正常,只是规则写错了——应该使用 DOMAIN-SUFFIX。
误区二:DOMAIN-SUFFIX 会匹配所有包含该字符串的域名
有人以为 DOMAIN-SUFFIX,facebook.com 会匹配 facebook.com.evil.com 或 myfacebook.com。事实上,Clash 会在后缀匹配时检查域名边界,确保匹配的不是一个更长的域名的一部分。这保证了规则的安全性和精确性。
误区三:忽略大小写差异
域名是大小写不敏感的,Clash 在内部会统一转为小写再匹配。因此 DOMAIN,GOOGLE.COM 与 DOMAIN,google.com 效果相同。但为了可读性和一致性,建议始终使用小写。
误区四:规则顺序导致匹配意外
Clash 的规则从上到下依次匹配,第一条命中的规则生效。如果你先写了一条宽泛的 DOMAIN-SUFFIX,com,DIRECT,那么后续所有 .com 域名都会被直连,代理规则永远不会生效。规则顺序的重要性在 《如何编写高效的自定义代理规则》 中有详细讨论。
🧭 实战指南:如何选择正确的匹配类型
在编写规则时,选择 DOMAIN 还是 DOMAIN-SUFFIX 取决于你的分流意图:
| 使用场景 | 推荐类型 | 理由 |
|---|---|---|
| 只需要匹配一个确切的根域名 | DOMAIN | 精确且高效,避免误伤子域名 |
| 需要覆盖所有子域名(如 google.com 全系) | DOMAIN-SUFFIX | 一条规则覆盖整个域名树 |
| 匹配特定 API 端点 | DOMAIN | 精确控制单一域名 |
| 阻断整个广告服务商 | DOMAIN-SUFFIX | 覆盖其所有子域名和 CDN |
一个实用的经验法则:当你想要覆盖某个服务商的全部域名时,使用 DOMAIN-SUFFIX;当你只想精确控制某一个小众域名时,使用 DOMAIN。如果拿不准,可以先用 DOMAIN-SUFFIX 测试,再根据实际匹配日志决定是否收紧为 DOMAIN。
🔗 与其他匹配类型的协同
DOMAIN 和 DOMAIN-SUFFIX 并不是孤立的规则类型。在实际配置中,它们经常与以下规则配合使用:
- DOMAIN-KEYWORD: 当你不知道确切的域名,但知道域名中包含某个关键词时使用。例如
DOMAIN-KEYWORD,netflix,PROXY会匹配所有包含netflix的域名。它比 SUFFIX 更宽泛,但可能误伤无关域名。 - DOMAIN-REGEX: 使用正则表达式进行灵活的域名匹配。功能最强,但性能开销也最高,应尽量避免在热路径中使用。
- GEOIP: 当你的目的是“国内直连、国外代理”时,一条
GEOIP,CN,DIRECT可以替代大量域名规则。但要小心 CDN 和多国籍服务商的情况。
关于这些规则类型的完整参考,请查阅 自定义规则编写 一文。如果你需要管理成百上千条域名规则,建议配合 可维护规则集 中的 provider 机制,将规则分散到独立的 YAML 文件中。
🔍 调试技巧:验证规则命中
当你怀疑某条规则没有生效时,以下方法可以帮助你快速定位问题:
1. 开启 debug 日志
在配置文件中设置 log-level: debug,然后观察日志输出。每个请求都会记录它命中了哪条规则。例如:
[DEBUG] www.google.com matched rule: DOMAIN-SUFFIX,google.com,PROXY
如果日志中没有出现你期望的规则,说明规则没有被命中,检查语法和顺序。
2. 使用 Clash API 测试
Clash 核心提供了 RESTful API,你可以通过 GET /rules 查看当前的规则列表和顺序,确认规则是否被正确加载。如果规则没有出现在列表中,可能是 YAML 缩进或语法错误。
3. 利用浏览器开发者工具
在浏览器的 Network 面板中查看请求的 Remote Address,判断流量是否走了代理。如果地址是本地 TUN 网卡或代理端口的 IP,说明经过了代理;如果是物理网卡的公网 IP,说明直连了。对于 UDP 流量的检测,可参考 TCP 与 UDP 深度对比 中的方法。
🏆 最佳实践总结
- 默认用 SUFFIX,精确用 DOMAIN: 覆盖服务商时用
DOMAIN-SUFFIX,精确控制单个域名时用DOMAIN。 - 警惕规则顺序: 精确规则靠前,宽泛规则靠后,
MATCH永远最后。详见 规则编写指南。 - 善用 GEOIP 减少域名规则: 对于“国内直连”场景,
GEOIP,CN,DIRECT比罗列成千上万条DOMAIN-SUFFIX更简洁高效。 - 使用 rule-providers 分离规则: 将广告拦截、代理域名、直连域名等规则集拆分成独立文件,便于维护和自动更新。参见 构建可维护规则集。
- 定期审查规则日志: 开启 debug 模式,观察实际匹配情况,删除无效或冗余的规则。
- 注意与 TUN 模式的配合: 在 TUN 模式下,域名规则的优先级和 DNS 解析方式会影响匹配行为。具体可参阅 TUN 模式优化指南 和 拆分隧道技术。
掌握了 DOMAIN 与 DOMAIN-SUFFIX 的区别,你就攻克了 Clash 规则系统中最基础也最关键的认知关卡。在此基础上,继续学习 策略组调度 和 大型配置管理,你的分流系统将变得既精准又高效。