I'm using nginx reverse proxy cache with gzip enabled. However, I got some problems from Android applications HTTP-requests to my Rails JSON web service. It seems when I turn off reverse proxy cache, it works ok because the response header comes without gzip. Therefore, I think the problem is caused by gzip. What is the most appropriate level of gzip compression?

gzip               on;
gzip_http_version  1.0;
gzip_vary          on;
gzip_comp_level    6;
gzip_proxied       any;
gzip_types         text/plain text/css text/javascript application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss;
up vote 15 down vote accepted

The level of gzip compression simply determines how compressed the data is on a scale from 1-9, where 9 is the most compressed. The trade-off is that the most compressed data usually requires the most work to compress/decompress, so if you have it set fairly high on a high-volume website, you may feel its effect.

It sounds like your issues are more related to the HTTP headers on the requests. Usually gzip-compressed HTTP traffic is accompanied by the Content-Encoding: gzip header. If this is being dropped somewhere, then the client might not know to have to decompress the response.

  • How to disable gzip response using http request header from the client? I try Accept-Encoding: '', but it doesn't work. – Chamnap Mar 30 '11 at 4:01
  • From RFC2616 (w3.org/Protocols/rfc2616/rfc2616-sec14.html) I think you want just 'Accept-Encoding: ' with nothing following. – growse Mar 30 '11 at 8:28
  • Yeah, I added the header Accept-Encoding with empty string with poster addon on mozilla, and the response back without Content-Encoding: 'gzip'. However, on the android app, it always returns back in gzip. I checked what has been cached in the proxy cache directories, nginx caches the gzip content, so it's probably responses back in gzip. How to solve this? – Chamnap Mar 30 '11 at 9:03
  • Some sources suggest that the decompression resources do not increase as the compression level increases. Resources actually decrease in some cases as the compression level increases. stackoverflow.com/questions/28452429/… – user2208096 Oct 9 at 20:51

I tested this under nginx 1.3.9 with two files, and these were the results I got for the various levels:


text/html - phpinfo():

0    55.38 KiB (100.00% of original size)
1    11.22 KiB ( 20.26% of original size)
2    10.89 KiB ( 19.66% of original size)
3    10.60 KiB ( 19.14% of original size)
4    10.17 KiB ( 18.36% of original size)
5     9.79 KiB ( 17.68% of original size)
6     9.62 KiB ( 17.37% of original size)
7     9.50 KiB ( 17.15% of original size)
8     9.45 KiB ( 17.06% of original size)
9     9.44 KiB ( 17.05% of original size)

application/x-javascript - jQuery 1.8.3 (Uncompressed):

0    261.46 KiB (100.00% of original size)
1     95.01 KiB ( 36.34% of original size)
2     90.60 KiB ( 34.65% of original size)
3     87.16 KiB ( 33.36% of original size)
4     81.89 KiB ( 31.32% of original size)
5     79.33 KiB ( 30.34% of original size)
6     78.04 KiB ( 29.85% of original size)
7     77.85 KiB ( 29.78% of original size)
8     77.74 KiB ( 29.73% of original size)
9     77.75 KiB ( 29.74% of original size)

I'm not sure how representative this is but it should serve as an example. Also, I haven't taken the CPU usage into account but from these results the ideal compression level seems to be between 4 and 6.


Additionally, if you use the gzip_static module, you may want to pre-compress your files (in PHP):

function gzip_static($path)
{
    if ((extension_loaded('zlib') === true) && (is_file($path) === true))
    {
        $levels = array();
        $content = file_get_contents($path);

        foreach (range(1, 9) as $level)
        {
            $levels[$level] = strlen(gzencode($content, $level));
        }

        if ((count($levels = array_filter($levels)) > 0) && (min($levels) < strlen($content)))
        {
            if (file_put_contents($path . '.gz', gzencode($content, array_search(min($levels), $levels)), LOCK_EX) !== false)
            {
                return touch($path . '.gz', filemtime($path), fileatime($path));
            }
        }
    }

    return false;
}

This allows you to get the best possible compression without sacrificing the CPU on every request.

If you really can spare CPU resources, you can use 9, but for most sites a value of 2 is enough, since gzip doesn't reduce the file much after level 1.

Edit: I looked at Amazon CloudFront and it seems to be using level 6, probably because that level is the one that runs decompression faster, thus improving page render performance.

  • This isn't correct – calumbrodie Jul 26 at 14:28
  • 2
    Cloud you explain what's wrong about that? Anyways, I updated the answer, I researched a bit more and I see that sites like Amazon CloudFront uses a compression level of 6, probably because it's best about decompression speed (thus pages will load faster). – DiegoG Jul 27 at 17:16
  • 1) The difference between 2 and 6 is non trivial, it can up to 10-15%, look at the data or try it yourself. 2) the level of compression doesn't affect the difficulty to decompress (see stackoverflow.com/questions/28452429/…) – calumbrodie Jul 28 at 18:54

If you have high volume website and still would like to have a full level (9) of compression, the best idea would be to put your static content on Amazon S3 or similar object storage services and upload the compressed files.

You still would want to use nginx to compress your HTML, so better to keep that value to normal, I use 5 there.

  • I would want to use your suggestion, but I currently haven't included a comp_level in my config, so I can't tell what level I'm currently at. Do you know what the defaults are? Source? – Hassan Baig Feb 12 at 17:09

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.