分类 Nginx/Apache 下的文章

给Nginx加上监控检查机制

Nginx本身并没有提供一个health check的机制

但在upstream中可以通过配置max_fails和fail_timeout以及proxy_next_upstream这些参数,见之前的这个文章

可以实现,当某个server挂掉后,在多长时间内不再向该server发请求了

但过了那个时间后,nginx仍然后继续给server发请求,如果失败后,则

在error的日志中,我们是能看到类似这样的错误日志的

2011/11/11 16:36:18 [error] 11834#0: *51 connect() failed (111: Connection refused) while connecting to upstream, client: 10.x.x.x

nginx默认是会将该失败的请求再转向另外一个server去处理,所以理论上讲应该不会影响Client端

这样的方式并不是一个真正的健康检测机制,不过可以通过一个第三方的插件healthcheck_nginx_upstreams可以实现这个功能

这个插件貌似现在还有Bug,需要打https://github.com/liseen/healthcheck_nginx_upstreams这么一个patch,然后就能在round robin下实现健康检查了

安装很简单

cd nginx-1.0.9

patch -p1 < cep21-healthcheck_nginx_upstreams-8870d34/healthcheck.patch

./configure --add-module=./cep21-healthcheck_nginx_upstreams-8870d34

配置如下参数即可

healthcheck_enabled;    

healthcheck_delay 1000;    

healthcheck_timeout 2000;    

healthcheck_failcount 3;

healthcheck_send "GET /error.jsp HTTP/1.0" 'Host: xxxx.xxx.com';

当Down掉后台的某台server后,则nginx不会把请求再转发到这台server上,所以error日志中也不会有upstream错误的日志了

可以在nginx里配置一个location,通过web界面去查看health check的状态

location ~ /health {

    healthcheck_status;

    access_log   off;

    allow 10.x.x.x/24;

    deny all;

 }

Nginx的proxy_set_header继承

nginx配置中,proxy_set_header可以放在http,server,loaction中

逻辑上讲,下面loaction的配置应该会继承上面的proxy_set_header

但Nginx有一个限制

proxy_set_header directives issued at higher levels are only inherited when no proxy_set_header directives have been issued at a given level.

就是说,当location里写的有其它的proxy_set_header时,则无法继承高层server中定义的proxy_set_header的设置

如果location想继承上面定义的proxy_set_header,则location里不能proxy_set_header指令

用proxy_redirect解决proxy后重定向url问题

今天配置Nginx时,遇到了“/”的问题

前端的Nginx负责把http://mtpc.sohu.com/yum/Server/开头的url反向代理到后端的http://192.168.1.1/Server/上

对于有完整的路径,如http://mtpc.sohu.com/yum/Server/的代理没有问题,Server对应后台服务器的一个目录

但当访问http://mtpc.sohu.com/yum/Server时,后端Nginx会发送一个301到/上,于是返回到前端后URL变成了

http://mtpc.sohu.com/Server/,这个url显然不是我们想要的

 

在Apache中有个ProxyPassReverse的参数,用来调整反向代理服务器发送的http应答头的url,可以解决这个问题

查了Nginx的手册后,终于发现了proxy_redirect这个参数,它实现的功能和ProxyPassReverse类似

增加如下配置:

 

location ^~ /yum

{

            proxy_pass http://192.168.1.1/;

            proxy_redirect http://mtpc.sohu.com/ /yum/;

}

这样,当访问http://mtpc.sohu.com/yum/Server后,就会301到http://mtpc.sohu.com/yum/Server/

IE6的gzip问题

关于IE6下gzip的问题,网上流传很多个版本

并不是说IE6对所有的gzip压缩都有问题,现在可以确认的是:

  1. 对图片的gzip压缩会造成压面的假死,见:开启Nginx的gzip压缩功能。这个处理比较简单,直接取消对gzip的压缩即可
  2. 对JS的gzip压缩,在某些IE版本下会有问题,之前比较暴力的解决方法是直接禁用IE6的gzip压缩

对于第2个问题,权威的微软官方的Issue如下:

BUG: Script Errors with Cache-Control:no-cache HTTP Header and HTTP Compression

就是说,在同时满足以下几个条件时,IE6执行JS会报错,才会导致整个页面出现问题:

  1. 引用外部的JS
  2. 服务器对JS进行了gzip压缩
  3. 服务器输出了Cache-Control: no-cache

找了一台纯净的IE6机器,没有打任何的Patch,在Nginx上配置了

more_set_headers    "Cache-Control: no-cache";

登录mail后,果然出现了页面错误,如下图:

正如微软官方所说的,报错:

Object doesn't support this property or method

然后在一台IE6 SP2的机器上同样测试,没有重现这个错误,就是说在SP2以上的IE6上已经没有问题了

反之,如果不输出“Cache-Control: no-cache”这个Header,那么js在任何版本的IE6上也都没有问题

 

知道Bug的起因后,如果确实存在不需要缓存的js,可以有以下2个办法:

        1.  我们在Nginx上输出expires,而不要输出Cache-Control: no-cache即可:

             expires 0;

             注意,不要设置成-1,因为对于负值,Nginx会自动输出一个“Cache-Control: no-cache”的Header

        2.  配置Nginx,对于IE6 SP2以下版本的IE6,不要启用gzip压缩:

            gzip_disable "MSIE [1-6]\.(?!.*SV1)";

在Apache和Nginx中实现StickySession功能

当我们使用负载均衡,后端对应多台Server,而且使用了单机Session的

如果不进行配置,可能会发生丢Session的问题,因为前端Nginx可能会随机分发Request请求

Aapache已经提供了stickysession的功能,前端Apache2的配置如下:

ProxyPassMatch ^/(.*)$ balancer://vip stickysession=STICKY_HOST
ProxyPassReverse / balancer://vip
<Proxy balancer://vip>
        BalancerMember http://192.168.x.x smax=5 max=20 ttl=120 retry=30 route=159
        BalancerMember http://192.168.x.x smax=5 max=20 ttl=120 retry=30 route=160
</Proxy>

它是依赖Cookie来实现route的,需要在后端的Apache2上设置相应的Cookie值:

RewriteEngine On
RewriteRule .* - [CO=STICKY_HOST:host.159:.xxx.test.com]

Nginx上也可以实现这样的机制,配置如下:

set $serverid $cookie_STICKY_HOST;
if ($serverid ~ ^host.159$)
{
    proxy_pass http://192.168.x.x;
}
if ($serverid ~ ^host.160$)
{
    proxy_pass http://192.168.x.x;
}

Nginx还提供了一个ip_hash的指令,可以根据ip来分发请求

也可以实现StickySession的功能,使用很简单:

upstream mail_pop
{
    ip_hash;
    server  10.x.x.x:83;
    server  10.x.x.x:83;
}
 

Apache的Alias和Rewrite

Apache2中通过配置Alias,可以方便的把某个URL给重定向到某个目录下

如下述配置:

<Directory "e:/ysz">
        Options Indexes FollowSymLinks
        AllowOverride None
        Order allow,deny
        Allow from all
</Directory>
Alias /flash e:/ysz/
ProxyPass /flash !
ProxyPass /   http://10.10.66.71/

注意上面最后有一个反向代理,把所有的请求都反向代理到某台机器上

所以,需要设置对于/flash开头的url就不在反向代理了

Rewrite的功能就更强大了,一个简单的例子:

RewriteEngine on
RewriteRule ^/post/([0-9]+)/  http://www.tech126.com/?p=$1 [R=301,L]

Windows下编译Apache2的Passport模块

虽然,线上运行的服务都是在Linux平台,直接在Linux上编译对应的passport模块就可以了

但是,我们的很多开发人员仍然是在Windows下工作,所以需要passport模块的windows版本

最近,passport模块又进行了升级,可以支持多账号绑定功能了

于是,又需要编译一个Windows下的新版本,原来曾经编译过,但编译的环境没有了

上午又捣鼓了半天,终于编出来dll了,记录一下过程

  1. 安装Apache2.2,选择“自定义安装”,需要把一些headers和libs给装上
  2. 安装Win32Openssl,我装的版本是Win32OpenSSL-0_9_8e
  3. 安装Visual Studio express 2008中的Visual C++,它已经包含SDK工具包了
  4. 参考vsvars32.bat,写了一个bat文件:
@set PATH=C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE;C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools;C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 9.0\VC\VCPackages;c:\Program Files\Microsoft SDKs\Windows\v6.0A\bin;%PATH%
@set INCLUDE=C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include;c:\Program Files\Apache Software Foundation\Apache2.2\include;c:\Program Files\OpenSSL\include;%INCLUDE%
@set LIB=C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;c:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib;c:\Program Files\Apache Software Foundation\Apache2.2\lib;c:\Program Files\OpenSSL\lib\VC;%LIB%
@set LIBPATH=C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;%LIBPATH%

cl /MD /D "WIN32" /c mod_passport.c
link /DLL mod_passport.obj libhttpd.lib libapr-1.lib libeay32MD.lib
mt -manifest mod_passport.dll.manifest -outputresource:mod_passport.dll;#2

在编译过程中,报了一个错:

 mod_passport.c(896) : error C2275: “BIO”: 将此类型用作表达式非法
 c:\Program Files\OpenSSL\include\openssl/bio.h(199) : 参见“BIO”的声明

在宋老师的指点下,把bio的声明给提前到所在函数的第一行就可以了

使用Cygwin编译Windows上的Nginx

Nginx的官方最近也开始提供Windows版本的下载了


如果不需要附加的第三方模块的话,直接使用其提供的Windows版本就可以了


但我们线上运行的Nginx需要编译进好多附加的模块,所以只能自己动手了


上网Google一搜,好多关于在Cygwin下编译Nginx的文章


但真正自己动手去编译,发现还是出了很多的问题


我使用的编译选项如下:



折叠复制代码




  1. ./configure --prefix=.--sbin-path=nginx--with-cc-opt="-D FD_SETSIZE=4096"--with-debug --with-mail --with-mail_ssl_module --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module--add-module=../nginx-upload-progress-module--add-module=../nginx_passport--add-module=../ngx_cache_purge-1.0--add-module=../headers-more-nginx-module





 


在编译过程中,遇到了以下问题:



  1. prefix的选项,如果我们指定--prefix=/cygdrive/d/nginx,那么最后脱离Cygwin环境运行,会发现root无法指向其它磁盘上的目录,所以这里使用了相对路径,而且指定了可执行文件nginx在根目录下,而不是默认的sbin/nginx

  2. FD_SETSIZE=4096,网上都说了,是将select模式的最大worker_connections加大

  3. 编译mod_passport之前,最好执行dos2unix.exe mod_passport/config转换一下格式

  4. 编译mod_passport时,会报错:cc1: warnings being treated as errors,需要修改objs/Makefile文件,把其中的-Werror删除即可

  5. 编译成功后,在Cygwin下运行正常,但如果要脱离Cygwin,需要从cygwin/bin下拷贝cygwin1.dll,cyggcc_s-1.dll,cygz.dll,cygcrypto-0.9.8.dll,cygssl-0.9.8.dll,cygpcre-0.dll,cygcrypt-0.dll这几个dll到nginx目录下

  6. 最后,不使用Cygwin,在普通Dos下运行nginx时,会报错:emerge: getpwnam("nobody") fail。这也是最令我郁闷的一个错误了,看了网上很多人的帖子,似乎都很顺利就成功了,但用我的Cygwin编译出来的nginx,就一直报这个错误,尝试不加第三方模块,指定user为本机的administrator,依然报错...郁闷了很久之后,最后还是找到nginx源码中相关逻辑,做如下修改:
    nginx-0.8.49/src/core/nginx.c,把getpwnam和getgrnam相关逻辑判断注释掉

    nginx-0.8.49/src/os/unix/ngx_process_cycle.c把setgid和setuid相关逻辑判断注释掉
    最后重新编译运行,才成功了

  7. 当引用外部的目录时,需要用cygwin格式的路径,如:root /cygdrive/d/work/git/python_mail/web;


 


最后,写了一个restart.bat脚本,用来重启nginx



折叠复制代码




  1. @echo off

  2. echo Stoping nginx...

  3. taskkill /F /IM nginx.exe

  4. echo Validating nginx.conf...

  5. nginx.exe -t -c conf/nginx.conf

  6. echo Starting nginx...

  7. nginx.exe -c conf/nginx.conf

  8. tasklist | findstr nginx




 


 

开启Nginx的gzip压缩功能

默认情况下,Nginx的gzip压缩是关闭的


同时,Nginx默认只对text/html进行压缩


所以,开启gzip的指令如下:



折叠复制代码




  1. gzip on;

  2. gzip_http_version 1.0;

  3. gzip_disable "MSIE [1-6].";

  4. gzip_types text/plain application/x-javascript text/css text/javascript;




注意:


1. 其中的gzip_http_version的设置,它的默认值是1.1,就是说对HTTP/1.1协议的请求才会进行gzip压缩


如果我们使用了proxy_pass进行反向代理,那么nginx和后端的upstream server之间是用HTTP/1.0协议通信的



This module makes it possible to transfer requests to another server.


It is an HTTP/1.0 proxy without the ability for keep-alive requests yet. (As a result, backend connections are created and destroyed on every request.) Nginx talks HTTP/1.1 to the browser and HTTP/1.0 to the backend server. As such it handles keep-alive to the browser.



如果我们使用nginx通过反向代理做Cache Server,而且前端的nginx没有开启gzip


同时,我们后端的nginx上没有设置gzip_http_version为1.0,那么Cache的url将不会进行gzip压缩


 


2. gzip_disable的设置是禁用IE6的gzip压缩,又是因为杯具的IE6


IE6的某些版本对gzip的压缩支持很不好会造成页面的假死,今天产品的同学就测试出了这个问题


后来调试后,发现是对img进行gzip后造成IE6的假死,把对img的gzip压缩去掉后就正常了


为了确保其它的IE6版本不出问题,所以就加上了gzip_disable的设置

Nginx的Cache和Set-Cookie的冲突

上周,让NO同学帮忙检测了一下mail登录的数据


最后发现,结果很不理想,平均登录时间在50s左右


看了相关的数据后,发现以前的CDN也有一定的问题


首先,以前的CDN缓存时间太小,只有12个小时,几乎没啥用


再次,CDN似乎不太稳定,有时用户访问CDN的时间很长


经过和NO的同学讨论后,准备更改CDN


从js.sohu.com迁移到js.mail.sohu.com上


新的url是我们自己的服务器,上面存储一些静态的资源


NO同学负责更改该url的DNS解析,在全国范围内就近解析到最近的CDN上


他们的CDN实现似乎也很简单,Nginx+ProxyPass+Cache就搞定了


 


在测试过程中,有一个问题,郁闷2天了


静态的js文件,首次访问,CDN正常返回200


但按F5刷新后,CDN不是返回的304,而是继续返回200


但设置js.mail.sohu.com的host到我们的服务器,就能返回304


和NO同学调试了一天,才发现是Set-Cookie的header惹的祸


我们的js.mail.sohu.com上装了passport的module


当用户登录后访问,会设置相应的cookie,所以每个请求都会有这个header


但Nginx的Cache模块貌似是,发现有这个Set-Cookie的heaer后,就不cache了


所以,当用户按F5后,它不会返回304,而是向后台去请求返回200


 


最后,是这么解决的:


在nginx上配置清除那个header:



折叠复制代码




  1. more_clear_headers 'Set-Cookie';




当然,你的nginx需要编译进去headers-more-nginx-module这个模块

最新文章

最近回复

  • feifei435:这两个URI实际是不一样的
  • zsy: git push origin 分支 -f 给力!
  • 冼敏兵:简单易懂,good fit
  • Jack:无需改配置文件,看着累! # gluster volume se...
  • Mr.j:按照你的方法凑效了,折腾死了。。。。
  • zheyemaster:补充一句:我的网站路径:D:\wamp\www ~~菜鸟站长, ...
  • zheyemaster:wamp2.5(apache2.4.9)下局域网访问403错误的...
  • Git中pull对比fetch和merge | 炼似春秋:[…] 首先,我搜索了git pull和git fe...
  • higkoo:总结一下吧, 性能调优示例: gluster volume s...
  • knowaeap:请问一下博主,你维护的openyoudao支持opensuse吗

分类

归档

其它