nginx的问题(续)

昨天说了nginx的几个问题,

由于我现在支持的主要是通用CDN,也就是小图片和CSS以及JS这些东西,并没有做大文件的cache。而问了我们视频部门他们也根本不用nginx作为cache使用,所以有些问题还是没考虑周到。

一个问题是之前发现的,在做tmpfs的时候,当你设置的cache大小为tmpfs的90%的时候,一旦要缓存的内容大于这个90%的时候,nginx会自己崩溃掉。这个我明天做个测试再重现一下,现在有点忘记原因了,好像是tmpfs会占用到实际的磁盘才导致的。

另外一个其实是upstream的问题,这个是一个新浪的老兄提的,基本现在是无解。问题是:比如平均一个文件10M,你在磁盘上存3000个文件,然后模拟多个客户端去访问,因为shm一开始是空的,所以都会去后端拽文件,我们放慢这个拽的过程,比如说网络不好吧 呵呵,那么第一个请求发现不在lookup失败,就会去upstream取数据,边取边向downsteam发,并且存在一个临时文件中,这时第二个请求来了也请求这个文件,因为第一个请求没有处理完,所以第二个请求找不到目标文件只好继续去后端拽,又生成临时文件,并发量大的时候,一个大文件会对应N多的临时文件,最终这些文件rename到一个目标文件,大大浪费了磁盘IO。这个rename是内核做的,nginx调完之后就返回了。这种问题往往会导致内部网络流量非常大,而实际却没有根本没有大。

当有多个连接来获取同一个文件的时候,squid中却没有跟nginx cache一样的问题。我们看看squid是怎么解决的吧。我们在squid有这样一个参数collapsed_forwarding on(http://wiki.squid-cache.org/Features/CollapsedForwarding),一旦设置了参数了,当发现有连接请求同一个文件的时候,squid会合并多个连接,但是它会以最慢速的那个连接去取,然后同步地传送给客户端。这样就不会重复请求后端了。但是squid也有问题,因为首先它是同步的。当用户请求的是动态的内容的话会导致客户端错误。而且当一个用户连接速度很快,一个用户连接速度很慢,那就会以最慢的速度进行获取和传输。所以在squid3.0以后取消了这个参数。

这个问题的解决办法暂时看起来只能在nginx cache前充一下热点的大文件。还好一般内网都是千兆连接,这个速度往往大于用户的连接速度。只有当文件特别大,并且热点文件特别多的情况下才会发生。而且nginx这种处理方式也有一定的好处。

nginx upstream流程我们可以参考http://bollaxu.javaeye.com/blog/900424http://bollaxu.javaeye.com/blog/900357这2篇文章。基本是由于nginx upstream为了防止锁所以进程间是不共享的。

###########################################

Best regards
Timo Seven
blog:http://www.timoseven.com
twitter: http://twitter.com/zauc
Linux System Admin  & MySQL DBA

Advertisements

nginx cache现有的几个问题

在我这边现实环境中主要是有三个问题。

第一个问题是当cache过期的时候,nginx会把cache状态设置为updating,但是这个updating却没有设置一个超时,所以导致的情况当一个cache过期的时候好多nginx会连接到源站取数据,而如果源站并发量有限的话,会导致源站突发负载过高,而这个时候导致nginx一直处于updating过程中,如果导致源站挂掉的话,那完蛋了。当然我们也可以设置proxy_cache_use_stale updating;但是这样会导致cache的内容不准确。

解决的方法有2种,一个是我们现在更改nginx源码,使之可以updating设置有超时时间,这样不会导致长时间连接源站造成拥塞。另外一种就是nginx cache分层,分为父节点和子节点,只有父节点才会去源站更新,子节点只从父节点上更新。

第二个问题是upstream中server的状态,我们知道upstream中可以设置proxy_next_upstream当一个服务器挂掉后自动转到其它的服务器上,但是这里有个问题就是让用户访问的时候proxy会每次都会先访问下这个坏的服务器,连接不通了再转到其它服务器上,这每次都要测试会浪费大量的时间。我们需要得到的是proxy会独立一个线程去检查后端服务器,一旦发现后端服务器挂掉的话,那直接从upstream中剔除掉这个服务器就可。而等检测后端服务器又存活了再加进来。

这个现在有ngx_http_healthcheck_module这个第三方模块。具体可以参考http://wiki.nginx.org/HttpHealthcheckModule

第三个问题是nginx proxy连接nginx cache的时候居然使用的是http1.0的,而不是http1.1,就没法使用keepalive连接后端,导致我们小文件的cache服务器连接数过高,而没法进行复用链接。

这个暂时还没有解决,不过看到http://wiki.nginx.org/HttpUpstreamKeepaliveModule这个第三方模块,但是实际还没有测试过,没法做什么结论。

其实大家可以完全查看http://wiki.nginx.org/3rdPartyModules 来看看是否针对自己的应用,有些还是我们国人自己开发的,但是针对第三方模块还是要谨慎使用,上面的healthcheck模块还是经过我们自己的开发重新修改后并进行压力测试后再上线的。开源就是这点好啊。看来我要得学习学习C语言编程来,以后自己也改改增加增加功能啥的。

###########################################

Best regards
Timo Seven
blog:http://www.timoseven.com
twitter: http://twitter.com/zauc
Linux System Admin  & MySQL DBA

nginx单一端口域名转发

对于后端是同一端口多域名转发的nginx proxy。在nginx中的默认proxy是只能对后面real server做端口转发的,而不能做域名转发。
这个是因为默认

proxy_set_header Host $proxy_host; 

这样就等于前端输入域名后到nginx这里直接转换成IP进行转发了。
于是我们需要修改proxy_set_header的参数

proxy_set_header Host $http_host;

例如下面一个举例。下面这个例子中backend1权重为5,其他默认为1,最大失效次数3次,如果30秒内没有响应就认为是失效了。

        upstream lb  {
		server backend1.test.com weight=5;
		server backend2.test.com:8080 max_fails=3  fail_timeout=30s;
		server unix:/tmp/test3;

        }

        server {
                listen 80;
                server_name  lb.test.com;
                location  /     {
                proxy_store off;
                proxy_redirect  off;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header Host $http_host;
                proxy_pass http://lb;
                }
        }