How to limit the keep-alive TTL in Go Transport? - http

We have a proxy service built in Go. It needs to communicate with another service however the connection is busy enough ~20 req/sec that Go never terminates the keep-alive connection.
We don't want to completely disable the keep-alive, but rather have the connection gracefully closed after 60 seconds so it forces a reconnect.
Is this possible with the Transport directly or how would it be done with a ticker?

Related

go doesn't seem to honor persistent connections setting

I have a reverse proxy built using go. I have set it to use persistent connections. But when I monitor the open connections (using lsof -i) on my machine, looks like its closing connections within a few minutes despite me setting it for 60 minutes.
If I set other timeouts in the settings below, like ResponseHeaderTimeout, those are being honored.
myProxy.Transport = &transport{&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 200 * time.Millisecond,
}).DialContext,
MaxIdleConns: 0, //no limit
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 60 * time.Minute,
}}
Idle connections in http.Transport relies upon HTTP keep-alive as mentioned in http.Transport documentation. These settings are used by the transport while exchanging http payloads with peers (by adding appropriate keep-alive headers).
Having said that, HTTP keep-alive has to be agreed upon by both the parties in exchange (client and the server). Most of the servers restrict maximum number of open connections AND the duration (timeout) of open connections with keep-alive requests. This is done to avoid potential DOS attack and give all it's consumers fair chance with limited system resources at server (each keep-alive connection adds overhead on server).
A 60 minute idle timeout is way too high and I suspect any of the server will honor that (unless you control the server configuration on other end as well). Typically this is kept in few seconds to give enough time to a single HTTP page and all it's resources (css, js, images) to load from server using a single connection. Once a page loads successfully, there's no reason for the connection to be kept open in general browsing world. Apache HTTPD, by default, keeps KeepAliveTimeout as 5 seconds.
It's also worth noting, as clearly stated in Mozilla Keep-Alive documentation, timeouts longer than the TCP timeout may be ignored if no keep-alive TCP message is set at the transport level.
Given all these facts, this is absolutely normal for you to see what you see (connections being automatically closed). The transport will automatically initiate new connections as and when needed.

HTTP-Long Polling keep-alive and handshakes

I'm doing a test where I examine how much HTTP-long polling compared to Websockets is affecting the battery performance on my iPhone. Basically what I have is a Node.js with express server that sends out a random string every 0.5 or 10th second to the iPhone. I've inspected the messages in Chrome and I can see the keep-alive header is present. I know keep-alive is a default feature since HTTP/1.1. From what I've understood the TCP-connection will be held open and can be used for pipelining, and this is certainly the case when I'm sending out pings from the server every 0.5 seconds. But when I send out every 10 seconds, will the connection be closed during that time?
How do I know how long the connection is open? This seems to be a crucial part to have in mind when doing the tests.
Will the HTTP-handshake still be made when the TCP-connection is open?
AFAIK, in HTTP 1, the server cannot send a response back to the client if that client didn't send a request first. That might sound irrelevant to your question but bear with me.
The Connection: keep-alive header tells the client that it can reuse the connection if he want to, not that it must. The client can decide to close it any time, it all depends on the client library implementation and you don't have any guarantee.
The only way to force the client to not close the connection is to not finish the response. The only way to do that is to send a response with a Transfer-Encoding: chunked, and never send the final chunk (this has some serious caveats, like a buffer overrun on the client...).
So to answer your 2 points:
You can't, this low-level detail is totally hidden (for good reasons) from the client.
There is no HTTP handshake, there is a TCP handshake which is made when the client socket connects to the server socket. There is the TLS handshake which is made after the TCP connection and before any request is made. Once the connection is open, http requests are sent by the client and the server responds with resources.

Why are underlying TCP connections are released so late?

As you see above, the tcp connection release so slow.
I'm wondering how it happened and if it affect my program (http layer)?
This is persistent connections that defined by HTTP/1.1. When client makes requests to the server several requests can share one underlying TCP connection.
In your case request was performed and system waits for a while expecting other request. After 30 seconds inactivity it considers connection as idle and close it (sends TCP FIN).
About impact to the system: some resources are consumed for TCP connection handling. This may be an issue on huge servers handling millions requests but I don't think that this is your case.

