Attached patch fixes up some of the excessive caching we added during D7. In our zeal to avoid mysql load, we cache even fast queries because it is faster and more reliable to fetch from memcache, mongo, etc.
The patch creates cache_get_memory() and cache_set_memory() which no-op unless an in-memory cache backend is in use. Core won't set its DB backend to in-memory but memcache and others will. Setting this flag is all they have to do to gain these advantages.
You can see the node.module hunk of the patch that only a tiny change is needed at call time. This hunk refines the persistent caching added at #898360: Cache node types such that it only happens for memcache and similar backends. Upon positive feedback, I will add similar changes in other parts of core.
I think this is a good compromise. Open to other ideas.
Comment | File | Size | Author |
---|---|---|---|
0001-Add-memory-versions-of-cache_get-and-cache_set.-Redu.patch | 3.03 KB | moshe weitzman | |
Comments
Comment #2
catchLet's give this issue a less loaded title.
The node type caching is more than a 'fast query' exchanged for a cache_set()/get() - it also skips invocation of hook_node_type_info() and some other stuff. Whether there's a measurable improvement when using the MySQL cache backend would require benchmarks which I don't think have been done. But just because a cache_set()/get() wraps a fast query, doesn't mean that's the only thing that's being cached. For example if we'd moved all 'info/registry' hooks to an include in D7 (which we didn't do), then caching the result of hook_node_type_info() would prevent that include from being lazy loaded on every page.
Also we need a better name than in-memory to describe this. MongoDB isn't an 'in memory' cache backend - it also stores on disk. Similarly Redis is also backed by disk storage. And potentially you might want to use http://drupal.org/project/filecache for these things as well. The main point of caching stuff like this is not that it's faster than getting it from MySQL, but just to reduce overall requests to MySQL in favour of something else.
It might be better to specify a particular cache backend to skip, and then offer hook_skip_cache_backend_alter(). Core would add $skip_cache_backends = array('DrupalDatabaseCache'); - then another caching backend could come with a module that implements hook_skip_cache_backends_alter(), or custom code could do it to tweak something that's not worth caching for that site (or to remove DrupalDatabaseCache from that array). This might be useful if we sort out chaining of cache backends as well.
Comment #3
moshe weitzman CreditAttribution: moshe weitzman commentedOK, is true that instances of this patttern often save including some code in addition to a fast query.
I'm open to a better name than in-memory. I think it is fine though given that memory is the most frequent way to make caches fast. mongo writes to memory first according to the legendary http://www.xtranormal.com/watch/6995033/mongo-db-is-web-scale. then yes it writes to disk "later".
You say that the point of this is not to read from something faster that mysql but merely to remove requests/connections to mysql. are you suggesting that mysql is sufferring from too many connections or something?
I'm not really following the skip_cache_backend stuff. Each bin uses one and only one backend. How would it help to add a notion of skipped backends? Are you thinking that bins would use multiple backends with some priority?
Comment #4
catchWell it depends what the bottleneck is, if you are serving pages with 2, 5, 20 second queries then the amount of queries total is unlikely to be the bottleneck.
However you can:
- optimize slow queries to use indexes
- move slow queries into mongodb + EntityFieldQuery (where they'll be fast if done right)
- potentially have a simple site that mainly serves blog posts, maybe with an apachesolr-powered related posts block, comments and not much else.
If any of the above is true, then MySQL is going to mainly be handling CUD operations and lots of small read queries (anything that's not cached at all, and cache misses).
MongoDB, ApacheSolr etc. can generally handle much higher throughput than MySQL, so even if you moved your slow MySQL operations away, it's possible that with an increase in traffic, MySQL would continue to be the bottleneck - it still has to receive the SQL, parse it, fetch results, and send them back again.
Most of these smaller queries, as opposed to search or listing queries, are not slave-safe - they need to be bang up to date all the time - so they are much better suited to caching + expiration than replication. Also, it is much, much easier to add memcache memory (or servers) than try to scale MySQL sideways via replication. Adding extra memcache bins to a cluster is almost zero work comparatively.
Right I've been thinking about a stack of cache backends - an obvious one would be APC + memcache. So you'd put cache_bootstrap into both, have a version in memcache, when you invalidate APC, it would fall back to memcache so that each individual server doesn't have to do a full rebuild of the same cache item (especially now that we started adding global read locks to sites while some cache items are rebuilt). If you only have one backend and you skip it, then it would be the same as a no-op.
Comment #5
Fabianx CreditAttribution: Fabianx commented#1234830: Revert cache_menu patch removal, add a $conf setting instead (was: cache_menu: huge table size) will also profit from that as then n (= number of anchestor cache_gets) could be done instead of one slow DB query.
Comment #18
smustgrave CreditAttribution: smustgrave at Mobomo commentedWonder if this is still relevant for D10?
Comment #19
catchI think this can be closed as outdated. The example in the issue summary is already in a dedicated bin (cache_entity) and you can define a null cache backend for that if you really want to. But more than that sites wanting to optimize their cache layer should use redis or memcache instead of trying to tweak the database cache.
Comment #20
smustgrave CreditAttribution: smustgrave at Mobomo commentedThanks @catch!