【发布时间】:2021-11-26 13:58:53
【问题描述】:
简介
首先,我已经尝试了来自 C# DNS 相关 SO 线程和其他互联网文章的所有建议 - 弄乱了 ServicePointManager/ServicePoint 设置,通过 HTTP 标头设置自动请求连接关闭,更改连接租用时间 - 没有任何帮助.似乎所有这些设置都是为了解决长期运行的进程(如 Web 服务)中的 DNS 问题。如果一个进程拥有自己的 DNS 缓存以最小化 DNS 查询或操作系统 DNS 缓存读取,这甚至是有意义的。但这不是我的情况。
问题
我们的生产基础架构使用 HA(高可用性)DNS 在维护或功能问题期间交换服务器节点。它的构建方式是,在某些地方我们有多个 CNAME 记录,它们实际上指向同一个 HA A 记录:
- eu.site1.myprodserver.com (CNAME) > eu.ha.myprodserver.com (A)
- eu.site2.myprodserver.com (CNAME) > eu.ha.myprodserver.com (A)
所有这些记录的 TTL 为 60 秒。因此,当欧洲节点出现故障或维护时,A-record 会切换到其他节点的 IP 地址。
然后我们有一个监控实用程序,它每 5 分钟执行一次,并使用 site1 和 site2。为了使其正常工作,两个名称必须指向同一个 DC,因为 DC 之间的数据同步不会那么快发生。由于乍一看这两个 CNAME 实际上都链接到具有短 TTL 的同一个 A 记录,因此似乎没有任何问题。但事实证明它可以。
该实用程序是用 C# 为 .NET Framework 4.7.2 编写的,并使用 HttpClient class 执行对两个站点的请求。 Yeah, it's him again.
我们注意到,当发生服务器节点切换时,该实用程序通常会开始像 site1 和 site2 在不同的 DC 中一样运行。它在这些时刻的行为模式是严格确定的,因此它不会在过程中间的某个地方混淆 - 它从一开始就错误地解析了这些地址中的一个或两个。
我制作了另一个更简单的实用程序,它只向 site1 发送一个 GET 请求,然后开始有意地打开和关闭节点并运行该实用程序以查看哪个 DC 将满足其请求。结果非常令人沮丧。
尽管 Windows DNS 缓存已经更新(通过 ipconfig 和 Get-DnsClientCache cmdlet 检查)并且尽管整体记录的 TTL 为 60 秒,但 HttpClient 有时会继续向旧 IP 地址发送请求 15-20 分钟.即使我已经完全关闭了“过时”的应用程序服务器 - 该实用程序一直在尝试连接它,所以即使连接失败也不会唤醒它。
如果您在实用程序运行之间开始运行ipconfig /flushdns,那就更令人沮丧了。有时在 flushdns 之后,实用程序会意识到 IP 已更改。但是,一旦您制作了另一个flushdns(或者甚至不需要-我还没有100%清楚地弄清楚这一点)并再次运行该实用程序-它就会回到旧地址!难以置信!
并增加更多的挫败感。如果您在调用 HttpClient 之前使用 Dns.GetHostEntry 方法(根据 this comment 使用缓存)从同一实用程序中解析 IP 地址,则解析结果将是正确的......但是 HttpClient 无论如何都会连接到似乎是他自己独立选择的IP地址。所以 HttpClient 似乎不依赖于内置的 .NET Framework DNS 解析。
所以问题是:
- 新创建的 .NET Framework 进程从哪里获取这些缓存的 DNS 结果?
- 即使有某种神秘的全球 .NET 特定 DNS 缓存,为什么它绝对忽略 TTL?
- 它怎么可能在它已经“理解”一次地址已更改后恢复到过时的旧 IP 地址?
附:我通过实现一个自定义的HttpClientHandler 来解决这个问题,它对每个主机名的第一次使用执行 DNS 查询,因此它独立于外部 DNS 缓存(除了在中间 DNS 服务器上缓存,这也会在一定程度上影响事物)。但这在 TLS 证书验证方面有点棘手,最终解决方案似乎还没有准备好生产 - 但我们只将它用于监控,所以对我们来说没关系。如果有人对此感兴趣,我将展示类似于this answer's example 的类代码。
2021 年 10 月 8 日更新
该实用程序在公司代理后面工作。事实上,负载平衡有多个代理。所以我现在也在验证这一点:
- 如果 DNS 解析由代理执行并且它们不遵守 TTL,或者如果它们通过主机名缓存(保持活动状态)TCP 连接 - 这将解释整个问题
- 如果不同的代理有可能在实用程序的不同运行中处理 HTTP 请求 - 这将回答最令人沮丧的问题 #3
2021 年 10 月 15 日更新
“.NET Framework 是否具有独立于操作系统的全局 DNS 缓存?”的答案?是否。 HttpClient 类或 .NET Framework 通常与所有这些无关。将我的调查结果发布为已接受的答案。
【问题讨论】:
-
DNS 通常由操作系统处理,而不是由 .NET 处理。
-
@Neil 哦,我希望这一直是真的。正如我在帖子中所说,我确实验证了 Windows 的 DNS 客户端缓存并且它按预期工作。至少这是 ipconfig 和 Get-DnsClientCache 向我展示的方式:Windows 缓存中记录的 TTL 始终
-
如果你按照代码往下走,你会到达
Dns.GetHostAddresses,它会调用操作系统。它可能是一个中间解析器,它正在缓存而不是遵守 TTL -
@Charlieface 正如我在帖子中所说,我还测试了从实用程序中调用
Dns.GetHostEntry方法,它返回了正确的(实际)结果 - 就像 Windows 实用程序一样。我会看看Dns.GetHostAddresses是否返回不正确的内容。 -
@Am_I_Helpful 是的,我确实在没有代理的情况下尝试过,但问题没有重现。我什至发现了一些代理服务器搞砸的间接证据。我现在正积极与我们的代理服务器管理员合作,以弄清楚那里到底发生了什么。一旦出现问题,我将发布更新(希望对我自己的帖子有详细的已接受答案)。
标签: dns high-availability