What is an idle http connection?

I am working with http connection and using a MultiThreadedHttpConnectionManager and httpClient.
For my purpose I am closing all the idle connection after 1ms with the following method : closeIdleConnections(1).
I am wondering what is considered as an " idle connection" in http ? It seems that waiting for an answer is not an idle connection.
Regards,
HTTP (1.1) specifies that connections should remain open until explicitly closed, by either party. Beyond that the specification provides only one example for a policy, suggesting using a timeout value beyond which an inactive (idle) connection should be closed. A connection kept open until the next HTTP request reduces latency and TCP connection establishment overhead. However, an idle open TCP connection consumes a socket and buffer space memory.
Excerpt from RFC 7230:
6.5. Failures and Timeouts
Servers will usually have some time-out value beyond which they will no longer maintain an inactive connection. Proxy servers might make this a higher value since it is likely that the client will be making more connections through the same server. The use of persistent connections places no requirements on the length (or existence) of this time-out for either the client or the server.
When a client or server wishes to time-out it SHOULD issue a graceful close on the transport connection. Clients and servers SHOULD both constantly watch for the other side of the transport close, and respond to it as appropriate. If a client or server does not detect the other side's close promptly it could cause unnecessary resource drain on the network.
A client, server, or proxy MAY close the transport connection at any time. For example, a client might have started to send a new request at the same time that the server has decided to close the "idle" connection. From the server's point of view, the connection is being closed while it was idle, but from the client's point of view, a request is in progress.
By studying the source code, in the HttpClient MultiThreadedHttpConnectionManager implementation, connection is simply considered idle when the connection in the pool's age is more than the idleTime. The idleTime is passed to the method closeIdleConnections(idleTime) as an argument.

Use HTTP Keep-Alive for server to communicate to client

Recently in an interview I was asked how I would approach an online chat client application. I went through the standard "polling" solution but was cut off because the interviewer was looking for the "HTTP 1.1 keep-alive" method. Having used HTTP for quite a while and remembering that the whole point was to be "stateless", this never occurred to me (also, not to mention that the keep-alive is not consistently implemented).
My question is, is it possible for a web server to broadcast and/or send information to a client when the "keep-alive" header has been set?
With HTTP 1.1, keep-alive is the default behavior. (In HTTP 1.0, the default behavior was to close the connection.) The server must send the 'Connection: close" header to terminate the connection with the first response. So there is still a TCP socket available to push data through, but just pushing data from the server would violate the HTTP protocol in a major way. Even using keep-alive, the client would still have to poll the server.
It is important to distinguish between HTTP Keepalive and TCP Keepalive. HTTP keepalive prevents the connection from being closed by the server or client. TCP keepalive is used when the connection might be idle for an extended period of time and might be dropped by a NAT proxy or firewall. TCP keepalive is activated on a per-socket basis by setsockopt() calls.
When doing a 'long poll' to eliminate the need to re-poll, TCP keepalive might be needed.
Keep-alive simply holds a TCP socket open, so each time you poll, you save the overhead of the TCP setup/teardown packets--but you still have to poll.
However, "long polling" is a strategy for the web server to broadcast notifications to the client. Essentially, the client issues a GET request, but instead of immediately responding, the web server waits until they have a notification to send, at which point they respond to the GET request. This eliminates any need for packets to go across the wire for polling purposes, and keeps the connection stateless, which as you correctly mention is one of the purposes of the protocol.
You might read more about Comet servers. That sounds basically like the approach that the interviewer was asking about. Their effectiveness is disputed by some, but it has been used in several similar situations.
For example, I believe gmail uses comet technologies for some things (but don't quote me on it).
Another example that seems relevant is BOSH, which is a protocol for transmitting chat information using HTTP and XMPP. But I don't believe that using keep-alive is involved in that.

Resources