At present, the Drupal memcache module disables compression when using the memcached extension:
$default_opts = array(
Memcached::OPT_COMPRESSION => FALSE,
Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
);
This was discussed several years ago in #1472332: Implications of enabling compression and the consensus seemed to be that the benefits of compression were not worth the cost in terms of CPU.
However, lots of sites are moving from the memcache extension to memcached as a side-effect of upgrading to PHP7.x (as only the memcached extension has been updated to support PHP7), and we have seen quite a few suffer from significant performance degradation as a result of compression being disabled as part of this change.
The negative effects include:
- A dramatic increase in volume of data being transmitted.
- An increase in the number of cache items which have to be split as they exceed the size limit.
- An increase in evictions in memcached as much more data is stored.
It's possible to enable compression with the memcached extension e.g. in settings.php (this example is for D7):
$conf['memcache_options'] = array(
Memcached::OPT_COMPRESSION => TRUE,
);
...and we've observed a reversal of the negative performance impacts outlined above when compression is enabled like this. In some cases the performance improvement after enabling compression has been quite dramatic.
As the memcache extension does compression by default, mirroring that behaviour with the memcached extension seems reasonable; there should not be a net increase in CPU cost (assuming a site is moving from memcache to memcached), and the benefits of compression seem to be considerable in many cases.
We've seen enough evidence of disabling compression (as part of the move from PHP5.6/memcache to PHP7.x/memcached) causing significant performance degradation to advocate for compression to be enabled by default.
Patch(es) on the way; this should be done in both the D7 and D8 branches.
Comment | File | Size | Author |
---|---|---|---|
#14 | 2958403-14.patch | 1.24 KB | catch |
#2 | 2958403_enable_compression_d7.patch | 1.51 KB | mcdruid |
#2 | 2958403_enable_compression_d8.patch | 1.56 KB | mcdruid |
Comments
Comment #2
mcdruidPatches for 7.x-1.x and 8.x-2.x
Comment #3
Jeremy CreditAttribution: Jeremy at Tag1 Consulting commentedThanks for the patch; I'll do some new load testing to compare and confirm it's a win.
Comment #4
mxhHere are some observations using Gzip compression with Database backend.
Comment #5
webchick@Jeremy pointed me over to https://github.com/tag1consulting/drupal-loadtest which is what they use for load testing, if anyone is game to do this.
Comment #6
mcdruidThanks, I did a first pass at a load test using D7 and the current memcache-7.x-1.6 with and without the patch.
The test scripts are set up for D6 so I had to make a few minor tweaks (e.g. setting passwords through drush rather than just md5 straight into the db). I don't think I had to change anything particularly significant though.
This was with PHP 7.2 and D7 HEAD, using the memcached extension. The memcached deamon had pretty much default settings, with
-m 64
memory allocation.Initial results:
Before (i.e. no compression)
After (i.e. with compression enabled)
So my interpretation of those numbers are that the hit rates etc.. were not significantly different, but...
Without compression, 1598.50MB were written, and 156.30MB read. There were 30.5k evictions.
With compression, 529.18MB were written, and 95.55MB read. There were 16.1k evictions.
Very roughly speaking, compression resulted in 1/3 of the amount of data being written, 2/3 the amount of data read, and almost half the amount of evictions.
Here are the performance comparisons:
Before
After
I'm not sure how much to trust these numbers, as this test was run on my laptop using containers while it had several other things running... so this comparison may be less accurate than the memcache stats.
It looks like the site may have been very marginally slower with compression enabled, but I'd like to run these again in a more scientific test before drawing any real conclusions.
I suspect I may not have configured the test site perfectly (e.g. the changes which are marked as "todo: should be scripted"), as reflected by the 100% error rates for a couple of the rows.
IMHO whether the compression is "worth" any additional cost in CPU will depend on a few factors, but if data going over the network incurs any significant cost then that alone can cause performance degradation with no compression. The higher memory requirements for storing uncompressed data, and corresponding higher rate of evictions given the same allocation of memory can also be significant.
FWIW I think some D8 sites may cache significantly more data than this basic D7 test site, and it seems that the performance impact of handling uncompressed data is therefore greater.
For some simple sites that don't cache a large amount of data, the difference may not be much.
I'd still vote for compression on by default, at this stage... but I'm happy to do some more testing if this is a useful exercise.
Comment #7
mxhMaybe following points can improve the significance of the test results regards performance impact by compression:
Memcached
does not have an option to change this threshold :( Memcache does though.I'm trying to find some time playing around with the compression functions provided by the
zlib
extension inside the Memcache backend service, instead of usingMemcached
's built in compression. Probably worth checking out in case serialization is not the problem there...Comment #8
mxhI'm sorry that I can't deliver well-defined test results here atm, but I took some time playing around a little bit on a D8 project using 180+ modules. On its frontpage - not using page and dynamic page cache - 1582 config items, 135 discovery items, 7 bootstrap items, 87 entity items, 148 data items, 61 render items, 65 default items and 8 menu items are being loaded from the cache when cache items are valid. My findings on that:
I estimate (2.) for not being true at production mode, as the Memcache size would still be too small to handle all variants of cached items. I think the eviction rate would still be too high at this size. Luckily the Memcache size is way larger in production mode, yet having many evictions due to a very busy render and data cache bin. I already have worked against that with the help of the Cache Split module. Especially the render cache can be split up very well.
I also tried with
zlib
compression by adding a serialization+gzcompress (level 6 and level 3) and unserialization+gzuncompress step before get/sets, not using Memcached's built in compression. But this was visibly slower than Memcached's built in compression (up to 300 ms difference, but I could not exclude the volatility), maybe because it compresses all items including those which are smaller than 100 bytes. So I think myzlib
approach from above is not a valuable alternative.Next time I will try to reduce the volatility, and analyze the method's overhead with the help of Xhprof.
AS a result from my observations: For this project, using PHP 7.1, I would enable Memcached's built in compression in favor of
Edit: I fetched some numbers via Xhprof - 3 times - out of
Drupal\memcache\MemcacheBackend::getMultiple
regards the above mentioned frontpage (all numbers are milliseconds):Compression disabled:
(1) Request after drush cr: 183, 267, 262
(2) Request after (1): 170, 137, 195
Compression enabled:
(1) Request after drush cr: 198, 244, 250
(2) Request after (1): 192, 135, 135
So still the volatility thing here.
Then, looking at
Drupal\memcache\DrupalMemcached::set
I was quite surprised:Compression disabled:
(1) Request after drush cr: 700, 765, 509
Compression enabled:
(1) Request after drush cr: 533, 520, 451
I'm not sure, it could be that the environment processes were going wild when I looked at disabled compression. It just seems to me that compression is a completely negligible performance impact.
I guess, the more complex the project, the higher its volatility and by this, I would recommend using compression.
Comment #9
bkosborneI think a big benefit of using compression is that it's less likely you'll exceed the default memcache item size limit of 1MiB. The D7 version of this module accounts for items larger than that by splitting up the data into multiple chunks and then re-constructing them. There's some work to get that same procedure into the D8 branch as well but it's not committed yet.
Comment #10
vurt CreditAttribution: vurt as a volunteer and at Computer Manufaktur GmbH commentedI did a short benchmark on two quite big D8 sites (local memcached). The difference with compression was not huge and for my test cases it even seemed to be a little faster and consistent without compression.
Compression offers an advantage when the memcache server(s) are not installed on the same machine as the webserver and network throughput becomes more important.
I guess it is not really important if compression becomes the default or not. It is more important to document the options (with advantages and disadvantages). For really big sites owners should do benchmarks and compare for themselves anyway.
@bkosborne: This was missing for D8 a long time - happy to see this is on the way now.
Comment #11
bkosborneI want to re-iterate my point in #9. I recently found out that the PHP "memcache" extension has had compression enabled by default since version 3.0.3. Users that switch to PHP 7 and must use the Memcached extension will likely suddenly stop using compression, since the memcached extension does NOT enable it by default.
As a result, much less data will be available for storage, so evictions will be higher.
Comment #12
vurt CreditAttribution: vurt as a volunteer and at Computer Manufaktur GmbH commentedbkosborne, you are correct. We are on the safer side if compression is on as a default.
Comment #13
bkosborneComment #14
catchThe 8.x patch didn't apply. I've re-rolled it, and also instead of removing all the mentions of compression, changed the default to TRUE and updated the documentation to reflect the choice.
Also, generally agreed on enabling compression by default. 8.x stores things like entities which potentially have a lot of long text fields that are very compressible as well as render caching in general, so the ratio of items that will benefit from compression should be higher as well as there just generally being a lot more stuff to cache and therefore space/memory being more of an issue.
Comment #15
catchGiven this is something that can be enabled and disabled in settings.php, should we be adding the setting as a bit to memcache keys? That way changing it doesn't require a flush. Not sure what memcache does if it encounters compressed/uncompressed data when the setting is flipped.
Comment #16
vurt CreditAttribution: vurt as a volunteer and at Computer Manufaktur GmbH commentedI would just add something like "when changing this setting you need to empty the cache..." to the readme. It is not a setting that you change often.
Comment #17
Fabianx CreditAttribution: Fabianx at Tag1 Consulting for Acquia commentedRTBC + 1, let's get this committed
Given that we did not document changing it that much before, I'd suggest people should have an idea what they do when changing that setting.
In other words:
I do not think the key space we waste for storing the setting is worth the trouble of how less this will be changed in practice - especially if this sneakily is the default in memcache-3.0.3 anyway.
Comment #18
damiankloip CreditAttribution: damiankloip at Acquia commentedI have been following along, and had a couple of discussions about this too. I agree with the conclusions above. Going to commit this one. Thanks everyone for your input.
Comment #20
damiankloip CreditAttribution: damiankloip at Acquia commentedComment #21
mcdruidGreat - thanks for committing this for D8.
I created #2996888: enable compression by default with memcached extension (D7 branch) to get this into the D7 branch too.