Reputation: 113
I'm currently writing a proxy using go. I'm using the ReverseProxy from the standard library and also the default Transport from the standard library.
Suppose for this question that we only have one origin host for the proxy. We set DisableKeepAlives
to be false, allow more than one idle connection to the origin server and set the IdleConnTimeout
to be 60 seconds.
Suppose a client uses the proxy to make one request to the origin host every 10 seconds. The first connection will cause a DNS lookup to find the IP of the origin host. The transport will keep a connection open to that IP which will never be closed as we keep re-using it before the timeout. The way that go caches the connection is on the host rather than the IP.
Now suppose that the DNS record for that host changes and points to a new IP. We will still have our connection open to the original IP, and because this never gets closed, we never need to make a new connection and so will not start communicating to the new IP (on the assumption that the original host is still active after the dns change).
What pattern is appropriate if we want to design the system in such a way that it is responsive to DNS changes? One idea I had was to have an infinite loop which closes any idle connections which exist every N seconds. This would work for the toy example above but in the case where we have much more traffic flowing through, then there's a good chance that a request will be in-flight during the flush.
An alternative to that would be to just set a maximum length of time that a connection can be alive for. However I can't see a way to manipulate the standard library to achieve this.
Can anyone advise on a design which would be responsive to a DNS change?
Upvotes: 5
Views: 1997
Reputation: 27
Judging by the question, it seems that the proxy implementation was designed to use an ip as an endpoint.
If you cannot avoid using hostnames as your target endpoints, you could configure your httputil.ReverseProxy.Director
to resolve the hostnames. At the expense of the lookup time (could be configured to only lookup when the dns ttl expires), you'd get realtime updated target endpoints, while still utilizing the http.Transport
s connection cache.
Example 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]
}
Upvotes: 3