Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

audit: multiple, costly round trips to any origin 🚙 (preconnect) #3106

Closed
addyosmani opened this issue Aug 23, 2017 · 24 comments
Closed

audit: multiple, costly round trips to any origin 🚙 (preconnect) #3106

addyosmani opened this issue Aug 23, 2017 · 24 comments

Comments

@addyosmani
Copy link
Member

addyosmani commented Aug 23, 2017

Description: Avoid multiple, costly round trips to any origin
Failure description: Page made 12 round-trips to 3 origins.
Help text: Consider using<link rel=preconnect> to set up early connections before an HTTP request is actually sent to the server. This will reduce multiple, costly round trips to any origin.

We had previously discussed suggesting <link rel=dns-prefetch> to pre-resolve DNS of a specific domain, but per @igrigorik if we're recommending preconnect, dns-prefetch is a no-op and we don't need to recommend both.

previously: #873

@wardpeet
Copy link
Collaborator

wardpeet commented Sep 4, 2017

I guess critical-ish assets are assets that are not preloaded and are not requested by the document itself? So all critical assets that are not picked up by the preload scanner?
yah this seems like a good place to start.
We'd have to see on a few sites what requests this would recommend preload for. To be more conservative we could start with only CRC depth = 2 requests.. (rather than depth > 2).
#931 (comment)

If not mistaken everything that is not covered by the preload audit we will ask to preconnect here? Should we consider all domains where we do a minimum of x requests?

@addyosmani addyosmani changed the title audit: multiple, costly round trips to any origin 🚙 audit: multiple, costly round trips to any origin 🚙 (preconnect) Sep 26, 2017
@paulirish
Copy link
Member

Preload is awesome if you know the exact URL.
Preconnect is useful if you don't know the exact URL but know the origin. That applies to a decent amount of 3rd party situations.

One approach is that we recommend you preconnect to all origins that are CRC depth >= 2. (depth == 1 excluded because IMO the preloadscanner should kick off those at about the same time).

I tried out this recommendation: I found some cases where this would include 20 origins.. I traced it to see if opening a crapton of sockets adds extra overhead and slows down the rest of the pageload. But the results are inconclusive. @igrigorik do you think that one needs to be conservative or might as well go wild and preconnect ALLLL the things?

@addyosmani
Copy link
Member Author

addyosmani commented Sep 30, 2017 via email

@yoavweiss
Copy link

yoavweiss commented Oct 1, 2017

One issue with the "preconnect all the things!!" approach: Chrome can only send 6 DNS requests at the same time. Preconnecting to unneeded hosts can then stall other DNS requests. Another side effect of that is that if you preconnect, you want to preconnect to all critical hosts in order (or just the first 6 ones).

I think a more conservative approach of recommending preconnecting to hosts serving critical or important content makes more sense, at least at first.

@paulirish
Copy link
Member

@yoavweiss thanks for weighing in! Appreciate it.
Separately from adding DNS resolution contention... is there CPU overhead in proactively opening a bunch of sockets? Blink's overhead of just starting a new network request is definitely measurable, so I didn't know if it's similar down in the net stack.

@igrigorik
Copy link

+1 for Yoav's points. I think we should recommend that you preconnect to a small (N<5) external origins. A large number of origins in critical path is its own anti-pattern, and something we could flag as separate warning -- you're dependent on a lot of origins, consider reducing this number.

(As an aside: do we have blocking / SPOF audits? Each additional blocking origin in CRP is an invitation for a SPOF).

In addition to the above, an important and overlooked property of preconnect:

  • Preconnect establishes a "clean" socket. Chrome's socket manager will keep an unused socket around for 10s. Meaning, the time delta between processing preconnect a request should be <10s.
  • Once a socket is "used", Chrome's socket manager will keep it around for a minimum of 300s.

So, preconnect to hosts that you will use soon.

@yoavweiss
Copy link

Separately from adding DNS resolution contention... is there CPU overhead in proactively opening a bunch of sockets? Blink's overhead of just starting a new network request is definitely measurable, so I didn't know if it's similar down in the net stack.

There were reports of preconnect contending on the I/O thread with other more critical activity, such as the Service Worker start. I also got reports of preconnect related delays which were hard to reproduce and seemed related to the extension-based WebPageTest agent, and failed to reproduce in the newer agents. So I don't know of current delays related to over-preconnecting, but it's probably safer to be conservative.

@paulirish
Copy link
Member

paulirish commented Oct 2, 2017

Sounds good guys. Thanks very much.

