6

In python I generate complex static pages. I then put them into memcached so the next time they're requested, they can be served directly from Nginx (without hitting python at all)

This worked great until I realized how inefficient it was to store uncompressed html in Nginx. So I tried to manually gzip data before storing it, and get Nginx to return that directly (just setting content-encoding:gzip), but although Nginx's documentation suggests it's possible, I haven't been able to get it to work.

In my test, I had python fill the cache with data I gzip in python via NPE's answer at How do I gzip compress a string in Python? . I also set the memcached flag for these to 1.

With no other changes, at this point, Nginx serves the raw data, which gets displayed as junk in the browser.

After that, I changed the Nginx settings for that location, setting the memcached_gzip_flag field to 1 so that Nginx would know that data was already gzipped, but nginx still served the raw data. I've experimented with every combination of nginx's settings: gzip on and memcached_gzip_flag 1 but in all cases the browser displays raw data (after the first direct python hit); in some cases firebug reports that content-encoding is gzip (but is still showing raw gzip data) and in others, content-encoding is not set.

Overall, my plan of attack is to trick nginx into serving already-compressed data with the right headers so that browsers will unzip it.

I'm in nginx 1.6 & memcached 1.4.13

Here's the related nginx config lines, which originally would work. First hit gets data from python which fills the cache, 2nd hit serves directly from memcached.

location ~* <matching stuff> 
{
    if ($request_method = POST){
        break;
    }
    memcached_gzip_flag 1;
    set $memcached_key $uri;
    memcached_pass 127.0.0.1:11211;
    error_page 404 405 502 = @redo;
    default_type text/html;
}

UPDATE: I experimented more (details in the comments), but still no result.

UPDATE POST BOUNTY: I have no good answer at all to this. Basically, I can't get the memcached_gzip_flag function to work at all. Note for future answerers: if you answer this I will make a bounty & award it to you. This is preferable to having half of the bounty automatically awarded to completely wrong answers.

Community
  • 1
  • 1
fastmultiplication
  • 2,951
  • 1
  • 31
  • 39

3 Answers3

3

The documentation is a little sparse, but if I'm understanding it correctly: memcached_gzip_flag specifies which bits in the flag associated with the cached object indicate the content is already gzipped. You need to say something like: memcached_gzip_flag 1, then store the data with a flag having the matching bits set:

 memcache.set('key', 'gzipped-value', flags=1)
Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
  • the python memcache lib I'm using's set command definition looks like this: `def set(self, key, val, time=0, min_compress_len=0)` - I don't see any place to set the flag. Is my library just not exposing that functionality? – fastmultiplication Apr 24 '14 at 13:32
  • That is possible. The API reference I found is here, which is likely a different lib: https://python-memcached2.readthedocs.org/en/latest/memcacheclass.html – Dark Falcon Apr 24 '14 at 13:34
  • I am successfully setting flags using this lib. (telnetting to 11211 and doing `GET ` returns `VALUE ` and I can control the flag; when the data returned is gzipped, the flag is set to 1. and I've got memcached_gzip_flag 1 set in nginx, and have restarted nginx, but still no luck. – fastmultiplication Apr 24 '14 at 14:37
  • Have you checked the headers returned? Is the `Content-Encoding` header in the response? For reference, here is the code which should be adding the header: http://trac.nginx.org/nginx/browser/nginx/src/http/modules/ngx_http_memcached_module.c#L376 – Dark Falcon Apr 24 '14 at 14:49
  • Note that this code is checking `ngx_http_get_module_loc_conf`. If you have not done so, perhaps you could try setting the `memcached_gzip_flag` at the location level? – Dark Falcon Apr 24 '14 at 14:58
  • I checked the headers - I can control gzip header with a global "gzip on" but setting `memcached_gzip_flag` locally makes no difference. And having gzip on globally or not, in both cases I see raw gzip data. Added my config to the problem description. – fastmultiplication Apr 24 '14 at 15:10
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/51360/discussion-between-fastmultiplication-and-dark-falcon) – fastmultiplication Apr 24 '14 at 15:17
0

Memcached has a builtin behaviour where if your data is over 20KB, then it will compress it by default. Maybe what is happening there is two-level compression in your case, and the browser just do one data decompression when rendering (given that all headers are fine). Look for Memcached's CompressionThreshold option.

Marcel
  • 1,266
  • 7
  • 18
  • Are you sure it's memcached doing the compression, and not your access library? Many php libraries compress it by default over 20k - do you have references saying that memcached does it too? – fastmultiplication May 06 '14 at 09:09
  • Do you have any official memcached documentation of this? I haven't been able to find any. I've stored text data larger than 20k in memcached and then looked at it directly with `telnet 11211`; `get ` and it comes back uncompressed - are you saying that memcached is invisibly uncompressing it? – fastmultiplication May 07 '14 at 04:01
  • Memcached documentation I can find seems to indicate the client is doing the compression before sending it to memcached, not memcached itself. https://code.google.com/p/memcached/wiki/NewCommonFeatures and https://code.google.com/p/memcached/wiki/NewConfiguringClient – fastmultiplication May 07 '14 at 04:07
  • So you're saying you have not yet solved your problem? – Marcel May 08 '14 at 13:04
  • I am not certain that your link refers to memcached documentation - it's a low-rated comment without any links. Both the links from official memcached documentation I added in my comment refer to clients doing compression, and marking it with flags; neither refers to memcached doing the compression invisibly itself. Therefore, I think my original method to try to solve the problem is still valid, and the problem isn't that memcached is doing something I'm not realizing. – fastmultiplication May 08 '14 at 13:30
  • OK, have you tried to remove `default_type` directive from nginx config? because, I think if you compress it the header should be `Content-Encoding: deflate` or `gzip` – Marcel May 08 '14 at 13:33
0

Memcached server has no any compression. A memcached client have to compress/decompress. And clients usually have CompressionThreshold logic

For me, working following configuration with nginx memcached and gunzip modules:

ocation / {
  set $memcached_key "$uri?$args";
  memcached_pass memcached.up;
  memcached_gzip_flag 2; #  net.spy.memcached use second byte for compression flag
  default_type text/html;
  charset utf-8;
  gunzip on;
  proxy_set_header Accept-Encoding "gzip";
  error_page  404 405 400 500 502 503 504 = @fallback;
}

memcached_gzip_flag:

Enables the test for the flag presence in the memcached server response and sets the “Content-Encoding” response header field to “gzip” if the flag is set.

demon101
  • 544
  • 1
  • 11
  • 39