找回密码
 用户注册

QQ登录

只需一步,快速开始

楼主: winston

高性能Web服务器Nginx的配置与部署研究

[复制链接]
 楼主| 发表于 2012-1-19 21:02:38 | 显示全部楼层
高性能Web服务器Nginx的配置与部署研究(11)应用模块之Memcached模块的两大应用场景

本文来自:CSDN博客专栏《Nginx高性能Web服务器》Poechant技术博客,转载请注明出处。
一、应用场景1
最近在一个项目中,用到了Nginx的Memcached模块,所以就在这个系列教程中提前把Memcached模块拿出来写了。另外发现最近我的博客文章频频被很多用采集器的网站拿走,帮我发扬光大,都不听我说声谢谢。在此还是希望我的博文被转载的时候能够被注明出处,满足下我小小的虚荣心。

现在有这样一种应用场景:
客户端Client通过Nginx反向代理,访问服务器Server。每次访问的内容就是将文件File传到Server上,然后可以访问到File的URL被广播到所有Client上,每个Client再加载File。


Analysis:
这么多Client同时加载File,对Server的压力一定很大吧?读者朋友肯定会说,有了Nginx反向代理,Client访问Server的时候,相应访问的资源就可以被Nginx缓存,减轻了Server的压力。但有一点要注意,如果这样的话,Nginx反向代理配置的缓存是在有Client访问到Nginx时才会从Server拿来缓存到Nginx上。可是广播后,所有Client加载File是同时的,如果等地一个访问请求到来并使得Nginx产生缓存后,其他Client接收到广播后的加载响应,恐怕早已经发起并且接近尾声了。负载压力还是落到Server上。怎么办呢?

Solution Overview:
某个Client上传File到Server的同时,将File内容写入到Nginx的缓存中,然后广播后,Client加载File的请求在到达Nginx时去缓存中查找,那么基本是100%命中。

Deployment Solution:
(1)Reverse-Server(192.168.0.1):反向代理服务器,用Nginx实现。对外提供11000端口,接收到HTTP请求后到Cache-Server的14000端口的缓存服务中查找,如果有则返回,如果没有则将请求传递给Store-Server的12000端口。
(2)Store-Server(192.168.0.2):文件存储服务器,用FastDFS实现。对外提供12000端口用于下载,接收来自Reverse-Sever的HTTP请求。对外还提供12500端口用于上传。
(3)Process-Server(192.168.0.3):业务处理服务器,对外提供13000端口,接收Client传递来的File,并将File通过Store-Server的12500端口转储到Store-Server中。
(4)Cache-Server(192.168.0.4):文件缓存服务器,用Memcached实现,对外提供14000端口。接收来自Reverse-Server的读操作,和Process-Server的写操作。


Configuration Solution:
(1)FastDFS的配置与部署,请参见GoogleCode上的FastDFS相关wiki。
(2)Memcached部署很简单,wget,tar,./configure,make,make install就OK了。
(3)Process-Server是由我自己实现的,不具有通用性就不说了。
(4)Reverse-Server的Nginx配置文件中http模块中,建立一个用户解决该问题的server,配置方式如下:

[plain] view plaincopyprint?



  • server {  
  •     listen 11000;  
  •     server_namelocalhost;  
  •   
  •     default_typetext/html;  
  •       
  •     location / {  
  •         proxy_set_headerX-Real-IP $remote_addr;  
  •         proxy_set_headerHost $http_host;  
  •         proxy_set_headerX-Forwarded-For $proxy_add_x_forwarded_for;  
  •          
  •         if ($request_method = POST) {  
  •             proxy_pass http://192.168.0.2:12000;  
  •             break;  
  •         }  
  •   
  •         set $memcached_key  "$uri";  
  •         memcached_pass      192.168.0.4:14000;  
  •   
  •         error_page  501 404 502 = /fallback$uri;  
  •     }  
  •   
  •     location /fallback/ {  
  •         internal;  
  •   
  •         proxy_set_header    X-Real-IP   $remote_addr;  
  •         proxy_set_header    Host        $http_host;  
  •         proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;  
  •   
  •         proxy_redirect      off;  
  •   
  •         proxy_pass      http://192.168.0.2:12000  
  •     }  
  • }  


Details
Nginx的Memcached模块只提供对Memcached的读操作,不提供写操作。如果Memcached中没有相应的键值,即未命中,则返回404。如果请求未能找到Memcached Server,则返回502错误。因此,我们可以采用这样一种方式:当返回这类错误时,将请求交给Store-Server。这样只有在不命中时才访问Store-Server,缓存服务器由此可以为存储服务器分担很多负载。


