Skip to content

Conversation

@Meo597
Copy link
Collaborator

@Meo597 Meo597 commented Oct 19, 2025

  • ip 过滤 + fallback 实现精准境内外分流时,未知域名或 geosite 错误分类的域名,并行查询可显著降低延迟
  • 不过滤 ip 且有多个上游时,会选最快响应的,能轻微降低延迟;上游故障时能显著降低延迟
  • 多层回落 ip 过滤,如果某层有多个上游,但其中一个响应太慢也会拖慢速度,此 pr 无法 cover,除非启用乐观缓存缓解;或者未来把 DnsServerObject 内部改成多个上游且并行
  • 上面的 case 解决了,现在智能就完事了
  • 我又拉了一坨大的
{
  "dns": {
    "enableParallelQuery": true
  }
}

缓存重构(#5248)、乐观缓存(#5237)、并发查询(#5239)
三个 PR 相互冲突,如果全部接受得按这个顺序 merge
我好 rebase

此 PR rebase 后的 diff
https://github.com/Meo597/Xray-core/compare/rebased-new-dns/optimistic-caching..rebased-new-dns/parallel-query

@Meo597 Meo597 force-pushed the feat-dns-parallel-query branch from 67cef37 to 8b8abe9 Compare October 19, 2025 02:03
@t-e-s-tweb
Copy link

Is there any with combination of 5237 and 5239?

@Meo597
Copy link
Collaborator Author

Meo597 commented Oct 19, 2025

Is there any with combination of 5237 and 5239?

https://github.com/Meo597/Xray-core/actions/runs/18633074311

@Meo597

This comment was marked as resolved.

@Meo597 Meo597 changed the title feat(dns): Implement parallel query feat(dns): add parallel query Oct 21, 2025
@Meo597 Meo597 requested a review from Fangliding October 27, 2025 23:46
@Meo597
Copy link
Collaborator Author

Meo597 commented Oct 28, 2025

第一版糊的太粗糙了

因为一旦发现需要过滤 IP 就退出竞速模式(虽然并发请求,但是等所有结果返回再匹配)
这样路径上容易有单点故障,多写几组不同服务器也没用,因为没有分组的概念

而且除 IP 过滤外,tag queryStrategy skipFallback clientIP domains 也至关重要

现在改了第二版:
依然是先并发请求所有服务器
但组内竞速,更快的同时,还防止单点故障

为了不增加用户心智负担,特意把并发查询做成傻瓜模式
会自动把附近的规则相似的服务器归为一组
也就是说小白完全不需要理解它是怎么工作的,只要开启就能得到不小的提升


现在的设计能完全 cover 需求,并解决了这些坑:

  • 以前未知域名和被错误分类的域名要多等 1 rtt 四舍五入就是一个亿
  • 未知域名多写服务器就得多 rtt,少写又有单点故障
  • 递归挂的时候(cf今年三次)必须等四秒超时了才能响应
  • 得精心挑递归服务器,防止太慢拖垮速度,说的就是 Cisco + Oracle
{
  "dns": {
    "servers": [
      // 走直连试探 geosite:cn
      // 要求必须返回中国IP
      {
        "tag": "dns-direct",
        "address": "223.5.5.5",
        "skipFallback": true,
        "domains": ["geosite:cn"],
        "expectIPs": ["geoip:cn"]
      },
      {
        "tag": "dns-direct",
        "address": "114.114.114.114",
        "skipFallback": true,
        "domains": ["geosite:cn"],
        "expectIPs": ["geoip:cn"]
      },
      // 走代理试探 geosite:geolocation-!cn
      // 要求必须返回国外IP
      {
        "address": "8.8.8.8",
        "skipFallback": true,
        "domains": ["geosite:geolocation-!cn"],
        "expectIPs": ["geoip:!cn"]
      },
      {
        "address": "1.1.1.1",
        "skipFallback": true,
        "domains": ["geosite:geolocation-!cn"],
        "expectIPs": ["geoip:!cn"]
      },
      {
        // 未知域名、或者是上面规则回落下来的
        // 走代理,但用ECS试探是不是在中国
        // 不是就继续回落,获取代理CDN友好的IP
        "address": "8.8.8.8",
        "clientIp": "222.85.85.85", // 你当地ISP的地址,这样直连CDN友好
        "skipFallback": false,
        "expectIPs": ["geoip:cn"]
      },
      {
        "address": "8.8.4.4",
        "clientIp": "222.85.85.85",
        "skipFallback": false,
        "expectIPs": ["geoip:cn"]
      },
      "1.1.1.1"
    ],
    "tag": "dns-proxy",
    "enableParallelQuery": true
  }
}

本来写那篇用例是想抛砖引玉等有人把并行 DNS 给糊了,没想到还是得自己动手

@Meo597
Copy link
Collaborator Author

Meo597 commented Oct 29, 2025

目前三个 PR 在我的用例下测了几天,没发现什么问题。

只是设计上仍有些小瑕疵:

  • 组内竞速败者组预热缓存害怕上层取消 ctx (已解决)
    没看那块代码。使用没发现问题,设计上感觉脆弱
    直觉上,上层应该是超时取消而不是返回立即取消,否则乐观缓存也不可能异步刷新成功
  • 乐观缓存工作在 nameserver 级,竞速时其它 ns 可能 ttl 未过期,现在可能返回乐观缓存结果非最优
    并发模式下应该在 lookupip 再套一层缓存还能省点 cpu,而且返回的 ttl 也不会像现在这样乱跳
    这样设计如果用户进一步把原来的 ns 缓存禁用还能省点内存,但回源次数可能变多特别是上游 ttl 不一致时
  • 有些罕见的回落不应该预先并发请求,而是等真的回落了再做,比如走代理但 geosite:geolocation-!cn 响应了 cn ip
    类似 finalQuery 加个 parallelLazy 开关
  • 因 anycast, ecs 等原因一些递归解析结果非最优,写上去只是想当备份。现在只能靠禁用这台的缓存实现
    或许可以加个延迟发起请求,这样也能 cover 上一条需求

仅备忘,暂时不想动了
现在已经很够用了

@t-e-s-tweb
Copy link

t-e-s-tweb commented Nov 5, 2025

Getting a lot of these context cancelled errors. Also not getting any cache OPTIMISE in logs or the previous cache HIT in debug logs. I am using these in the order that you mentioned with rebases.
Screenshot_2025-11-05-02-27-31-52_9bb1ebbbe77763a71e2076eef80e3e18

@Meo597

Edit: added additional logs with dnslog. The site hkping.igamecj.com has very small TTL. So better for testing.

Screenshot_2025-11-05-19-55-18-49

@Meo597
Copy link
Collaborator Author

Meo597 commented Nov 5, 2025

@t-e-s-tweb
乐观缓存和并发查询等相互冲突,不能直接简单地 rebase
你使用的是这个版本吗?它在我这几个设备持续工作一周了
https://github.com/Meo597/Xray-core/tree/rebased-new-dns/parallel-query

@t-e-s-tweb
Copy link

@t-e-s-tweb 乐观缓存和并发查询等相互冲突,不能直接简单地 rebase 你使用的是这个版本吗?它在我这几个设备持续工作一周了 https://github.com/Meo597/Xray-core/tree/rebased-new-dns/parallel-query

Yes. This is the one that I am using. Its working fine. Only the logs show context cancelled or empty responses but the sites are browsable and connecting. But there isn't anyway to check if cache is being hit or optimistic is being used. Parallel queries logs do show them working.

@Meo597
Copy link
Collaborator Author

Meo597 commented Nov 5, 2025

因为我把 debug 日志那几行给注释掉了,它们设计的不好,太“重”了
缓存命中状态现在应该是只在 dns log 而非 debug 中显示

我晚点看一下 ctx 取消是咋回事

@t-e-s-tweb
Copy link

因为我把 debug 日志那几行给注释掉了,它们设计的不好,太“重”了 缓存命中状态现在应该是只在 dns log 而非 debug 中显示

我晚点看一下 ctx 取消是咋回事

Thanks. Here is the complete logcat for the domain.

Logcat.txt

@Meo597
Copy link
Collaborator Author

Meo597 commented Nov 5, 2025

Logcat.txt

  • 组内竞速败者组预热缓存害怕上层取消 ctx
    没看那块代码。使用没发现问题,设计上感觉脆弱
    直觉上,上层应该是超时取消而不是返回立即取消,否则乐观缓存也不可能异步刷新成功

之前就猜测过这块可能有问题,但我只用 udp 所以没发现
他不会导致任何出错,但影响缓存预热效果,我需要优化这一块

@Meo597
Copy link
Collaborator Author

Meo597 commented Nov 5, 2025

然后被我注释掉的那两行 cache debug log
想了想还是应该加回去

因为我搜了下各种热点函数都在 errors.LogDebug
也不差这两行了

Logger 应该先判定 level 再拼字符串

@Meo597
Copy link
Collaborator Author

Meo597 commented Nov 7, 2025

@t-e-s-tweb 感谢测试与反馈!

Getting a lot of these context cancelled errors.

现在,非 disableCache 的服务器,处于并发查询模式下,会忽略 caller 的 ctx.cancel() 以充分预热缓存。
我只用 udp 没发现此问题,是因为 udp 不受 caller 的 ctx 控制。


Also not getting any cache OPTIMISE in logs or the previous cache HIT in debug logs.

把 debug 日志加回去了。


测试时还发现一个 xray 原有的 bug:
其中一台服务器没有任何响应(比如网络错误),另一台服务器工作正常但不响应 ip 时(比如被规则过滤掉、比如不存在的记录)
预期应该是给客户端响应正常工作的那台服务器的结果:rcode 或空 ip
实际是不响应,导致 nslookup 和 dig 都会超时重试几次
顺手在这个 pr 改成能响应

其实这样还是有问题,如果什么 app 无视 rcode 3 疯狂重试
在一台服务器挂了的情况下缓存 rcode 3 没有任何意义
要么遇到 rcode 3 直接返回,不再尝试其它服务器
要么把上游服务器网络错误也给缓存一小会儿
要么把故障的服务器标记为故障一会儿也行
或者是实现上面说的给 lookupip 套一层缓存,而不是现在的 per nameserver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants