Hello!
不好意思,我的上一封邮件存在严重的编辑错误(这是写长邮件时很容易出现的问题,嘿嘿)。现重新编辑如下:
2012/10/10 luo.zj:
> 你好,我正是使用ngx_memc 和ngx_srcache来缓存内容,为了客户端能够进行缓存需要将last-modified放到头部,
> 可是由于非文件的形式response header中并不会自动产生last-modified。
>
ngx_srcache 并不会自动为你生成 Last-Modified. 从逻辑上讲,Last-Modified
响应头也不应该由缓存层来自动生成,因为只有资源的创建者(即响应的原始生成者)才真正知道当前资源在语义上究竟是何时修改过的。
所以,正确的做法应当是在你的后端应用中生成正确的 Last-Modified 响应头。比如你的后端应用是 PHP 编写的,你则应该在 PHP
代码中使用 header() 函数 [1] 输出 Last-Modified ;而如果你的后端是 Java 编写的,则同理应当使用你的
Java 框架提供的方法生成这个响应头。
如果你非要在 cache miss 时自动从当前系统时间生成 Last-Modified 响应头,则也可以使用 ngx_lua 模块 [2]
提供的 header_filter_by_lua 指令来实现:
http://wiki.nginx.org/HttpLuaModule#header_filter_by_lua
下面给出一个经过测试的完整示例:
location /t {
srcache_fetch GET /memc $uri;
srcache_store PUT /memc $uri;
header_filter_by_lua '
if ngx.var.srcache_fetch_status == "MISS" then
ngx.header["Last-Modified"] = ngx.http_time(ngx.time())
end
';
echo "hello world"; # emulate the backend app
}
location /memc {
internal;
set $memc_key $query_string;
set $memc_exptime 10;
memc_pass 127.0.0.1:11211;
}
这里我们进行缓存的接口是 location /t,里面为简单起见,直接使用了 ngx_echo 模块 [3] 提供的 echo 配置指令输出
hello world 这个响应。我们使用了 ngx_srcache + ngx_memc 的组合来对 echo
指令生成的响应进行缓存。缓存使用的 key 就是请求的 URI,缓存的过期时间是 10 秒钟。
这个例子同时使用了 header_filter_by_lua 指令在 nginx.conf 配置文件中内联了 3 行 Lua 代码,用以在
ngx_srcache 缓存不命中的时候(这是通过 Nginx 变量 $srcache_fetch_status [4] 来判断),强制使用
Nginx 缓存住的当前系统时间来作为 Last-Modified 响应头的值。
不过,这里需要特别注意的一个地方是,ngx_lua 模块的头输出过滤器必须运行在 ngx_srcache
模块的头输出过滤器之前。不同模块的输出过滤器之间的先后顺序是在 Nginx 构造时确定的,特别地,和各模块对应的
--add-module=PATH 选项的指定顺序恰好相反。所以,为了使上面的例子可以正确工作,在构造 Nginx 时须使用类似下面的命令:
./configure --add-module=/path/to/srcache-nginx-module \
--add-module=/path/to/lua-nginx-module \
...
这样 ngx_lua 的过滤器就可以运行在 ngx_srcache 之前了。
如果你直接使用的是 ngx_openresty 软件包(http://openresty.org/ )的话,则从 1.2.4.1rc1
开始,都会使用这种模块顺序(较早的顺序都不是期望的):
http://agentzh.org/misc/nginx/ngx_openresty-1.2.4.1rc1.tar.gz
> 我不清楚ngx_srcache将内容放到缓存时是如何处理头部信息的?会将头部单独缓存么?
ngx_srcache 模块会把待缓存的整个响应(包括响应头和响应体)都作为值传递给缓存后端(在这里,缓存后端就是
Memcached,但其实也可以是 Redis 或者其他任何东西)。在这一点上,和 Apache2 的 mod_cache 模块是类似的。
你可以使用 telnet 这样的工具直接检查你的 Memcached 服务器中实际存储的值的内容。例如,对于上面那个例子,使用 telnet
检查 /t 这个 key 对应的 value 值,在我这里是类似下面这个样子的:
$ telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
flush_all
OK
get /t
VALUE /t 0 101
HTTP/1.1 200 OK
Content-Type: text/css
Last-Modified: Thu, 11 Oct 2012 19:29:19 GMT
hello world
我们看到 /t 这个 key 所对应的值其实就是整个 HTTP 响应:
HTTP/1.1 200 OK
Content-Type: text/css
Last-Modified: Thu, 11 Oct 2012 19:29:19 GMT
hello world
而由 header_filter_by_lua 自动为我们生成的 Last-Modified 响应头也确实被存在了 Memcached 中。
> 如何让它产生last-modified头信息了?处理逻辑是怎么样子的?
>
见上面的示例和讲解 :)
Best regards,
-agentzh
[1] http://php.net/manual/en/function.header.php
[2] http://wiki.nginx.org/HttpLuaModule
[3] http://wiki.nginx.org/HttpEchoModule
[4] http://wiki.nginx.org/HttpSRCacheModule#.24srcache_fetch_status