See multiple TCP connections when using HTTP/2 from chrome to node-http2 server
Asked Answered
F

1

7

UPDATE (for anyone interested in the outcome :)

I wasn't able to figure out why next protocol negotiation between chrome and node-http2 server fails. My suspicion was self signed certificate or ALPN/NPN support issue. So I moved to golang HTTP/2 implementation. The same setup works perfectly and I see single mutliplexed TCP connection (chrome --> golang)


I have been reading about HTTP/2 and how it solves the latency issue with HTTP/1.1 with single multiplexed TCP connection per host so I decided to try it out.

The experiment

  • created a simple html file with references to one css, one js and couple of images.
  • A simple http server in Node.js which serves all these files
  • Used chrome to make a http request
  • Used tcptrack on Ubuntu (tcptrack) to track TCP connections being made to the http server.

The tcptrack window shows 4 connections established. So the browser is opening different connection for image and css/js request.

Tcp track output for http/1.1 request from chrome

I get similar output using tcpdump. For reference tcptrack command used was

tcptrack -d -i eth0 -r 3600 port 8989

and tcpdump also shows similar output

tcpdump -i eth0 -nns 0 "dst port 8989 and tcp[tcpflags] == tcp-syn"

The simple all in one http server serving these files was something like below (relevant code)

(function(){
  ...........
  var server = http.createServer(function(request, response) {
      ..........
      fs.readFile(filetoRet, function (err,data) {
      if(filePath.indexOf(".jpg") >-1){
        response.writeHead(200, {"Content-Type": "image/jpg"});
      }.....
      
      response.write(data);
      response.end();
      });

   
  });
   

  server.listen(8989);  
})()

After this I tried using http/2.

  • Enabled chrome flag to send http/2 request
  • Created a http/2 server using node-http2
  • The simple http server has the same code as http/1.1 except that it uses http2 server module installed in step 2.
  • Made the request using chrome (It needed to be an https request inline with HTTP/2 spec)
  • Captured tcptrack/tcpdump output

tcptrack output for http/2

So, this still shows multiple TCP connections being made. Also if I increase the number of images in the html, the number of connections increases.

So I am not sure how to read this. Is this how HTTP/2 should behave (or is this a chrome bug)? Is there a better way to visualize the HTTP/2 gains using a simple http/2 client server?

Note:I am using self signed certificate for the HTTP/2 server so chrome throws a warning before proceeding to the page and possibly those closed connections represent it but I don't think it should impact how the page and its components are requested by protocol

Thanks for everyone's patience in reading this and appreciate any suggestions.

msingh

P.S : Wireshark TCP capture is no different. Just that I found it harder to isolate the traffic in Wireshark so used tcpdump and tcptrack.

Update: update: Looking at chrome://net-internals/ the HTTP/2 request negotiation fails and it falls back to using HTTP/1.1. Don't understand the reason yet.

The chrome internal tool events show

t=879052 [st= 0] +HTTP_STREAM_JOB  [dt=19]
                  --> original_url = "https://msinghlinux.ads.com:8900/"
                  --> priority = "HIGHEST"
                  --> url = "https://msinghlinux.ads.com:8900/"
t=879052 [st= 0]   +PROXY_SERVICE  [dt=0]
t=879052 [st= 0]      PROXY_SERVICE_RESOLVED_PROXY_LIST
                      --> pac_string = "DIRECT"
t=879052 [st= 0]   -PROXY_SERVICE
t=879052 [st= 0]   +HOST_RESOLVER_IMPL_REQUEST  [dt=0]
                    --> address_family = 0
                    --> allow_cached_response = true
                    --> host = "msinghlinux.ads.com:8900"
                    --> is_speculative = false
t=879052 [st= 0]      HOST_RESOLVER_IMPL_CACHE_HIT
t=879052 [st= 0]   -HOST_RESOLVER_IMPL_REQUEST
t=879052 [st= 0]   +SOCKET_POOL  [dt=19]
t=879071 [st=19]      SOCKET_POOL_BOUND_TO_CONNECT_JOB
                      --> source_dependency = 26961 (CONNECT_JOB)
t=879071 [st=19]      SOCKET_POOL_BOUND_TO_SOCKET
                      --> source_dependency = 26967 (SOCKET)
t=879071 [st=19]   -SOCKET_POOL
t=879071 [st=19]    HTTP_STREAM_REQUEST_PROTO
                    --> next_proto_status = "negotiated"
                    --> proto = "http/1.1"
t=879071 [st=19]    HTTP_STREAM_JOB_BOUND_TO_REQUEST
                    --> source_dependency = 26910 (URL_REQUEST)
t=879071 [st=19] -HTTP_STREAM_JOB

The value of next protocol is http/1.1 (next_proto_status and proto). But it doesn't say what failed in the negotiation that caused this fallback? Can the self signed certificate be the reason?

HTTP/2 Server code

var options = {
  key: fs.readFileSync('./server.key'),
  cert: fs.readFileSync('./server.crt')
};

options.log = bunyan.createLogger(...);
require('http2').createServer(options,function(request, response) {
      .... same code as http/1.1 server


}).listen(8900);
Femur answered 27/4, 2015 at 1:45 Comment(0)
M
1

I suspect that you are not actually using HTTP/2. There is a plugin for FF and I think some option for Chrome that shows you the protocol used in the address bar.

Note that HTTP2 will give you lower latency via a number of methods.

The single connection itself is not going to give you too much improved latency initially, at least not until it's flow control window increases. The point of the single connection is that it can grow it's window to optimal size and you stop getting slow start delays for each new connection created.

But HTTP/2 also has a push mechanism, where the server can know that the CSS, JS and images are associated with a page and proactively push them to the client along with a request to get the html. This saves on the round trip times to parse the HTML and then send new requests. Even more round trips are saved if the number of resources is more than 6 (the HTTP1 defacto connection limit).

We are running Jetty HTTP2 on our website and we have a page that demos push at https://webtide.com/http2-tests/push/

That image is made from many small images, which you tend to see load individually with HTTP/1, but they load as a block if you use HTTP/2

Maclay answered 28/4, 2015 at 1:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.