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.10.79.108
nginx默认是会将该失败的请求再转向另外一个server去处理,所以理论上讲应该不会影响Client端
这样的方式并不是一个真正的健康检测机制,不过可以通过一个第三方的插件healthcheck_nginx_upstreams可以实现这个功能
这个插件貌似现在还有Bug,需要打https://github.com/liseen/healthcheck_nginx_upstreams这么一个patch,然后就能在round robin下实现健康检查了
安装很简单
1 2 3 4 5 | 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.1.1.0/24;
deny all;
}
十月 31st, 2011Nginx的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指令
六月 7th, 2011用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/
三月 28th, 2011IE6的gzip问题
关于IE6下gzip的问题,网上流传很多个版本
并不是说IE6对所有的gzip压缩都有问题,现在可以确认的是:
- 对图片的gzip压缩会造成压面的假死,见:开启Nginx的gzip压缩功能。这个处理比较简单,直接取消对gzip的压缩即可
- 对JS的gzip压缩,在某些IE版本下会有问题,之前比较暴力的解决方法是直接禁用IE6的gzip压缩
对于第2个问题,权威的微软官方的Issue如下:
BUG: Script Errors with Cache-Control:no-cache HTTP Header and HTTP Compression
就是说,在同时满足以下几个条件时,IE6执行JS会报错,才会导致整个页面出现问题:
- 引用外部的JS
- 服务器对JS进行了gzip压缩
- 服务器输出了Cache-Control: no-cache
找了一台纯净的IE6机器,没有打任何的Patch,在Nginx上配置了
1 | 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即可:
1 | expires 0; |
注意,不要设置成-1,因为对于负值,Nginx会自动输出一个“Cache-Control: no-cache”的Header
2. 配置Nginx,对于IE6 SP2以下版本的IE6,不要启用gzip压缩:
1 | gzip_disable "MSIE [1-6]\.(?!.*SV1)"; |
十一月 2nd, 2010在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.95.159 smax=5 max=20 ttl=120 retry=30 route=159
BalancerMember http://192.168.95.160 smax=5 max=20 ttl=120 retry=30 route=160
</Proxy>
它是依赖Cookie来实现route的,需要在后端的Apache2上设置相应的Cookie值:
RewriteEngine On
RewriteRule .* – [CO=STICKY_HOST:host.159:.vip.sohu.com]
Nginx上也可以实现这样的机制,配置如下:
set $serverid $cookie_STICKY_HOST;
if ($serverid ~ ^host.159$)
{
proxy_pass http://192.168.95.159;
}
if ($serverid ~ ^host.160$)
{
proxy_pass http://192.168.95.160;
}
Nginx还提供了一个ip_hash的指令,可以根据ip来分发请求
也可以实现StickySession的功能,使用很简单:
upstream mail_pop
{
ip_hash;
server 10.10.71.24:83;
server 10.10.71.25:83;
}
九月 26th, 2010Apache的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]
九月 6th, 2010Windows下编译Apache2的Passport模块
虽然,线上运行的服务都是在Linux平台,直接在Linux上编译对应的passport模块就可以了
但是,我们的很多开发人员仍然是在Windows下工作,所以需要passport模块的windows版本
最近,passport模块又进行了升级,可以支持多账号绑定功能了
于是,又需要编译一个Windows下的新版本,原来曾经编译过,但编译的环境没有了
上午又捣鼓了半天,终于编出来dll了,记录一下过程
- 安装Apache2.2,选择“自定义安装”,需要把一些headers和libs给装上
- 安装Win32Openssl,我装的版本是Win32OpenSSL-0_9_8e
- 安装Visual Studio express 2008中的Visual C++,它已经包含SDK工具包了
- 参考vsvars32.bat,写了一个bat文件:
1 2 3 4 5 6 7 8 | @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的声明给提前到所在函数的第一行就可以了
八月 21st, 2010使用Cygwin编译Windows上的Nginx
Nginx的官方最近也开始提供Windows版本的下载了
如果不需要附加的第三方模块的话,直接使用其提供的Windows版本就可以了
但我们线上运行的Nginx需要编译进好多附加的模块,所以只能自己动手了
上网Google一搜,好多关于在Cygwin下编译Nginx的文章
但真正自己动手去编译,发现还是出了很多的问题
我使用的编译选项如下:
- ./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
在编译过程中,遇到了以下问题:
- prefix的选项,如果我们指定–prefix=/cygdrive/d/nginx,那么最后脱离Cygwin环境运行,会发现root无法指向其它磁盘上的目录,所以这里使用了相对路径,而且指定了可执行文件nginx在根目录下,而不是默认的sbin/nginx
nginx-0.8.49/src/os/unix/ngx_process_cycle.c把setgid和setuid相关逻辑判断注释掉
最后重新编译运行,才成功了
当引用外部的目录时,需要用cygwin格式的路径,如:root /cygdrive/d/work/git/python_mail/web;
最后,写了一个restart.bat脚本,用来重启nginx
- @echo off
八月 10th, 2010开启Nginx的gzip压缩功能
默认情况下,Nginx的gzip压缩是关闭的
同时,Nginx默认只对text/html进行压缩
所以,开启gzip的指令如下:
- gzip on;
注意:
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的设置
八月 9th, 2010Nginx的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:
- more_clear_headers 'Set-Cookie';
当然,你的nginx需要编译进去headers-more-nginx-module这个模块