用压缩数据填充memcached,直接从nginx提供服务
在Python中,我生成复杂的静态页面。然后我把这些页面放到memcached里,这样下次有人请求时,就可以直接从Nginx提供这些页面,而不需要再去调用Python。
这方法一开始效果很好,直到我发现把未压缩的HTML存放在Nginx里效率很低。所以我尝试在存储之前手动对数据进行gzip压缩,然后让Nginx直接返回这些压缩后的数据(只需设置content-encoding:gzip),虽然Nginx的文档上说这样是可以的,但我一直没能成功。
在我的测试中,我让Python通过NPE的回答填充缓存,具体方法可以参考如何在Python中进行gzip压缩。我还把这些数据的memcached标志设置为1。
在没有其他更改的情况下,此时Nginx提供的是原始数据,这在浏览器中显示为乱码。
之后,我更改了Nginx的设置,为该位置设置了memcached_gzip_flag
字段为1,以便Nginx知道数据已经被gzip压缩,但Nginx仍然提供原始数据。我尝试了Nginx设置的各种组合:gzip on
和memcached_gzip_flag 1
,但在所有情况下,浏览器显示的都是原始数据(在第一次直接调用Python之后);有些情况下,firebug报告内容编码为gzip(但仍显示原始gzip数据),而在其他情况下,内容编码没有设置。
总体来说,我的计划是让Nginx能够提供已经压缩的数据,并带上正确的头信息,这样浏览器就能解压缩它。
我使用的是Nginx 1.6和memcached 1.4.13。
以下是相关的Nginx配置行,最初是可以工作的。第一次请求从Python获取数据并填充缓存,第二次请求则直接从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;
}
更新: 我进行了更多实验(详细信息在评论中),但仍然没有结果。
更新奖励:
我对此完全没有好的答案。基本上,我无法让memcached_gzip_flag
功能正常工作。给未来的回答者一个提示:如果你能回答这个问题,我会设置奖励并颁发给你。这比让一半的奖励自动颁发给完全错误的答案要好。
3 个回答
Memcached服务器本身不支持任何压缩功能。也就是说,使用Memcached的客户端需要自己负责压缩和解压缩数据。而且,客户端通常会有一个叫做CompressionThreshold的逻辑来处理这个问题。
对我来说,以下配置在nginx的memcached和gunzip模块中可以正常工作:
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服务器的响应中是否有特定的标志,如果有,就会把“Content-Encoding”这个响应头的值设置为“gzip”。
Memcached有一个内置的功能,如果你的数据超过20KB,它会默认进行压缩。也许在你的情况下,发生了两级压缩,浏览器在渲染时只进行了一次数据解压(前提是所有的头信息都没问题)。你可以查看Memcached的CompressionThreshold
选项。
这个文档的内容有点少,不过如果我理解得没错的话:memcached_gzip_flag
是用来指定缓存对象的 flag
中哪些位表示内容已经被压缩成 gz 格式。你需要这样设置:memcached_gzip_flag 1
,然后在存储数据时,确保对应的标志位被设置正确:
memcache.set('key', 'gzipped-value', flags=1)