二、应用场景2

在应用场景1中,将不命中时的逻辑换作向Memcached的写操作。这种场景的服务器系统部署方案如下:

(1)Reverse-Server:Client访问该服务器的11000端口,请求被转至Cache-Server的14000端口,如果Cache-Server命中则response;否则交给Process-Server的13000端口,进行进一步的处理。
(2)Data-Server:对外提供12000端口,用于读取数据。
(3)Process-Server:提供13000端口,用于接收Reverse-Server转发来的HTTP请求,到Store-Server的12000端口查询,并将得到的Value与从Reverse-Server发来的Key值共同构成K-V对,通过Cache-Server的14000端口写入Cache-Server。
(4)Cache-Server:提供14000端口,用于对外提供读写操作。

这是的Nginx的Memcached模块配置,要将request的方法为post和error_log,不再是如“应用场景1”中那样转至Store-Server,而是都转至Process-Server去。因为应用场景1中,向Cache写的操作,是预先完成的。而应用场景2中向Cache写的操作,是在读Cache失败后发生的。注意这两者适用的业务需求。


 楼主| 发表于 2012-1-19 21:03:04 | 显示全部楼层
高性能Web服务器Nginx的配置与部署研究(12)应用模块之Memcached做文件缓存时压缩引起的问题

本文来自:CSDN博客专栏《Nginx高性能Web服务器》Poechant技术博客,转载请注明出处。
在上一篇文章中,提到的Nginx的Memcached模块应用场景,主要是作为文件缓存。然后就发现了一个问题,当以字节数组方式缓存较大的文件时,缓存数据会被压缩,从而在读取的时候出现问题。

