Closed (fixed)
Project:
Drupal core
Version:
8.0.x-dev
Component:
cache system
Priority:
Major
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
2 Oct 2014 at 07:22 UTC
Updated:
18 Feb 2015 at 22:54 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
znerol commentedThis will fail due to the fact that
session_name()is not initialized at the point where theNoSessionOpenrequest policy is instantiated. This is resolvable by #2347877: Move DrupalKernel::initializeCookieGlobals() into a SessionConfiguration service.Comment #3
tim.plunkettMiddlewar sounds pretty cool :)
Comment #6
znerol commentedReroll.
Comment #8
wim leersThis was blocked on #2347877: Move DrupalKernel::initializeCookieGlobals() into a SessionConfiguration service, which has been committed yesterday!
Comment #9
berdirTest fails look like there's an issue with serializing non-serializable responses, like files, among other things.
I assume we somehow lost this part?
Comment #10
berdirCan we move drupal_page_cache_get_cid() into this as well (it is not used anywhere else I think) or at least wrap it in a method that is easy to override?
Goal: Solve #2062463: allow page cache cid to be alterable by making it easy to subclass this and replace the service.
Same here, move this part into a helper method, like writeInternalCache() would make it easier to explore some ideas I had with having a quickly expiring edge cache + a long-living page cache that uses cache tags for invalidation.
Extending on #9, I think we are missing the use for those two interfaces?
Comment #11
znerol commentedAgree, done.
Right, fixed.
What about extracting a storage class instead?
Comment #12
wim leersCan we get an interdiff? :)
Comment #14
znerol commentedOh, sorry. Forgot to attach.
Comment #16
wim leersThis is a misnomer; we call the parts that make up a cache ID "cache keys", but this returns the "cache ID", not "cache keys".
I bet it's the fact that this can easily be looked at as a key/value store type thing that made you think of this name, that'd make perfect sense in that context? :)
Other than that, this patch looks awesome! I think we want some profiling here to ensure we don't make things slower? But IIRC that already happened somewhere else, before #2257695: [meta] Modernize the page cache got split up into many child issues? Since so much time has passed, we probably want to do new profiling anyway though?
Comment #17
dawehnerIt would be pretty slick if we could stop including the page cache middleware, if its not configured to be executed.
Comment #18
berdirPossibly, but that would require a container rebuild when you change the setting.
That said, *if* we would that, we could drop the settings check there *and* the weird setting, because we would always check if enabled, so that might be quite interesting for performance. So maybe a follow-up to investigate that?
Comment #19
wim leersWow, that sounds fascinating!
dawehner++
Berdir++
Comment #20
znerol commentedTook me some time to fix the remaining test fails... Will address the pending feedback (thanks!) in a subsequent patch.
Comment #21
znerol commentedComment #22
znerol commentedAdressing #10 and #16.
Comment #23
znerol commentedI actually meant to pass through
$allow_invalid.Comment #24
dawehnerReally great work!
@znerol
What do you think about the follow up to pass the configuration on compiler dump time?
Why do we not just call ->forward in places we call pass?
Is there a reason we don't inject it atm. already?
Comment #25
znerol commentedRe #24:
forward()is also called from withinfetch(). Inliningpass()will result in a situation where a subclass would be incapable of telling the reason for a call to kernelhandle().Comment #26
dawehnerOkay, that is fair!
One thing which changed now, is that we inject the configFactory, so even if you have set
Settings::get('page_cache_without_database'the db is initialialized, additional to all other dependencies of the config manager. Not sure whether we should deal with it, given the idea of #17/#18
which would solve that problem again.
Comment #27
berdirThat's a very good point. Maybe we should not inject the config factory but add a @todo on a follow-up for the dynamic service definition idea? Definitely needs to be profiled.
Comment #28
znerol commentedAddresses #26, indeed very good point. Note that config is also accessed from within
fetch(). Thus a follow-up in the spirit of #17 will likely need to convert the compression-setting into a container parameter.Comment #29
berdirI think we have an open issue for that already somewhere, not quite sure, however.
Comment #30
wim leersLeaving at NR; just nitpicks for the fix of #16 :)
s/id/ID/
s/key/ID/
Comment #31
znerol commentedAttempting to perform some benchmarks without database access. Baseline is 8.0.x
HEADwith the mockcache module enabled and properly configured, database server turned off, PHP 5.6.4 with Zend OPcache v7.0.4-dev.$ ab -k -c1 -n1000 http://localhost:3000/(see attachments for the full log):HEAD
patch (db turned off)
Turns out that the early exit in
HEADsidesteps the call to$kernel->terminate()in the front controller. Since subscribers of the terminate event wish to access all kinds of stuff, the database connection is initiated there (and if the db is not available the request blows up in a weird way #2408435: Uncaught exception message is shown when exception is thrown during the terminate event).patch (db accessible)
The results above are with the db turned off and exceptions thrown all over the place, they are worse when the db is accessible:
patch (terminate removed)
When simply removing
$kernel->terminate()from the front controller, the results are as follows:I think the tiny regression is acceptable given it is well within the margin of error (= standard deviation multiplied by 2).
Just how we can get rid of
$kernel->terminate()for cached responses?Comment #32
wim leersDo we understand why there is a regression?
That's fair, but if it's consistently reproducible to have a lower throughput, then that argument would be less applicable.
Also note that the standard deviation is lower than that of HEAD, which is good. Can we also consistently reproduce that lower standard deviation? If we can, that'd be another reason in favor of the patch.
Comment #33
znerol commentedCurrently
DrupalKernelchecks whether the kernel has been booted before forwardingterminateto the http kernel. We simply could check whetherpreHandle()was run instead.Comment #34
berdirCan we add a comment here why we are doing this?
With that I think this is ready.
Will try to do something profiling on this as well.
Comment #36
dawehner+1 for the wrapping of \Drupal::config() for now.
@znerol
I think one approach we could indeed do is to use config to fill the compression setting, or lets be honest, this is not really something you need to configure through the UI IMHO.
Comment #37
znerol commentedRe #32 found the reason: Now that everything moved to the middleware, the response policy is also instantiated when cached requests are delivered (~ +200 function calls).
Comment #38
znerol commentedOh, and another fun thing: All middlewares are constructed as soon as the http kernel is instantiated. It follows that performance of the page cache depends on the dependencies of all middlewares - unless perhaps if those with heavy dependencies are constructed lazily.
Comment #39
znerol commentedI've reviewed usage of the
needs_destructiontag. In core it is only used forCacheCollectorand derivative classes (e.g. theme registry, alias whitelist) in order to update caches which accumulate entries over time. Therefore I think it is okay to simply fix the test here.Also addressed #34.
Comment #40
wim leers+1
#37: awesome!
#38: I'd hope #1973618: DIC: Lazy instantiation of service dependencies (ProxyManager for "proxy services") helps with that? :)
Comment #41
neclimdulre: #37, why was that not being called prior to this patch? Did we add the code using this service to improve performance characteristics in some way? I don't see a discussion of it in this thread.
Being as its sort of hard to pick them out, are there any other code changes that should be noted that aren't just moving code around that we could document in the summary?
Comment #42
znerol commentedI cannot follow, please elaborate.
This patch does not contain any functional changes. Even the change to
DrupalKernelregardingterminate()is just compensating for the earlyexitwe had before.The reason for the slight regression visible from #31 is that response policy is prematurely constructed as a result of injecting it. That being said, we could make the response policy lazy (as proposed by wim) after #2408357: The ProxyBuilder includes parent interfaces, which causes php errors. gets in. Benchmark looks like this then:
Head is
5.873 [ms](see #31), margin of error is 2.6. Difference between HEAD and patch with lazy loaded response policy in terms of function calls is 26.Comment #43
neclimdulYeah, I understood that injecting the service was causing this regression. I should have been more clear though. Injecting the services lead to the regression but if that code was being used previously it should have had similar characteristics that made me ask why we started injecting it. So I found the code calling this service which is just this one block of code.
This code did not exist previously so why was it added?
Also made me curious if there was any other code that was added to deal with the code being called differently or something.
Comment #44
znerol commentedOh, I see. That code still exists in
FinishResponseSubscriberwhere this was extracted from. That's why it does not show up in the patch. The response policy is evaluated two times now, once for the internal cache in the middleware and once when setting headers for external caches. Note that this was already the case for the request policy before.Comment #45
znerol commentedComment #46
znerol commentedCR draft
Comment #47
wim leersComment #48
wim leersDraft CR looks good.
Do you see any way to reduce that increase, or even turn it around into a decrease?
Comment #49
znerol commentedThe increase is due to the fact that the class loader needs to find the response policy. Removing it from constructor arguments results in 6 function calls fewer than
8.0.x.no response policy
lazy response policy
Comment #50
znerol commentedComment #51
znerol commented#2408357: The ProxyBuilder includes parent interfaces, which causes php errors. went in.
Comment #52
neclimdulRe: my other questions. I see now how the combination of the request policy check in handle() and the response policy check roughly match the logic in FinalResponseSubscriber.
Looking some more, can we merge these into a single method? They seem to do the same thing.
Comment #53
znerol commentedSee #24ff.
Comment #54
neclimdulThere doesn't seem to be a distinction in the documentation. The interface is our contract and both essentially document "pass the request though to the backend" so I'm still not clear why we need two. At the very least we need to document why we need two methods and what makes each useful.
Comment #55
znerol commentedI failed to come up with sane documentation. Moreover, if two experienced core contributors stumble over the same lines it is very likely that something is not quite right there.
How about removing
PageCache::forward()entirely and instead inline$this->httpKernel->handle()? I do not see any reason to override theforward()method in a subclass because the same effect can be achieved by simply adding another middleware between the page cache and the wrapped kernel.Comment #57
znerol commentedCannot reproduce the test-failure in
UserAccountLinksTests.Comment #58
znerol commentedReupload of #55.
Comment #59
neclimdulThat works for me. I don't see anything at this point that's a red flag and this is definitely where we where trying to go with the kernel. If Wim doesn't having anything else I'd support RTBC'ing this.
Hopefully we can start looking at tweaking logic to cut those calls out as follow ups too. Things like #1818628: Use Composer's optimized ClassLoader for Core/Component classes might minimize it at least.
PS - Thanks for putting up my the late questions and confusion! Great work!
Comment #60
neclimdulDang-it I lied. We should fix this.
Comment #61
znerol commentedRight.
PS - Thanks for the review, much appreciated.
Comment #62
wim leersRepeatingn znerol's test methodology of #31 on my system, to see whether I can reproduce. With one major difference: I'm not using the MockCache module, so I'm testing actual responses, of the actual D8 frontpage. PHP 5.5.11, no XHProf, no XDebug, with OpCache, with DB.
$ ab -k -c1 -n1000 http://tres/.The difference is negligible: the min, mean, sd and median are identical when comparing HEAD with the patch; only in the max is there a significant difference, but since all other numbers are the same, that doesn't really have any noteworthy effect.
Therefore, together with #59: RTBC. Great work, znerol! :)
Found these nitpicks, and fixed them:
Nit: s/preHandle/preHandle()/
These docs hadn't been updated accordingly.
Comment #63
alexpottLet's not do the config load if we don't have too. Yes we probably have already loaded system.performance - but we might not have so
Comment #64
znerol commentedComment #66
znerol commentedznerol--
Comment #67
wim leersOohh, well-spotted, Alex!
Comment #68
alexpottCommitted 1e985b0 and pushed to 8.0.x. Thanks!
Thanks for adding the beta evaluation.
Comment #70
berdirFollow-up: #2368987: Move internal page caching to a module to avoid relying on config get on runtime