Employing QUIC Protocol to Optimize Uber’s App Performance
eng.uber.com
eng.uber.com
https://www.youtube.com/watch?v=QCEid2WCszM
A lesser known *ownside to HTTP/2 over TCP solution was actually caused by one of the improvements - a single reusable (multiplexed) connection - that could end up stalled or blocked due to network issues. This behavior could go unnoticed over the legacy HTTP/1.1 connections due to browsers opening a hugh number of connections (~20) to a host, so when one would fail it wouldn't block everything.
Our current load balancer doesn't support HTTP2 end-to-end (and we are dong gRPC), so we are load balancing TCP connections to the individual instances. And for certificates, we would use SANs to reduce the number of certificates being requested.
Put those two together, and browsers will assume that the first connection they make to serviceA.example.com can also be used for serviceB.example.com. Oops!
TLDR, certificates for HTTP2 need to be unique to each endpoint that terminates a browser connection.
If the server_name is established in the TLS session handshake, the client SHOULD NOT attempt to request a different server name at the application layer.
Yeah, looks like the browsers are allowed to do that, although it's not recommended.
Connections that are made to an origin server, either directly or through a tunnel created using the CONNECT method (Section 8.3), MAY be reused for requests with multiple different URI authority components. A connection can be reused as long as the origin server is authoritative (Section 10.1).
For https resources, connection reuse additionally depends on having a certificate that is valid for the host in the URI. The certificate presented by the server MUST satisfy any checks that the client would perform when forming a new TLS connection for the host in the URI.
There is a way to respond with an error code when a server receives a request for the wrong domain, but it seems like a bad idea to depend on it (because it means lots of failed requests that could be avoided with better certificate management):
A server that does not wish clients to reuse connections can indicate that it is not authoritative for a request by sending a 421 (Misdirected Request) status code in response to the request (see Section 9.1.2).
I think you want something like Envoy in the middle to actually terminate TLS (you can still use TLS to talk to the backends, of course) and do the load balancing. Having one backend handle one HTTP/2 connection does not necessarily balance load, anyway. With Envoy in the middle, you can again load-balance requests as though they were independent connections; if a browser has an HTTP/2 connection open that wants 10 expensive things, Envoy can use 10 backends to handle that request, rather than sending 10 expensive requests to 1 backend.
The statistics and traces you get for free are also very worthwhile, not to mention more advanced things like automatic retries, canarying, outlier detection, circuit breaking, etc.
We could have bypassed this by having a single pool of shared Envoy instances for ingress, but at the time we wanted to avoid the complexity of multiple teams managing a single Envoy configuration. In the next year we'll hopefully switch to Istio, which will help with the multi-tenant configuration management.
basically we have a gitlab instance at IP .8 / external at .210 and a nexus instances at .210 internally/externally however we have IPv6 addresses pointed at gitlab.
In firefox sometimes you could end in the wrong location and I had no idea why that was happening. it just failed. And only in firefox.
(btw. the behavior of firefox is just stupid. https://bugzilla.mozilla.org/show_bug.cgi?id=1190136)
Generally images are the lowest priority download, so ensuring higher priority items get downloaded first is important and not all H2 implementations do it well
Images are the lowest priority resource on the page and apart from the visual appearance aspects there are no dependencies on which order they're fetched in.
Most other resources on a page have greater side effects and and dependencies e.g. sync JS blocking the HTML parser, sync and deferred JS need to be executed in order etc.
You can saturate a last mile connection with image downloads in a way you man not be able to with other resources due to effect of the browser processing those resources.
any kind of packet loss kneecaps the performance of the whole thing, unlike http1.1.
FWIW, I work on the Netflix CDN, and specialize in server-side efficiency; we have had 100G flash CDN nodes for years serving at 90G+ in production. None of that would be possible with QUIC as it stands. I suspect our max B/W on these machines would drop from ~95Gb/s to 20Gb/s or less if we were to switch to QUIC.
https://www.netdevconf.org/0x13/session.html?talk-quic-offlo...
Don't blame QUIC. Blame ISPs and middlebox makers for abusing their (literal network-wise) position and breaking the end-to-end principle. History has shown that we just have to encrypt everything and quite literally cut out the middleman/box.
While we used the NGINX reverse proxy to terminate TCP, it was challenging to find an openly available reverse proxy for QUIC. We built a QUIC reverse proxy in-house using the core QUIC stack from Chromium and contributed the proxy back to Chromium as open source.
Experiment 2
Once Google made QUIC available within Google Cloud Load Balancing, we repeated the same experiment setup with one modification: instead of using NGINX, we used the Google Cloud load balancers to terminate the TCP and QUIC connections...
Since the Google Cloud load balancers terminate the TCP connection closer to users and are well-tuned for performance, the resulting lower RTTs significantly improved the TCP performance.
With a little more testing using UDP, I could see I was getting very spotty packetloss (<0.5%). I'd never tried changing the TCP algo before but I knew random packetloss is normally interpreted as congestion and hence causes a speed backoff.
I tried all of the ones available at the time but the one that stood out not only in performance but also simplicity was TCP-Illinois[0]. The stats provided by `ss -i` also seemed the most accurate with TCP-Illinois. I force enable it on every machine I come across now.
ipv6 - 1280 bytes
Edit: formatting
File "<stdin>", line 1
print len("Dear Uber, I need a ride from 26th and 6th Street, Brooklyn to 999 Broadway. I am on the south side of the road. It's 6:99PM UTC, I have 55% battery, my public key is b82c9238e847b. I like Jazz. My phone is a Pixel 3, I am using app version 4.22.4, but you probably already knew that. I am running out of things to add, so here is some personally identifiable information... and we still have plenty of bytes left")
^
SyntaxError: invalid syntaxI was dissapointed that the article didn't get into any details about the HTTP-level differences, but I think that's basically because they didn't need to know or care about the transport at that level since they were using Google's "cronet" library to dispatch the requests, and Google Cloud Load balancers as the QUIC termination point, so nothing on their ends actually deals with the neccessary differences from HTTP/2.
> Recently developed algorithms, such as BBR, model the network more accurately and optimize for latency. QUIC lets us enable BBR and update the algorithm as it evolves.
Again this is available for TCP in recent linux kernels[1]. And it's sender-side, so it should be unaffacted by ancient android devices.
Are they using ancient linux kernels on their load balancers? Or are the sysctl knobs for these features turned off in some distros?
[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin... [1] https://kernelnewbies.org/Linux_4.9#BBR_TCP_congestion_contr...
(Something like, make the entire standard journey from opening to the app to requesting a car over something custom, and then leave the rest of the app using TCP)