(本文欢迎转载,尊重他人劳动,转载请注明出处:http://blog.csdn.net/poechant/article/details/7177603

解决方法很简单,就是在MemcachedClient端设置压缩的阈值。如果你使用的是net.spy.memcached的API,则可以如下设置:

[java] view plaincopyprint?



  • int EXPIRE_SECONDS = 18000;  
  • SerializingTranscoder transcoder = new SerializingTranscoder();  
  • transcoder.setCompressionThreshold(5242880);  
  • fileCache.set(key, EXPIRE_SECONDS, value, transcoder);  




如果你使用的是net.rubyeye.xmemcached的API,则可以如下设置:

[java] view plaincopyprint?



  • int EXPIRE_SECONDS = 18000;  
  • BaseSerializingTranscoder transcoder = new BaseSerializingTranscoder();  
  • transcoder.setCompressionThreshold(5242880);  
  • client = set(key, EXPIRE_SECONDS, value, transcoder);  




如果你使用的是danga.MemCached的API,则可以如下设置:

[java] view plaincopyprint?



  • int EXPIRE_SECONDS = 18000;  
  • MemCachedClient.setCompressThreshold(5242880);  
  • MemCachedClient.set(key, value, new Date(System.currentTimeMillis() + EXPIRE_SECONDS * 1000L));  


(本文欢迎转载,尊重他人劳动,转载请注明出处:http://blog.csdn.net/poechant/article/details/7177603

 楼主| 发表于 2012-1-19 21:03:25 | 显示全部楼层
高性能Web服务器Nginx的配置与部署研究(13)应用模块之Memcached模块+Proxy_Cache双层缓存模式

本文来自:CSDN博客专栏《Nginx高性能Web服务器》Poechant技术博客,转载请注明出处。
通过《高性能Web服务器Nginx的配置与部署研究——(11)应用模块之Memcached模块的两大应用场景》一文,我们知道Nginx从Memcached读取数据的方式,如果命中,那么效率是相当高的。那么:

(转载请注明来自Poechant的CSDN博客:http://blog.csdn.net/poechant/article/details/7179891

1. 如果不命中呢?

我们可以到相应的数据服务器上读取数据,然后将它缓存到Nginx服务器上,然后再将该数据返回给客户端。这样,对于该资源,只有穿透Memcached的第一次请求是需要到数据服务器读取的,之后在缓存过期时间之内的所有请求,都是读取Nginx本地的。不过Nginx的proxy_cache是本地硬盘缓存,效率要远低于Memcached。

2. 应该如何安装和配置呢?

(1)HttpMemcModule模块
如果使用Nginx的非核心模块——HttpMemcModule模块,则可以下载模块:
http://github.com/agentzh/memc-nginx-module/tags


[plain] view plaincopyprint?



  • michael@dev-machine:~$ tar -zxvf agentzh-memc-nginx-module-a0bc33a.tar.gz  
  • michael@dev-machine:~$ tar -zxvf nginx-1.1.12.tar.gz  
  • michael@dev-machine:~$ cd nginx-1.1.12  
  • michael@dev-machine:~$ ./configure --add-module=/home/michael/agentzh-memc-nginx-module-a0bc33a  
  • michael@dev-machine:~$ sudo make  
  • michael@dev-machine:~$ sudo make install  


目前验证发现Nginx 1.0.10版本 Nginx的1.1.3及其之前的版本,需要额外通过--add-module来加载upstream-keepalive模块,请自行google之。其他版本还不确定,猜测是在1.1  从nginx的1.1.4及其之后的版本开始,自动携带upstream-keeplive模块的。 (感谢agentzh的提示)

(转载请注明来自Poechant的CSDN博客:http://blog.csdn.net/poechant/article/details/7179891

然后我们来编辑配置文件吧。如下:

[plain] view plaincopyprint?



  • http {  
  •     ...  
  •     upstream data_server {  
  •         server  192.168.0.133:1234;  
  •         server  192.168.0.134:1234;  
  •         server  192.168.0.135:1234;  
  •         ip_hash;  
  •     }  
  •   
  •     upstream memc_backend {  
  •         server  127.0.0.1:11211;  
  •     }  
  •     ...  
  •     server {  
  •   
  •         listen      8080;  
  •         server_name localhost;  
  •   
  •         default_type    text/html;  
  •   
  •         location / {  
  •             set     $memc_cmd   get;  
  •             set     $memc_key   $uri;  
  •             memc_pass   memc_backend;  
  •   
  •             error_page  404 @fallback;  
  •         }  
  •   
  •         location @fallback {  
  •   
  •             internal;  
  •   
  •             proxy_pass      http://data_server;  
  •   
  •             proxy_cache     cache_one;  
  •             proxy_cache_valid   200 302 1h;  
  •             proxy_cache_valid   301 1d;  
  •             proxy_cache_valid   any 1m;  
  •             expires         30d;  
  •         }  
  •     }  
  •     ...  
  • }  


从上面的配置文件我们可以看出,一个请求到达后,会其uri作为key去Memcached服务器127.0.0.1:11211上查找value,如果没有命中,则返回404。这时通过error_page将404接收转到@fallback,然后去data_server中取文件,取完后将该文件在本地磁盘缓存,同时用户的浏览器也通过expires设置缓存时间。

这样绝大多数请求如果被第一层Memcached的内存缓存拦截的话,剩余的请求可以通过访问第二层Nginx服务器的硬盘缓存文件,来减少穿透。

按照上面的方式,客户端得到的请求响应中虽然包含了正确的文件内容,但状态码都是404(可以通过Fiddler来观察)。这似乎会引起问题。什么问题呢?绝大多数浏览器,即使在404的情况下,也会尝试去读取内容,如果有正确的内容,是可以正确显示的。但是比较常见的可能引起问题的两种情况是:
(a)、搜索引擎的spider爬到的404时,一般不会收录该URL,我想这不是你所希望看到的;
(b)、Flash等方式加载时,如果头是404,可能不予显示,我想着也不是你所希望看到的。

(转载请注明来自Poechant的CSDN博客:http://blog.csdn.net/poechant/article/details/7179891

那我们把它改成都是200,是不是很好呢?

[plain] view plaincopyprint?



  • error_page  404 =200 @fallback;  



非也,这样404传递到fallback处理请求后的状态如果不是200,就很不一致了,会引起更多问题。所以应该如下配置:
[plain] view plaincopyprint?



  • error_page  404 = @fallback;  


这样fallback的处理结果状态是什么,就用什么替换404。



(2)Nginx内部的Memcached模块
如果你想使用Nginx内部的Memcached模块,配置文件可以结合参考上面的示例和《高性能Web服务器Nginx的配置与部署研究——(11)应用模块之Memcached模块的两大应用场景》

(转载请注明来自Poechant的CSDN博客:http://blog.csdn.net/poechant/article/details/7179891

 楼主| 发表于 2012-1-19 21:03:48 | 显示全部楼层
高性能Web服务器Nginx的配置与部署研究(14)平滑升级你的Nginx
1、概述(可以直接跳过看第2部分)
Nginx方便地帮助我们实现了平滑升级。其原理简单概括,就是:

(1)在不停掉老进程的情况下,启动新进程。
(2)老进程负责处理仍然没有处理完的请求,但不再接受处理请求。
(3)新进程接受新请求。
(4)老进程处理完所有请求,关闭所有连接后,停止。

这样就很方便地实现了平滑升级。一般有两种情况下需要升级Nginx,一种是确实要升级Nginx的版本,另一种是要为Nginx添加新的模块。

2. 升级过程
具体的操作也很简单,如下:

(0)查看当前版本
在存放Nginx的可执行文件的目录下输入:

[java] view plaincopyprint?



  • ./nginx -V  


(1)下载新的Nginx版本并编译。

[java] view plaincopyprint?



  • wget nginx-1.0.11.tar.gz  
  • tar zxvf nginx-1.0.11.tar.gz  
  • cd nginx-1.0.11  
  • ./configure --add-module=/customized_module_0 --add-module=/customized_module_1  
  • make  


注意不要进行make install

(2)备份老版本的可执行文件

[java] view plaincopyprint?



  • cd /usr/local/nginx/sbin  
  • sudo cp nginxnginx.old  


(3)修改配置文件
如果有必要的话,进行配置文件的修改。

(4)拷贝新的可执行文件

[java] view plaincopyprint?



  • sudo cp /home/michael/tmp/nginx-1.0.11/objs/nginx /usr/local/nginx/sbin/  


(5)升级

[java] view plaincopyprint?



  • cd /home/michael/tmp/nginx-1.0.11  
  • make upgrade  



(6)清理多余文件

[java] view plaincopyprint?



  • rm -rf /home/michael/tmp/nginx-1.0.11  


(7)查看Nginx版本

[java] view plaincopyprint?



  • cd /usr/local/nginx/sbin  
  • ./nginx -V  


3、观察进程变化
在我的机器上可以观察到,我配置的是10个worker进程,启动后观察到:

[plain] view plaincopyprint?



  • root      6241 10419  0 10:51 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx  
  • nobody    6242  6241  2 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6243  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6244  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6245  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6246  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6247  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6248  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6249  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6250  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6251  6241  1 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6252  6241  0 10:51 ?        00:00:00 nginx: cache manager process  
  • nobody    6253  6241  0 10:51 ?        00:00:00 nginx: cache loader process  
  • luming    6310 25051  0 10:51 pts/1    00:00:00 grep --color=auto nginx  
  • nobody    7995 10419  0 Jan12 ?        00:20:37 nginx: worker process is shutting down  
  • nobody    7996 10419  0 Jan12 ?        00:20:11 nginx: worker process is shutting down  
  • nobody    7998 10419  0 Jan12 ?        00:20:04 nginx: worker process is shutting down  
  • nobody    8003 10419  0 Jan12 ?        00:20:12 nginx: worker process is shutting down  
  • root     10419     1  0 Jan08 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx  


可见新的进程有1个master和10个worker,另外还有1个老的master(可以从时间上看出)和4个worker(其他6个老的worker已经处理完所有连接而shutdown了)。还有一个loader进程。过几秒种可以看到worker只有两个了:

[plain] view plaincopyprint?



  • root      6241 10419  0 10:51 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx  
  • nobody    6242  6241  1 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6243  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6244  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6245  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6246  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6247  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6248  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6249  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6250  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6251  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6252  6241  0 10:51 ?        00:00:00 nginx: cache manager process  
  • nobody    6253  6241  0 10:51 ?        00:00:00 nginx: cache loader process  
  • luming    6430 25051  0 10:51 pts/1    00:00:00 grep --color=auto nginx  
  • nobody    7996 10419  0 Jan12 ?        00:20:11 nginx: worker process is shutting down  
  • nobody    8003 10419  0 Jan12 ?        00:20:12 nginx: worker process is shutting down  
  • root     10419     1  0 Jan08 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx  


再过一小会儿观察:

[plain] view plaincopyprint?



  • root      6241     1  0 10:51 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx  
  • nobody    6242  6241  0 10:51 ?        00:00:01 nginx: worker process        
  • nobody    6243  6241  0 10:51 ?        00:00:01 nginx: worker process        
  • nobody    6244  6241  0 10:51 ?        00:00:01 nginx: worker process        
  • nobody    6245  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6246  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6247  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6248  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6249  6241  0 10:51 ?        00:00:00 nginx: worker process        
  • nobody    6250  6241  0 10:51 ?        00:00:01 nginx: worker process        
  • nobody    6251  6241  0 10:51 ?        00:00:02 nginx: worker process        
  • nobody    6252  6241  0 10:51 ?        00:00:00 nginx: cache manager process  
  • luming    8680 25051  0 10:56 pts/1    00:00:00 grep --color=auto nginx  


Congratulations! You can upgrade your Nginx server gracefully.

您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-5-8 21:25 , Processed in 0.013183 second(s), 4 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表