当DNS更改时,Go传输连接保持活动状态

4
我正在使用go编写代理。 我正在使用标准库中的ReverseProxy和默认的Transport。假设我们的代理只有一个源主机。 我们将DisableKeepAlives设置为false,允许与源服务器建立多个空闲连接,并将IdleConnTimeout设置为60秒。 假设客户端每10秒钟使用代理向原始主机发出一次请求。 第一个连接将导致DNS查找以查找原始主机的IP。 传输将保持与该IP的连接永远不会关闭,因为我们在超时之前不断重用它。 Go缓存连接的方式是基于主机而不是IP。
假设那个主机的DNS记录更改并指向新的IP地址。我们仍将保持与原始IP的连接,因为这永远不会关闭,所以我们永远不需要建立新的连接,因此不会开始与新的IP通信(在假定原始主机在dns更改后仍处于活动状态的情况下)。
如果我们想设计一个系统,使其对DNS更改响应灵敏,什么模式是合适的?我想到的一个想法是设置一个无限循环,每N秒钟关闭任何空闲连接。这对上面的玩具示例有效,但在流量更大的情况下,有很大的可能性在刷新期间存在正在进行中的请求。
相比之下,另一种方法是仅设置连接可以存活的最长时间。但是,我无法找到一种操纵标准库以实现此目的的方法。
有人能指导一种对DNS更改响应灵敏的设计吗?

关闭空闲连接不会影响正在使用的连接,因为它们不是“空闲”的。只需设置IdleConnTimeout即可自动完成此操作。 - JimB
我正在设置 IdleConnTimeout。当连接实际上从未闲置那么长时间时,问题就会出现。尽管如此,我仍希望连接最终被关闭,以便在创建新连接时使用更新的 DNS。 - Austin Platt
好的,我明白你的意思了,你真正关心的不是空闲连接。现在Transport有了IdleConnTimeout,替换传输的蛮力方法可能是最容易协调的。 - JimB
1个回答

3
根据问题,代理实现似乎是设计为使用IP作为终点。

如果无法避免使用主机名作为目标端点,则可以配置httputil.ReverseProxy.Director以解析主机名。虽然需要查找时间(可以配置仅在DNS TTL过期时进行查找),但您将获得实时更新的目标端点,同时仍利用http.Transport的连接缓存。

示例Director

func director(req *http.Request) {
    addrs, err := net.LookupHost("yourdomain.com")
    if err != nil {
        handle(err)
    }
    if len(addrs) < 1 {
        handle(fmt.Errorf("No addresses found"))
    }

    req.URL.Host = addrs[0]
}

我认为这应该可以让我完成大部分工作,谢谢!剩下的问题是,如果我只向传输层传递IP地址,则无法使用TLS安全连接到原始服务器(因为这些服务器需要主机名)。我认为我可以通过保留IP到主机名的映射表并在连接时进行查找来解决这个问题。有更好的方法吗? - Austin Platt
您可以设置 req.Host,它将设置 Host 标头,以成为相关的域名。在 director 函数中:req.URL.Scheme = "https"req.URL.Host = addrs[0]req.Host = "thing.com"。这对我来说非常有效。 - glinton
但是在“传输”中,当我们拨号并建立连接时,我们只使用源服务器的地址进行连接(DialTLS func(network, addr string) (net.Conn, error))。在我们的情况下,该地址是IP地址,因此我们无法使用预期的服务器名称配置tls? - Austin Platt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接