nignx 问题 日志 解决 转

这篇博客详细介绍了在Nginx中实现健康检查机制、proxy_set_header的继承问题、proxy_redirect解决重定向问题、IE6的gzip问题以及如何在Apache和Nginx中实现StickySession功能。通过实例和配置示例,博主分享了Nginx在实际使用中遇到的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;

 }

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指令

今天配置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压缩都有问题,现在可以确认的是:

  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上配置了

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)";

当我们使用负载均衡,后端对应多台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]

虽然,线上运行的服务都是在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文件:
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的声明给提前到所在函数的第一行就可以了

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

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

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

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

编译成功后,在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目录下

最后,不使用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相关逻辑判断注释掉

最后重新编译运行,才成功了

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

 

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

折叠 复制代码

  1. @echo off

echo Stoping nginx…

taskkill /F /IM nginx.exe

echo Validating nginx.conf…

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

echo Starting nginx…

nginx.exe -c conf/nginx.conf

tasklist | findstr nginx

 

 

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

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

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

折叠 复制代码

  1. gzip on;

gzip_http_version 1.0;

gzip_disable "MSIE [1-6].";

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的设置

上周,让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这个模块

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值