Problem/Motivation
The node links of each node are built using a lazy loader. Which means they are not cached and need to be rebuilt on every page.
On a default article node, that is about 10% of the whole processing time, mostly because of comment.module. Note that this also happens when e.g. displaying a teaser of 20 nodes on the frontpage.
The main reason this was done is that those links are often related to specific permissions and are sometimes not cacheable well. However, when we did this, we didn't have the cache context bubbling and other tools that we have now.
#2530846: Fix and improve comment cache tag usage makes comment links cacheable, the only remaining problem then are statistic counters. See that issue for some discussion on that, still need to take it over to this.
Proposed resolution
Remove the lazy builder, build node links directly. Figure out what to do with statistics view counters.
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#12 | 2556767-node-links-lazybuilder-12-interdiff.txt | 1.17 KB | Berdir |
#12 | 2556767-node-links-lazybuilder-12.patch | 4.5 KB | Berdir |
#10 | 2556767-node-links-lazybuilder-8-interdiff.txt | 4.04 KB | Berdir |
#10 | 2556767-node-links-lazybuilder-8.patch | 4.49 KB | Berdir |
#5 | 2556767-node-links-lazybuilder-5.patch | 470 bytes | Berdir |
Comments
Comment #2
BerdirSee comment #10 in the referenced issue for a start on doing this.
Comment #3
andypost+1 on idea, #10 is API change (makes method non-static)
To properly cache node links each link should carry access somehow, also
\Drupal\comment\CommentLinkBuilder::buildCommentedEntityLinks()
can be optimizedComment #4
Wim LeersI think you actually mean: remove the
'#create_placeholder' => TRUE
. Because keeping it as a#lazy_builder
means it can be placeholdered if actually necessary.Comment #5
BerdirOh, that is fancy.
Just removing that line makes the frontpage with a single node and comment (not statistics.module) 9% faster with 10% less function calls. That's almost a critical.
Now, the same with 10 articles. Starting to get critical ;)
And if you're not convinced yet, the same with smartcache.
However, it doesn't fully solve the problem.
a) We don't have auto-placeholdering yet for max-age 0 but that's an easy fix I think?
b) statistics module has no cacheability, also theoretically easy to fix.
c) But we don't really want max-age 0 there (which is the only thing we can do, really), we don't want to make the page 10% slower just to calculate that stupid counter every time. if anything, we would have a placeholder just for statistics so we can just calculate that and avoid the huge comment links overhead. Maybe we could combine lazy-builder with min/max-age caching or something.
Thoughts?
As written before javascript isn't a solution, one random idea I just had is clearing the node cache tag with a certain % chance, e.g. 10% or 1%. but that's, well, random to whether it works.
This will still fail on statistics tests at least. But this might be a big enough difference to just break statistics for a while with a non-critical follow-up to figure that out?
Comment #6
catchMax age is #2559847: Auto-placeholdering for #lazy_builder with bubbling of max-age.
Statistics I would personally let it get stale for a while.
JavaScript might be a solution if we render stale information in PHP then update it in JS?
Comment #8
Wim LeersThis being the entire patch, and it speeding things up so significantly by deleting a single line of code … amazing! :D
Berdir <3
+1
Comment #10
BerdirOk, what about this?
Added a max age setting to statistics, defaults to 3600. Tests set it to 0 but also test with a non-0 setting.
Comment #11
Wim LeersI think this reads a bit strange. What about
How long any statistics may be cached, i.e. the refresh interval.
?Nit: One unnecessary blank line there.
Comment #12
BerdirFixed that.
Comment #13
Wim LeersComment #14
alexpottberdir++
This patch is a great performance improvement. Committing this under the performance beta eligibility criteria.
Committed d562cd4 and pushed to 8.0.x. Thanks!
Comment #16
Wim LeersSo great to see that almost two years after #2151439: Run node op links ("Read more", "Add child page", "Printer-friendly version", "X views" + contrib) through #post_render_cache to prevent render caching granularity being per-user, we are now able to simplify it enormously thanks to #2429257: Bubble cache contexts :)
Marking those as related issues to simplify future archeological work.
Comment #17
joachim CreditAttribution: joachim commented> Remove the lazy builder, build node links directly. Figure out what to do with statistics view counters.
Is there any more info about how lazy builders are going to work for individual links? Was there a follow-up for statistics view counters? We need a lazy builder for a single link for Flag module, and I can't see how to do it...
Comment #18
BerdirI assume you're talking about a single link as part of a list of links and I don't think that is possible, not easily.
The only thing I could imagine is that you build a link with a manual placeholder in it that is then replaced for both the link and the label. That requires that you cache the access check however, so as I said in #2584647: Flagging access system not extensible, it is then important that deal with AccessResult/cacheability metadata correctly. access logic that shows or doesn't show the link for the node author needs to make sure that the author has a different variant of the cached node output.
Comment #19
BerdirThat said, I'd suggest you open an issue so that we can try and figure out a way to make that work. I think one of the problems is that a placeholder that isn't actually replaced into a link would then have empty
<li>
tags around it.Comment #20
joachim CreditAttribution: joachim commentedOk thanks!
I've filed #2587417: Unable to use lazy builders for individual links in hook_node_links_alter(), hook_comment_links_alter() -- hopefully I've described the problem clearly enough there, but feel free to correct any mistakes I may have made :)