用压缩数据填充memcached,直接从nginx提供服务

6 投票
3 回答
2282 浏览
提问于 2025-04-18 04:05

在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 onmemcached_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 个回答

0

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_gzip_flag:

这个设置会检查memcached服务器的响应中是否有特定的标志,如果有,就会把“Content-Encoding”这个响应头的值设置为“gzip”。

0

Memcached有一个内置的功能,如果你的数据超过20KB,它会默认进行压缩。也许在你的情况下,发生了两级压缩,浏览器在渲染时只进行了一次数据解压(前提是所有的头信息都没问题)。你可以查看Memcached的CompressionThreshold选项。

3

这个文档的内容有点少,不过如果我理解得没错的话:memcached_gzip_flag 是用来指定缓存对象的 flag 中哪些位表示内容已经被压缩成 gz 格式。你需要这样设置:memcached_gzip_flag 1,然后在存储数据时,确保对应的标志位被设置正确:

 memcache.set('key', 'gzipped-value', flags=1)

撰写回答