Comments

vomiand created an issue. See original summary.

vomiand’s picture

Submitting patch.

vomiand’s picture

Status: Active » Needs review
vomiand’s picture

Posting updated patch

vomiand’s picture

One more update to fix cache invalidation

driki_’s picture

Patch proposal to ensure we have at least 4% gain on compression

driki_’s picture

StatusFileSize
new4.81 KB

oups sorry wrong patch

andypost’s picture

If compression going to be configurable I'd prefer to have igbinary

anish.a’s picture

Redis is supposed to be high performant cache. Compression is likely to slow down things way much, right? Any specific use case for this?

Jackinloadup’s picture

Amish, the ability to gzip responses can help greatly in being able to use lower priced hardware. The process of compressing and uncompressing data can speed up the overall time to transfer the large objects being passed back. I personally ran into an issue where our caching server didn't have enough bandwidth to keep up but plenty of CPU. Enabling gzip helped us push past that bottleneck without inuring more cost. I haven't reviewed recent benchmarks but there was some good material on this on the interwebs a few years ago.

slasher13’s picture

StatusFileSize
new4.66 KB
new155 bytes

remove patch file from patch

eiriksm’s picture

StatusFileSize
new4.91 KB
new1.82 KB

Here are some benchmarks:

Using this script:


$start = microtime(TRUE);
$cache = \Drupal::cache();

$i = 0;
while ($i < 100000) {
  $stuff = array_fill(0, 100, sprintf('%s%s%d%s', uniqid(), \Drupal::service('uuid')->generate(), rand(0, 10000000), \Drupal::service('uuid')->generate()));
  $cache->set('test-key-' . $i, $stuff);
  $i++;
}

$i = 0;
while ($i < 100000) {
  $cache->get('test-key-' . $i);
  $i++;
}

print sprintf("total time: %sms. Total memory: %d", microtime(TRUE) - $start, memory_get_peak_usage(TRUE)) . PHP_EOL;

The script was run with drush scr, and with cold (drupal) caches, and completely flushed and restarted redis.

Without gzip:
total time: 24.938342094421ms. Total memory: 58982400
Redis memory usage: 1128M

With gzip:
total time: 26.523010015488ms. Total memory: 58982400
Redis memory usage: 148M

So the performance hit for getting and setting 100K keys, with unnatural big is so small that for general get/set you have no way of noticing. The memory savings however is huge. Or huge wins, as the OP described it.

Here is also an updated patch that fixes some coding standard errors and edge cases.

berdir’s picture

Status: Needs review » Needs work
  1. +++ b/redis.info.yml
    @@ -4,3 +4,8 @@ package: Performance
     configure: redis.admin_display
    +
    +# Information added by Drupal.org packaging script on 2019-09-12
    +version: '8.x-1.2'
    +project: 'redis'
    +datestamp: 1568275689
    

    this shouldn't be added to the patch.

  2. +++ b/src/Cache/PhpRedisCompressed.php
    @@ -0,0 +1,45 @@
    +   */
    +  protected function createEntryHash($cid, $data, $expire = Cache::PERMANENT, array $tags) {
    +    $hash = parent::createEntryHash($cid, $data, $expire, $tags);
    +    $datalen = strlen($hash['data']);
    +    if ($datalen > 100) {
    +      // Minimum compression level has good ratio in low time.
    +      $zdata = @gzcompress($hash['data'], 1);
    +      if ($zdata && ((strlen($zdata) / $datalen) < 0.96)) {
    +        // We have at least 4% gain.
    +        $hash['data'] = $zdata;
    +        $hash['compressed'] = TRUE;
    +      }
    +    }
    +    return $hash;
    +  }
    

    I'm not sure I like the approach.

    This makes it PhpRedis specific, I'd instead suggest to make it a separate setting setting and putting directly into \Drupal\redis\Cache\CacheBase::createEntryHash.

    Not sure if the 4% check is a bit overengineered, is that really worth checking? I'd rather consider increasing the length to try compressing it in the first place.

    We could for example make the the setting, so Settings::get('redis_compress_minlength', 0) and if it's > 0, we compress if the length is higher. Then people can finetune it if they want to.

  3. +++ b/src/Cache/RedisCacheTagsChecksum.php
    @@ -65,7 +65,7 @@ class RedisCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTagsInv
     
           // We want to differentiate between PhpRedis and Redis clients.
    -      if ($this->clientType === 'PhpRedis') {
    +      if (in_array($this->clientType, ['PhpRedis', 'PhpRedisCompressed'])) {
             $multi = $this->client->multi(\Redis::PIPELINE);
             foreach ($keys_to_increment as $key) {
    

    this and all other changes below are then not needed anymore.

berdir’s picture

I also looked a bit into the compression level and gzcompress vs bzcompress, but it looks like gzcompress is considerably faster and doesn't make a big difference in size: https://labs.octivi.com/how-we-cut-down-memory-usage-by-82/

And based on the comment on https://www.php.net/manual/en/function.gzcompress.php, anything above the default 6 makes little difference as well and is likely not worth it.

berdir’s picture

Assigned: Unassigned » berdir

Working on this.

andypost’s picture

Btw ratio about compress/decompress makes me think about other algo support - zstd, igbinary, msgpack (they all mature last year in pecl).

berdir’s picture

Status: Needs work » Needs review
Issue tags: -redis compress gzip
StatusFileSize
new4.32 KB

This implements what I suggested, two settings for the length and level. Seems to work well in my own testing. It is passing tests (https://travis-ci.org/md-systems/redis/builds/642152240), I enabled it in the web test. I plan to commit this soon, but confirmation that this works from someone else would be great.

@andypost: We do support igbinary through the injected serializer, that was added for https://www.drupal.org/project/igbinary, but that didn't make it out of the experimental stage.

berdir’s picture

Status: Needs review » Fixed

Committed, seems to work fine for us.

  • Berdir committed 9645ac7 on 8.x-1.x
    Issue #2991121 by vomiand, driki_, eiriksm, slasher13, Berdir: Option to...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

ressa’s picture

Thanks everyone for adding this great feature, it is indeed a huge win! And thanks @eiriksm for sharing the script. I never heard about the drush php:script command before. But it came in handy for me today, because I wanted to check if compression was enabled ...

These are the results, and I can confirm that compression is enabled by default, via the settings.redis.example.php file, and also in Valkey, which I also tested in DDEV:

I adjusted the values for these two settings:
$settings['redis_compress_length']
$settings['redis_compress_level']

First column = "Compression Length / Compression Level".

Valkey 8.1.4 (October 2025)

None:     1.20G
100 / 1: 92.31M
100 / 6: 92.28M

Redis 7.4.6 (July 2024)

None:      1.21G
100 / 1: 117.73M
100 / 6: 117.75M

Interestingly, there were no almost no difference between compression level 1 and 6. It could be due to the test-nodes being very uniform?

I got the memory usage (used_memory_human) with this:
$ ddev redis-cli INFO MEMORY | grep used_memory_human

PS. Archived version of the Octivi article from 2014: https://web.archive.org/web/20140313012502/https://labs.octivi.com/how-w...