I summarized this and shared it with loading-dev (https://groups.google.com/a/chromium.org/d/topic/loading-dev/-n6b7byxqGA/discussion) in case there are any more insights we want to incorporate, but I'm already pretty happy with what we have here.

We can limit to hosts connected in the first 10s and some sort of sense of priority.


(As an aside: do we have blocking / SPOF audits? Each additional blocking origin in CRP is an invitation for a SPOF).

No we don't yet. I'll file a ticket for this. EDIT: filed Audit: SPOF detection · Issue #3463 · GoogleChrome/lighthouse

@addyosmani
Copy link
Member Author

I think we should recommend that you preconnect to a small (N<5) external origins. A large number of origins in critical path is its own anti-pattern, and something we could flag as separate warning -- you're dependent on a lot of origins, consider reducing this number.

This sounds pretty reasonable. Thanks for sharing your input, @igrigorik and @yoavweiss! What I'm hearing (pending further input on the loading-dev thread) is:

  • Overall: preconnect to (at most) 5 hosts you are likely to use soon, limited by connection in <10s
  • If Lighthouse sees 20 hosts that could qualify for preconnection in those 10s, perhaps suggest ~ "Of the N hosts below, preconnect to up to 5 of these that are most critical to your user experience"

Chrome can only send 6 DNS requests at the same time. Preconnecting to unneeded hosts can then stall other DNS requests.

Hmmm...I wonder if we should also be flagging over-preconnecting (e.g if a page is trying to preconnect to more than 5 hosts).

@wardpeet
Copy link
Collaborator

wardpeet commented Oct 3, 2017

Overall: preconnect to (at most) 5 hosts you are likely to use soon, limited by connection in <10s
If Lighthouse sees 20 hosts that could qualify for preconnection in those 10s, perhaps suggest ~ "Of the N hosts below, preconnect to up to 5 of these that are most critical to your user experience"
Just clarifying this for myself:

  1. Capture all domains that are being requested on the page. Measure the starttime of the initiator (or document) with the starttime of the asset and see if it's below 10s?

  2. Capture all domains until TTI or 10s and list them as preconnects.

I might create another audit or just add some kind of marking to the table that lists already preconnected domains which are over budget (>10s) and if we go over 5 hosts.

@wardpeet
Copy link
Collaborator

wardpeet commented Jan 23, 2018

@paulirish @addyosmani @patrickhulce Not much input was given on the loading-dev thread.

So to start on this would this be a good approach.

Capture all domains until TTI or below 10s from mainResource and list them as preconnects. (but only the first 5 hosts)

@patrickhulce
Copy link
Collaborator

Hmm, after coming back to this post-preload audit, I'm having trouble seeing the win with a separate preconnect audit.

Just to make sure I'm understanding right; we're looking for requests that are..

  • started <10s in
  • of a different origin
  • 2 or more levels deep in critical request chains (i.e. not discoverable by main document)

Perhaps I'm missing something, but it seems like the only requests different from preload will be all the 3+ levels deep critical request chain URLs that we just decided in review to explicitly filter out.

If our main concern is third party requests that you don't know the URL ahead of time, this already applies to the URLs we'd be surfacing over in preload and what if we just said "preload if you know the URL, preconnect to the domain if you don't" instead?

@addyosmani @paulirish WDYT?

@wardpeet
Copy link
Collaborator

critical requests 3 levels deep are hardly tagged as critical in our audits as they are hardly have a high priority. Wouldn't it be best to just scan all records before TTI or < 10s?

@addyosmani
Copy link
Member Author

addyosmani commented Feb 22, 2018

From a goals perspective, for third-parties specifically I use preconnect when I want to reduce the connection setup time for an origin but don't want to prioritize fetching (preloading) actual resources from it above other content in the critical path. I know it's really hard coming up with a criteria for capturing the difference here compared to preload otherwise...

Hmm. Another option here is doing some sort of special highlighting for third-party domains in the list of preload opportunities where we suggest those be preconnected to if they're not important enough to be preloaded. (effectively, agree with @patrickhulce if we can't define a different set of criteria here that perhaps this comes down to messaging)

Any further thoughts @paulirish?

@andydavies
Copy link

@addyosmani To return to the preconnect vs dns-prefetch discussion at the top…

Why not just include both i.e. rel="preconnect dns-prefetch", so there's a fallback for browsers that don't support preconnect?

@addyosmani
Copy link
Member Author

Why not just include both i.e. rel="preconnect dns-prefetch", so there's a fallback for browsers that don't support preconnect?

This is certainly something we could consider.

dns-prefetch has pretty decent cross-browser support: https://caniuse.com/#feat=link-rel-dns-prefetch
Support for preconnect is getting better, https://caniuse.com/#feat=link-rel-preconnect but while Safari and Edge haven't yet shipped support, mentioning a fallback seems reasonable to me.

@addyosmani addyosmani added P1 and removed P2 labels Mar 6, 2018
@paulirish
Copy link
Member

Why not just include both i.e. rel="preconnect dns-prefetch", so there's a fallback for browsers that don't support preconnect?

I like this a lot. Let's do this.


We have a plan for preconnect, but I think it was just under-documented.

  1. in the preload audit, we only show same-origin results. (the first checkbox of Preload audit improvements #4425)
  2. In the preconnect pr, we exclude same-origin
  3. In the preconnect pr, we exclude origins at depth===1 as we're already connected.

with that done, we can land #4362

@wardpeet
Copy link
Collaborator

wardpeet commented Mar 7, 2018

lets get cracking 😄

@ebizindia
Copy link

I generally recommend to preconnect to 3rd party resources which delay the onload event. This helps to save time in dns resolution + ssl connect.

The idea of limiting this to 5 sound like a good idea.

What's the latest on this?

@wardpeet
Copy link
Collaborator

@addyosmani @paulirish I think this one is done. Right?

@wardpeet
Copy link
Collaborator

Fixed by #4362

@cihati
Copy link

cihati commented Nov 28, 2018

I have Chrome "Version 70.0.3538.110 (Official Build) (64-bit)" , and I am still getting preconnect suggestions (even though I already have 5 in my page).

@patrickhulce
Copy link
Collaborator

@cihati can you file a separate issue with repro steps and the URL for us to take a look?

@charlespwd
Copy link

FYI, if you're from the future and you're reading this. Some of this info is out of date. The 6 request limit has been updated to 64 (in chromium) unless I'm poorly mistaken.

// Maximum of 64 concurrent resolver threads (excluding retries).
// Between 2010 and 2020, the limit was set to 6 because of a report of a broken
// home router that would fail in the presence of more simultaneous queries.
// In 2020, we conducted an experiment to see if this kind of router was still
// present on the Internet, and found no evidence of any remaining issues, so
// we increased the limit to 64 at that time.

https://source.chromium.org/chromium/chromium/src/+/main:net/dns/host_resolver_manager.cc;l=357-362?q=dns%20total_jobs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests