Nginx实践 使用memcached模块加速PHP应用程序

Memcached,就不多说了,地球人都知道.
Nginx有一个memcached_module,可以直接从后端的memached服务器中读取内容,
直接输出.

通过这个模块,可以极大的提升动态页面的访问速度.

我的实践中, 曾经用这个模块快速的解决了由于代码造成的一些瓶颈问题.

memcached可以通过upstream来从多台memcached服务器中读取,也可以支持热备份.

下面是我的完整例子

upstream memcached {
server 192.168.8.11:11211;
server 192.168.8.10:11211;
}

server {
listen 80;
server_name t.night9.cn;
limit_conn one 10;
charset utf-8;
access_log /logs/web/t.log main;
root /www/app/web;
default_type text/html;
index app;
location = / {
set $memcached_key $host$uri;
default_type text/html;
memcached_pass memcached;
error_page 404 = /missing;
}
location /missing {
internal;
rewrite ^/missing$ /app/site/blog last;
}
include php_app.conf;
}

在这个例子中, nginx首先从memcached中读取(缓存的key可以用memcached_key来设置.),
如果命中,则直接输出内容,注意,需要设置default_type ,否则可能不能正常显示.
如果没有命中,memcached_module会返回404,因此可以用 error_page 404来转发到后端的应用程序,
本例中是先转发到/missing ,而/missing则重写到实际的后端应用地址中.

Nginx只负责从memcached中读取内容,但不负责设置.因此,需要你的应用程序自行将相应的页面缓存
设置到memcached中.

在我的部署中, 我是通过设置一个PAGE_CACHE_ID给php的fastcgi:
(在fastcgi_params中加入):

fastcgi_param PAGE_CACHE_ID $memcached_key;

php程序一旦检测到这个环境变量,
那么会自动将当前页面的内容设置到memcached缓存中,由于是在php框架中自动作的,所以可以随时切换,不需要修改.

缺点:

很多事情都不是那么完美, 对于nginx的这个module,其最大的问题就是不支持压缩,
因此,在使用php的memcache函数设置缓存时,必须取消压缩,否则将无法正确输出.

这样带来的一个小问题就是:
由于一般页面至少数k以上,这样对于内存的消耗是比较大.

因此, 在这个module支持压缩之前, 可以考虑备选方案:
使用独立的FASTCGI服务器来替换memcache模块.

通过CPAN模块,实现起来非常简单!

Comments

18 Responses to “Nginx实践 使用memcached模块加速PHP应用程序”

  1. issac on July 23rd, 2008 9:38 am

    博主你好
    我在配置nginx的时候遇到了一个问题
    如果请求是/cache/XXX,我想用XXX作为memcache的key,总是配不对
    然后memcache不命中的时候,404我设置成/backend/,然后在 location的backend里要把/backend/ 改写成/backend/?url=XXX (和前面那个XXX一样)

    我是这样写的:
    rewrite ^/cache/?(.*)$ /$1;
    set $memcached_key $1;

    location = /backend {
    internal;
    rewrite ^/backend/?(.*)$ /backend/?url=$request_uri;

    请问是哪里错了
    搜了好多地方搜到这里来了
    如果您能指教我不胜感谢

  2. nightsailer on July 23rd, 2008 12:31 pm

    1.检查下你的error_page , 是否正确?
    2.尝试把location=/backend 改为 location /backend
    3.看看是否设置了memcached_pass 指令,如:
    location /cache {
    rewrite ^/cache/(.*)$ $1 last;
    set $memcached_key $1;
    memcached_pass 127.0.0.1:11211;
    error_page 404 = /missing;
    }
    location /missing {
    internal;
    rewrite ^/missing/(.*)$ /backend/?url=$1 last;
    }

  3. issac on July 23rd, 2008 2:39 pm

    谢谢
    可是还是有问题
    rewrite ^/cache/(.*)$ $1 last;
    set $memcached_key $1;

    log里讲the “$memcached_key” variable is not set

    我的请求是HOST:PORT/cache/http://www.g.cn

  4. epaddy on September 12th, 2008 6:11 pm

    如果php不用压缩,但nginx使用了gzip压缩行不?

  5. nightsailer on September 15th, 2008 5:36 pm

    @epaddy

    可以的

  6. AA on December 18th, 2008 3:02 pm

    可以留下msn吗 请教 这里说不清楚!

  7. AA on December 18th, 2008 3:03 pm

    我的 fywz10629@hotmail.com

  8. ahu on December 26th, 2008 10:20 pm

    能否分享下php程序的关键代码…php_app.conf有什么特殊吗?
    不知何故我反复尝试就是没试成功:(
    不知道哪里问题,就是不得要领

  9. nightsailer on December 31st, 2008 2:43 am

    @ahu
    没什么关键代码,就是普通的memcached的操作而已,在php程序中需要set到cache中,关键一点就是cache的key要传递给PHP程序
    在php的fastcgi配置中增加:
    fastcgi_param PAGE_CACHE_ID $memcached_key;

    上面是个例子,PAGE_CACHE_ID可以换成任意名称。
    之后就可以通过_SERVER['PAGE_CACHE_ID']
    来获得这个key了
    将要缓存的页面用这个key存到memcached即可

  10. fywz10629 on December 31st, 2008 2:13 pm

    为什么我的从memcached的读取速度还没有从硬盘读取速度快 才1000左右 好的时候 但从硬盘读取的时候有3000+ 是哪里的原因呢?可以解释一下吗?

  11. nightsailer on December 31st, 2008 11:47 pm

    @fywz10629

    环境配置?使用什么api? 最好在你实际部署环境测试。另外,自己看下命中率,命中率过低也许是你memcached根本就没有缓存住。

  12. yjh2002 on January 16th, 2009 7:17 pm

    怎么样把请求中的一个参数的值作为memcache key啊?
    比如http://localhost/cache/jsp.do?arg1=wi708g7df66&arg2=xxxx
    这里把arg1的值作为key 用来识别用户的session, 如何办?

  13. nightsailer on January 18th, 2009 10:37 pm

    @yjh2002
    不明白你的具体要求. 要在Nginx级别实现?还是在后端实现?
    jsp中可以获得arg1的key。
    如果你是希望nginx中使用arg1的值作为key,似乎应用的场景有些问题,
    也是可以有解决办法,你可以使用类似(未测试):

    rewrite ^/jsp.do?arg1=(.*)&arg2.*$ $1 last;
    set $memcached_key $1;

  14. yjh2002 on January 19th, 2009 4:57 pm

    直接在Nginx级别实现, 不在后端设逻辑。
    而且有的请求不一定参数arg1就在前面的, 有可能是这样的, http://localhost/cache/jsp.do?arg2=xxxx&arg1=wi708g7df66 所以我写了两个,
    rewrite ^/jsp.do?(.*)(arg1=)(.*)&(.*)$ $3 last;
    rewrite ^/jsp.do?(.*)(arg1=)(.*)$ $3 last;
    set $memcached_key $3;

    但是报错, the “$memcached_key” variable is not set。

  15. nginx+memcached的结合--性能400%的提升 | 鸭嘴的blog on April 1st, 2009 3:25 pm

    [...] nginx是个好东西,一直还没有时间好好研究。还有一篇中文: 使用memcached模块加速PHP应用程序Nginx实践 使用memcached模块加速PHP应用程序 [...]

  16. 阿权 on May 23rd, 2009 3:49 pm

    兄弟,nginx是可以做gzip的,这个我测试过,比如

    location ~* ^/xxxxx {
    set $memcached_key $host$uri;
    memcached_pass all_memcachedb;
    default_type text/html;
    gzip on;
    gzip_proxied any;
    error_page 404 = /fallback;
    }

  17. 阿权 on May 23rd, 2009 4:05 pm

    抱歉,你说的是内存的压缩问题,理解错了 :)
    这个我也奇怪,php里set可以压缩,get是取出的是不压缩的数据,那nginx取出的时候居然不处理数据是否压缩的问题

  18. 阿权 on May 23rd, 2009 4:07 pm

    抱歉,理解错了,存储时的确无法压缩
    php里get方法取出的是正常数据的,而nginx居然不处理是否压缩的问题

Leave a Reply