10 ms·
Stop Wasting Connections, Use HTTP Keep-Alive
- baybal2 8y agoOne more reason to do so: if you use client side TLS auth with a cert (or moreover a slow smartcard,) reauthenticating every connection will grind your performance to pieces.
- spockz 8y agoMy understanding was that with http/1.1 all connections are kept alive until a close is emitted. How is this different?
- mgartner 8y agoBased on https://en.wikipedia.org/wiki/HTTP_persistent_connection#HTTP_1.1 https://en.wikipedia.org/wiki/HTTP_persistent_connection#HTT... it sounds like your statement is correct. But the fact that the underlying HTTP connection is kept-alive by default doesn't necessary mean that the client is going to actually re-use that connection for multiple HTTP requests. And, in fact, in Node.js the connection is not reused by default.
- robocat 8y agoAlthough the keep alive periods may vary: https://fastmail.blog/2011/06/28/http-keep-alive-connection-timeouts/ https://fastmail.blog/2011/06/28/http-keep-alive-connection-...
- toast0 8y agoThe hidden danger, mentioned in the article, is if the client sends a second request while the server closes an idle connection. Until http/2, the client can't tell if the server closed the connection before or after it received the request. Many servers send a hint about the idle time out, but few client libraries process it (that I've seen). The larger the latency between server and client, the bigger deal this is.
- beagle3 8y agoThis is always an issue: you send an HYTP POST request (even on http/0.9) - and connection closes before you saw a response. Did the server receive it? You don’t know. Pipelining might amplify it, but it is always there, especially with unreliable mobile connections.
- adrianmonk 8y agoI wonder if it might be a minor performance issue in the worst case. Without keepalive, you create a new connection and pay the latency costs of doing so. With keepalive, there's a chance you try to reuse an old connection, and it fails, which requires round trips to learn about, and you still have the latency of creating a new connection. So more total latency in that case. It seems it would improve the average case but make the worst case slightly worse. If your keepalive timeout is short, maybe it would come up often enough to matter.
- toast0 8y agoIf it's the first request on a connection, and it appears that the server closes the connection, I have a reasonable expectation that the server doesn't care for my request. When the request times out, who knows -- most tcp stacks won't tell me it the server acked it, but many networks will fake acks these days anyway. On pipelined requests it's not too bad, you're not supposed to pipeline requests that aren't safe to retry. But pipelining ends up being somewhat rare in practice. Reusing an inactive connection is actually pretty risky, the server may be able to shut it down, your network may have silently dropped the connection already (some NAT timeouts are really short, I've seen cases in real mobile networks where the timeout was under a minute!). I'm not thrilled with multiplexing in http/2, but the sensible stream closure would be really nice to have. If you see a goaway, you know it it saw your request or not, so you can resend it with a clear concensce.
- beagle3 8y ago“Reasonable” to a human, maybe. If you are trying to build a robust system, in which requests don’t get lost, the difference is in quantity but not in quality - you must robustly handle the uncertainty in both cases.
- cetra3 8y agoSure, if Apple have fixed their issues with Keep-Alive for Safari: https://stackoverflow.com/questions/25372318/error-domain-nsurlerrordomain-code-1005-the-network-connection-was-lost/25996971 https://stackoverflow.com/questions/25372318/error-domain-ns...
- eridius 8y agoAccording to https://tools.ietf.org/html/rfc2068#section-19.7.1.1 https://tools.ietf.org/html/rfc2068#section-19.7.1.1 HTTP/1.1 defines the "Keep-Alive" header for use with keep-alive parameters but does not actually define any keep-alive parameters. I don't see a definition of this header in any of the RFCs that obsolete this one (just some mentions of issues with persistent connections and HTTP/1.0 servers, and the fact that Keep-Alive is a hop-by-hop header). MDN's documentation on this header references https://tools.ietf.org/id/draft-thomson-hybi-http-timeout-01.html#rfc.section.2 https://tools.ietf.org/id/draft-thomson-hybi-http-timeout-01... for the parameters, but this is an experimental draft that expired in 2012. Which is to say, I can't really fault Safari for not respecting keep-alive parameters that never made it out of the experimental draft phase.
- JdeBP 8y agoYou and eridius are talking about the Keep-Alive: header. The article at hand appears to be talking about the Connection: header.
- hkolk 8y agoBetter yet.. switch to http2 (where keep-alive is deprecated): https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ke...
- baroffoos 8y agoIts amazing that not everyone is on http2 yet when its basically free speed.
- Tharkun 8y agoIt's hardly a surprise. It takes time for people to migrate to new protocols. Not everyone can just leave 20 years of engineering effort behind and switch to HTTP2 because it's a bit faster in some situations.
- robocat 8y agoHTTP2 has multiple optimisations e.g. I only just realised it compresses XMLHTTPRequest requests, not just responses. We use CloudFlare, so most of our users get HTTP2 even though our own infrastructure is still HTTP1.1 (however some corporate customers have proxies, which usually downgrade the browser connection to HTTP1.1). We log whether HTTP2 or HTTP1.1 is used by the browser by JavaScript reading `window.performance.getEntries()[0].nextHopProtocol` which is supported by most modern browsers.
- zoeysaurusrex 8y agoI’m not amazed. While many stacks support it, most organizations still have lift on their end to implement this behind the other “priority” customer change requests.
- peterwwillis 8y agoOf all the micro-optimizations I could think of for web apps, the one with the highest cost and the least benefit would probably be supporting http2 (or *quic). In almost all cases, there is a fix that will speed up http1.1 to acceptable levels.
- jrochkind1 8y agoThe benchmarks say "to make 1000 HTTP requests", but I wanna know for sure if it was `https` (SSL) or not. The SSL connection init costs are real, although SSL session re-use can help there even without keep-alive.
- mgartner 8y agoThese metrics were collected for HTTPS specifically. I've omitted the URL I used in the benchmark scripts, but am using an HTTPS agent. Scripts live here: https://github.com/mgartner/node-keep-alive-benchmark https://github.com/mgartner/node-keep-alive-benchmark
- deleted 8y ago[deleted]
- superkuh 8y agoUnfortunately most people's primary computing devices are smart phones and smart phone radios cannot keep a TCP connection open, or won't, because of power usage.
- dmlittle 8y agoWhile this might be true for users connection to services there are also a lot of intra-serices connections that can keep TCP connections open and greatly benefit from doing so. For example, a microservice architecture where you have APIs communicating through HTTP with each other.
- ben174 8y agoThis article is talking about server-side services using keep-alive. Which are pretty unlikely to be running on a smart phone ;)
- sigjuice 8y agoWhy does the radio have to be on just because there is an open TCP connection?
- dmlittle 8y agoAre you asking why the radio has to be on or implying there are other reason that the radio could be on for? If you have a TCP connection open but the radio is off how are you going to receive incoming packets?
- toast0 8y agoIf it's a keep alive connection, you can just get the packets when you next turn on the radio. It's not a big deal to get the close right away; not that there's a good way to tell the system that. Anyway, you probably have a tcp connection open for the system push channel; if that requires the radio to stay on, it will be on.
- baroffoos 8y agoI thought the primary use case for this is you could load all of your websites resources on a single connection so you can make 100 file requests at the start and it only makes one connection.
- berkut 8y agoSo I've been writing a web server recently (mostly for learning purposes of HTTP and web stuff again as I've been out of that field for over a decade), and I've discovered that Firefox seems to be the only browser I've tried which still really utilises it fully and respects the headers: Safari sort of does, but only ever once, regardless of the header params, and Chrome never does, again, regardless of what the Connection header item says in the first response from the server. https://www.chromium.org/developers/design-documents/network-stack/http-pipelining https://www.chromium.org/developers/design-documents/network... shows they removed it in Chrome due to issues, and weirdly this Firefox ticket: https://bugzilla.mozilla.org/show_bug.cgi?id=264354 https://bugzilla.mozilla.org/show_bug.cgi?id=264354 (last updated 5 years ago), seems to show they're not going to enable keep alive for HTTP 1.1, but Firefox is most definitely utilising it.
- iforgotpassword 8y agoThese tickets talk about pipelining, not keep-alive. The chrome link specifically points out why they decided to disable it. Chrome and Firefox still support regular keep-alive and do reuse connections on http 1.1
- berkut 8y agoFair point, however I've seen no evidence Chrome is doing keep-alive on Linux or Mac OS - it always seems to send a FIN ACK after the response from the server to close the connection. Firefox most definitely is utilising it fully, and obeys the Keep-Alive params specified, which I can't see any of the other browsers doing.
- forreal1126 8y agotoo bad 99% of routers drop keepalives
- mh- 8y agoTCP keepalives != HTTP keepalives.
- tonyarkles 8y agoAlso, in my experience at least, it's not necessarily that routers drop TCP keep-alives, but rather that the keep-alive interval for most OSes is way longer than the router's connection timeout for idle entries in the NAT table. I was burned hard by this in Azure. It seems that the default expiry time is around 4 minutes for the TCP load balancers. You can bump it to 30 min, but if I recall the default interval on Linux is 2 hours. Any long-standing idle TCP connections would get into a state where both sides believed they were connected, but the packets would get dropped to the floor. When the LB timed out, it didn't emit any FIN or RST packets, so neither side knew it had been torn down. Fun debugging on that one. During the day there was enough activity to keep the connections alive, but at night they'd break. The overall behaviour was that the service worked great all day, but the first few actions out-of-business-hours would fail due to application-layer timeouts, and then everything would work great again until it had sat idle for a while.
- jazzyjackson 8y agoYou send heartbeats! There might be a max-connection-time but I haven't run into it, my connections being dropped through amazon infrastructure was solved by sending a few bytes (': <3' or '<!-- <3 -->') every 5 seconds or so.
- stevekemp 8y agoTCP keepalive should solve the problem too. Rather than HTTP keepalive. (i.e. To handle the case of "HTTP-Request", "huge delay", "final response". Rather than a streaming/chunking reply that is very long/slow.)
- iforgotpassword 8y agoA common mistake I see when people use libcurl is to create a new handle for each request, which pretty much guarantees no connection reuse. Reuse your handles for profit.
- swizzler 8y agoBe aware of the maximum connection bottlenecks in your stack, especially if you have an interactive app. I've had apache refuse new requests because old connections were holding slots.
- fabioyy 8y agoGRPC
- TYPE_FASTER 8y agoAssuming the client and server HTTP implementations don't have any bugs, and there aren't any network devices (proxies, etc.) in between, sure. Are modern clients able to start at HTTP/2, and gracefully degrade through HTTP/1.1 with keep-alive down to HTTP/1.0 if necessary? That would be really cool if so.
- dana321 8y agoOr better yet, use gzip and inline all images as base64 encoded. The file size is very similar to raw data, and the number of requests with associated http headers is reduced.
- mr_toad 8y agoMight be a good idea for statically generated pages, or the statically generated parts of pages, but I’d be wary of adding any more load to dynamic pages. Do any static site generators rewrite image links as data URIs?
- flomei 8y ago> Do any static site generators rewrite image links as data URIs? I'm using Hugo and this is at least no default behaviour, not sure though if there is a switch for that.
- SquareWheel 8y agoThat has some major downsides. No caching, so any shared images need to be re-downloaded on every page. And the size of base64 if about 40% larger in my experience. Request count is really not a big deal with HTTP/2 multiplexing.
- manigandham 8y agoDon't do this. Browsers are very optimized for subrequests and especially parsing image data. By forcing base64, you're eliminating all the caching and using much more CPU power to parse that back into a binary image. You're also making the page load slower as the initial payload is bigger and image data has to be handled in line rather than asynchronously.
- hidiegomariani 8y agoI believed keep alive was enabled by default on browsers with HTTP1.1
- dmarlow 8y agoWhat's the advice these days for when things are behind a reverse proxy or a load balancer, or both? I ran into issues where things end up balancing unevenly when multiple things are mixed.
- nvarsj 8y agoPeople seem to always get confused by this - http/1.1 is persistent by default and the vast majority of servers/clients use it. The "Keep-Alive" header was something tacked onto http/1.0 and doesn't really mean anything these days.
- tyingq 8y agoUnfortunately, depends on the server. Node says this: "Sending a 'Connection: keep-alive' will notify Node.js that the connection to the server should be persisted until the next request." The article seems to confirm this behavior. So clients have to account for non RFC compliant servers.
- nvarsj 8y agoAre you sure about that? That seems to violate the http/1.1 RFC. I think the node.js docs are talking about http/1.0 there. http/1.1 uses the "Connection" header to indicate whether to persist the connection.
- snek 8y agoyou don't need that npm library. just `new Agent({ keepAlive: true })` works
- paulddraper 8y agoI switched servers to Keep-Alive, but then I found out that it would introduce race conditions, at least with the Apache HTTP Client. The client would in the middle of sending a new request, but the server would have already decided to close the connection and the request would fail. I believe this is a common problem, can and yet the spec has nothing to address this obvious race condition. Right?