首页 > nginx

这两天观察了一下nginx缓存文件,从而对server端程序代码进行了调整,调整不大。

在原有v2.0版本的基础上增加了对nginx的指定文件缓存清除,提交请求的写法是一样的。

关于nginx支持purge的http头的方法请参考《web版清除缓存程序V1.2.3[原创] 》这篇文档的设置。这里我不在赘述

本篇文档主要讲解一下支持nginx指定内容缓存的原理,及nginx上关键的设置。 继续阅读→

阅读全文

在2010年的最后一天,蚊子我为这最后一天画上了一个圆满的句号。发布了这套《分布式缓存清除系统2.0》版,他的前身是《web版清除squid缓存》,从1.0到1.2.3共有6个版本。在这6个版本中只是实现了多台squidnginx的完整url缓存清除功能。

而今天发布的分布式缓存清除系统2.0,蚊子采用了C/S架构模式,由于squid和nginx缓存文件内容结构不同,所以此版本在前身版本功能的基础上,实现了对squid指定内容进行批量缓存清除的功能,不过遗憾的是暂时还不能支持nginx的指定内容的批量清除。后续的开发中,会增加对nginx的支持。 继续阅读→

阅读全文

最近蚊子我思考了一下,要是想让我的那个web版清除缓存程序支持对指定文件,对指定域名缓存的清除,那就只能使用c/s模式,那s端的脚本就是关键。

这篇文章只是蚊子下一步工作的一个铺垫,只能算是前期的一个准备工作。在s端,蚊子决定使用perl脚本来完成,所以,这里先写了一个使用perl在清除指定文件的脚本。为了方便其他人使用,特把这个脚本share出来。 继续阅读→

阅读全文

Nginx的Web缓存服务主要由proxy_cache相关指令集和fastcgi_cache相关指令集构成,前者用于反向代理时,对后端内容源服务器进行缓存,后者主要用于对FastCGI的动态程序进行缓存。两者的功能基本上一样。

蚊子下午在翻看nginx所有addone模块的是,发现了ngx_slowfs_cache,它扩充了Nginx的缓存功能,通过 ngx_slowfs_cache 可以实现本地站点静态文件缓存(配合root指令使用)。此功能为低速的存储设备创建快速缓存提供了可能。 继续阅读→

阅读全文

蚊子前几天上线了个页面,程序员做的时候是把动态页面和静态页面分离开的放在了两个目录,同时呢,所用域名下又没有使用二级目录,目录结构是这样的

php文件:/data/webroot/php/cgi
html等静态文件:/data/webroot/html

访问情况是这样的(我用我自己的域名做举例):

d.wenzizone.cn/index.php或者d.wenzizone.cn—>/data/webroot/php/cgi/index.php
d.wenzizone.cn/index.html及所有静态文件 —>/ata/webroot/html
所有php的页面都 —>/data/webroot/php/cgi/

开发人员告诉我了这个结构之后,蚊子认为只能通过apache的url rewrite来实现了,apache的配置如下

<VirtualHost *:80>
    ServerAdmin webmaster@d.wenzizone.cn
    DocumentRoot /data0/webroot           #这里一定要设置到这级目录
    ServerName d.wenzizone.cn
    DirectoryIndex index.php
    ErrorLog logs/d.wenzizone.cn-error_log
    CustomLog logs/d.wenzizone.cn-access_log common
    <directory /data0/webroot>
        DirectoryIndex index.php
        rewriteengine on
        RewriteBase /      #将/data0/webroot设置为基准目录

        #将d.wenzizone.cn和d.wenzizone.cn/的访问转化成d.wenzizone.cn/index.php 

        rewritecond %{REQUEST_URI} ="" [OR]
        rewritecond %{REQUEST_URI} =/
        rewriterule ^(.*)$ index.php

        #将所有php的页面重定向到基准目录下的php/cgi目录下

        rewritecond %{REQUEST_FILENAME} !-f
        rewritecond %{REQUEST_FILENAME} \.php$
        rewriterule ^(.*)$ /php/cgi/$1 [L]

        #将所有非php的静态文件重定向到基准目录下的html目录下

        rewritecond %{REQUEST_FILENAME} !-f
        rewritecond %{REQUEST_URI} !\.php$
        rewriterule ^(.*)$ /html/$1 [L]
    </directory>

    #下面这两项是打开rewrite日志,当时蚊子为了调试打开了,成功之后关闭就好了,不然会增加apache负担
    #rewritelog /var/log/httpd/rewrite.log
    #RewriteLogLevel 3
</VirtualHost>

保存后重启apache就可以了。

另外补充一点的,对于上面这个需求来讲,在nginx下实现起来是非常容易的,下面蚊子也把nginx下的实现方式写出来

server {
    listen       80;
    server_name  d.wenzizone.cn;

    location = / {
        root /data1/webroot/php/cgi;
        index index.php;
    }

    location / {
        root /data1/webroot/html;
        index index.html index.htm;
        expires 30d;
    }

    location ~* \.php$ {
            root /data1/webroot/php/cgi;
            index index.php;
            fastcgi_pass   127.0.0.1:9000;
            include        fastcgi_params;
            fastcgi_param  SCRIPT_FILENAME          $document_root$uri;
            fastcgi_param  SCRIPT_NAME              $uri;
    }
}

对于蚊子的需求,基于apache如果哪位达人还有更好更简便的方法,还望告知,不胜感激

阅读全文

nginx当下已经成了很热门的玩意了,nginxcache大有替换squid的趋势,蚊子这边当下也用上了,nginx配置cache的我就不细说了,网上相关的文章挺多的

今天主要是表表nginx的清除cache的方法,nginx官方推荐的addones是Cache Purge Module,但蚊子配上发现并不是很好用,估计可能我没掌握要领吧,索性也不去理会了

闲来没事看了一下nginx的cache文件,发现和squid类似,都是hash的,那这样必然能在cache文件中找到想要的东西,于是就用strings看了一下,果然发现了缓存的页面,于是就有了下面的这个脚本

将文件存成clear_cache.sh,并赋予可执行权限

使用方法1:清除所有.jpg的连接

/path/clear_cache.sh .jpg$

使用方法2:清楚所有www.wenzizone.cn域名的链接

/path/clear_cache.sh www.wenzizone.cn

阅读全文

为了学习nginx,又苦于公司生产环境没有打算要换到nginx上,于是就想到拿自己搭建的监控环境开刀了,一路配置下来确实还是遇到不少麻烦,不过还好最终还都是圆满解决掉了,下面就把我这次从apache迁移到nginx的过程整理下来

原来的监控环境是apache+cacti+nagios,按照网上相关的文档,配置起来那真是傻瓜之所及也,我也不太想赘述了,网上google一下后大把大把的。

新的监控环境nginx+cacti+nagios,其实就是把apache换成了nginx而已,cacti和nagios的安装方法我也不多说了,自己去搜好了,就把转换过程和需要注意的地方写下来。

nginx安装我不赘述,首先是cacti相关的配置,详细如下

location /cacti/ {
         alias /data/wwwroot/web/cacti/;
         index index.php index.html index.htm;
         }

location ~ \.php$ {
         root           /data/wwwroot/web/;
         fastcgi_pass   127.0.0.1:9000;
         fastcgi_index  index.php;
         fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
         include        fastcgi_params;
        }

下面解释一下上面的配置,因为我的地址是http://ip/cacti/这样的形式,所以我定义了location /cacti/这个,然后把这个目录重定向到了cacti所在的目录,再看后面php的配置,首先定义了root地址是/data/wwwroot/web/这个就是后面$document_root内容,我的访问php的页面是http://ip/cacti/plugins/monitor/monitor.php,在这个url里cacti/plugins/monitor/monitor.php这部分是$fastcgi_script_name的值,因为涉及到了php页面,所以就会到$document_root即/data/wwwroot/web/下去找,这也就是为什么root定义的时候我不是直接的定义到了/data/wwwroot/web/cacti下,之前我就是在这里出的错误,结果就是始终找不到所需要的文件。

因为nginx本身是不支持cgi的,所以需要使用一个perl脚本来进行转换,脚本如下

#!/usr/bin/perl
use FCGI;
use Socket;
use FCGI::ProcManager;
sub shutdown { FCGI::CloseSocket($socket); exit; }
sub restart  { FCGI::CloseSocket($socket); &main; }
use sigtrap ‘handler’, \&shutdown, ‘normal-signals’;
use sigtrap ‘handler’, \&restart,  ‘HUP’;
require ‘syscall.ph’;
use POSIX qw(setsid);

END()   { }
BEGIN() { }
{
 no warnings;
*CORE::GLOBAL::exit = sub { die "fakeexit\nrc=" . shift() . "\n"; };
};
eval q{exit};
if ($@) {
 exit unless $@ =~ /^fakeexit/;
}
&main;

sub daemonize() {
 chdir ‘/’ or die "Can’t chdir to /: $!";
 defined( my $pid = fork ) or die "Can’t fork: $!";
 exit if $pid;
 setsid() or die "Can’t start a new session: $!";
 umask 0;
}

sub main {

 $proc_manager = FCGI::ProcManager->new( {n_processes => 5} );
 $socket = FCGI::OpenSocket( "/usr/local/nginx/logs/cgi.sock", 10 )
 ; #use UNIX sockets – user running this script must have w access to the ‘nginx’ folder!!
 $request =
 FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket,
 &FCGI::FAIL_ACCEPT_ON_INTR );
 $proc_manager->pm_manage();
 if ($request) { request_loop() }
 FCGI::CloseSocket($socket);
}

sub request_loop {
 while ( $request->Accept() >= 0 ) {
 $proc_manager->pm_pre_dispatch();

 #processing any STDIN input from WebServer (for CGI-POST actions)
 $stdin_passthrough = ”;
 { no warnings; $req_len = 0 + $req_params{‘CONTENT_LENGTH’}; };
 if ( ( $req_params{‘REQUEST_METHOD’} eq ‘POST’ ) && ( $req_len != 0 ) )
 {
 my $bytes_read = 0;
 while ( $bytes_read < $req_len ) {
 my $data = ”;
 my $bytes = read( STDIN, $data, ( $req_len – $bytes_read ) );
 last if ( $bytes == 0 || !defined($bytes) );
 $stdin_passthrough .= $data;
 $bytes_read += $bytes;
 }
 }

 #running the cgi app
 if (
 ( -x $req_params{SCRIPT_FILENAME} ) &&    #can I execute this?
 ( -s $req_params{SCRIPT_FILENAME} ) &&    #Is this file empty?
 ( -r $req_params{SCRIPT_FILENAME} )       #can I read this file?
 )
 {
 pipe( CHILD_RD,   PARENT_WR );
 pipe( PARENT_ERR, CHILD_ERR );
 my $pid = open( CHILD_O, "-|" );
 unless ( defined($pid) ) {
 print("Content-type: text/plain\r\n\r\n");
 print
"Error: CGI app returned no output – Executing $req_params{SCRIPT_FILENAME} failed !\n";
 next;
 }
 $oldfh = select(PARENT_ERR);
 $|     = 1;
 select(CHILD_O);
 $| = 1;
 select($oldfh);
 if ( $pid > 0 ) {
 close(CHILD_RD);
 close(CHILD_ERR);
 print PARENT_WR $stdin_passthrough;
 close(PARENT_WR);
 $rin = $rout = $ein = $eout = ”;
 vec( $rin, fileno(CHILD_O),    1 ) = 1;
 vec( $rin, fileno(PARENT_ERR), 1 ) = 1;
 $ein    = $rin;
 $nfound = 0;

 while ( $nfound =
 select( $rout = $rin, undef, $ein = $eout, 10 ) )
 {
 die "$!" unless $nfound != -1;
 $r1 = vec( $rout, fileno(PARENT_ERR), 1 ) == 1;
 $r2 = vec( $rout, fileno(CHILD_O),    1 ) == 1;
 $e1 = vec( $eout, fileno(PARENT_ERR), 1 ) == 1;
 $e2 = vec( $eout, fileno(CHILD_O),    1 ) == 1;

 if ($r1) {
 while ( $bytes = read( PARENT_ERR, $errbytes, 4096 ) ) {
 print STDERR $errbytes;
 }
 if ($!) {
 $err = $!;
 die $!;
 vec( $rin, fileno(PARENT_ERR), 1 ) = 0
 unless ( $err == EINTR or $err == EAGAIN );
 }
 }
 if ($r2) {
 while ( $bytes = read( CHILD_O, $s, 4096 ) ) {
 print $s;
 }
 if ( !defined($bytes) ) {
 $err = $!;
 die $!;
 vec( $rin, fileno(CHILD_O), 1 ) = 0
 unless ( $err == EINTR or $err == EAGAIN );
 }
 }
 last if ( $e1 || $e2 );
 }
 close CHILD_RD;
 close PARENT_ERR;
 waitpid( $pid, 0 );
 } else {
 foreach $key ( keys %req_params ) {
 $ENV{$key} = $req_params{$key};
 }

 # cd to the script’s local directory
 if ( $req_params{SCRIPT_FILENAME} =~ /^(.*)\/[^\/] +$/ ) {
 chdir $1;
 }
 close(PARENT_WR);

 #close(PARENT_ERR);
 close(STDIN);
 close(STDERR);

 #fcntl(CHILD_RD, F_DUPFD, 0);
 syscall( &SYS_dup2, fileno(CHILD_RD),  0 );
 syscall( &SYS_dup2, fileno(CHILD_ERR), 2 );

 #open(STDIN, "<&CHILD_RD");
 exec( $req_params{SCRIPT_FILENAME} );
 die("exec failed");
 }
 } else {
 print("Content-type: text/plain\r\n\r\n");
 print
"Error: No such CGI app – $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n";
 }
 }
}

把上面这个脚本存放在/usr/local/bin下或者你习惯放置的位置,起名cgiwrap-fcgi.pl,当然你也可以使用其他的名字。当执行这个pl脚本的时候会在/usr/local/nginx/logs/生成一个cgi.sock文件,这个生成的文件要对nginx运行用户有访问的权限,因为我nginx用daemon这个用户跑的,所以我设置这个文件对daemon用户有访问的权限。

这个脚本设置好了之后再来看下nginx里的配置

location ~\.cgi$ {
         rewrite ^/nagios/cgi-bin/(.*)\.cgi /$1.cgi break;
         fastcgi_pass unix:/usr/local/nginx/logs/cgi.sock;
         fastcgi_param  SCRIPT_FILENAME  /usr/local/nagios/sbin/$fastcgi_script_name;
         include        fastcgi_params; 
         fastcgi_index  index.cgi;
         auth_basic      "nagios";
        auth_basic_user_file    /usr/local/nagios/etc/htpasswd.users; 
         }

location /nagios/ { 
         alias /usr/local/nagios/share/; 
         index index.html; 
         auth_basic      "nagios"; 
        auth_basic_user_file    /usr/local/nagios/etc/htpasswd.users; 
         }

location /pub/images/ {
                        alias /usr/local/nagios/share/docs/images/; 
         auth_basic      "nagios";
            auth_basic_user_file    /usr/local/nagios/etc/htpasswd.users; 
         }

接下来就是需要生成nagios执行cgi的用户和设置密码

/usr/local/apache2/bin/htpasswd -c /usr/local/nginx/conf/htpasswd.users nagiosadmin

接下来修改/usr/local/nagios/etc/cgi.cfg文件,在其中找到#default_user_name=guest这行,将其改为default_user_name=nagiosadmin,到此迁移工作就已经完成了,下面来启动相应的程序来测试吧,再次我写了一个nginx的启动脚本,内容如下

#!/bin/sh

spswfile=/usr/local/php529/bin/spawn-fcgi
phpcgi=/usr/local/php529/bin/php-cgi
nginxfile=/usr/local/nginx/sbin/nginx
cgifile=/usr/local/bin/cgiwrap-fcgi.pl

isrun() {
    if
        (ps auxf|grep nginx|grep -v grep >/dev/null 2>&1) && (ps auxf|grep php-cgi|grep -v grep >/dev/null 2>&1)
    then
        return 0
    else
        return 1
    fi
}

nginx_start() {
    if isrun
    then
        echo "nginx already start"
        exit 0
    else
        killall -9 php-cgi >/dev/null 2>&1
        killall -9 nginx >/dev/null 2>&1
                killall -9 perl >/dev/null 2>&1
        $spswfile -a 127.0.0.1 -p 9000 -f $phpcgi >/dev/null 2>&1
                /usr/bin/perl $cgifile >/dev/null 2>&1 &
        $nginxfile >/dev/null 2>&1
                sleep 10
                /bin/chown daemon /usr/local/nginx/logs/cgi.sock
    fi
}

nginx_stop() {
        killall -9 php-cgi >/dev/null 2>&1
        killall -9 nginx >/dev/null 2>&1
                killall -9 perl >/dev/null 2>&1
        rm -rf /usr/local/nginx/logs/nginx.pid
}

case $1 in
    start)      nginx_start;;
    stop)       nginx_stop;;
    restart)    nginx_stop
                nginx_start
                ;;
    *)          echo "useage: {start|stop}";;
esac

这样只需要执行这个脚本就可以启动fastcgi和cgi及nginx了,接下来就可以进行真正的测试了

以上文章参考了:

http://wiki.nginx.org/NginxSimpleCGI
http://www.lazysa.com/2009/05/392.html

另外有一点需要注意的就是cgi.cfg的修改,网上很多文章都没有提到,就是我上面写的那个是有默认用户的,如果那个不做修改的话,访问nagios的主机和服务的时候都显示如下,更改之后就没有问题了

无权查看任何主机的信息…
请检查HTTP服务器关于该CGI的访问权限设置。

 

 

阅读全文

今天自己在nginx环境下配置了一个wordpress,用来在实际的应用中学习nginx,不料,却遇到了个小问题,先把文件解决办法总结如下。

我设置了一个域名:http://www.wenzi.cn/
我的wordpress地址是:http://www.wenzi.cn/wordpress/

现在的问题就是如果我访问http://www.wenzi.cn/wordpress/就可以显示出我的blog的地址,但如果我访问http://www.wenzi.cn/wordpress结果却提示说找不到所需要的页面。群里问了一下,说是,nginx不会自动在请求的最后加上一个/的,原因是nginx不会自动判断请求的是一个文件还是一个目录,google上可以搜到解决办法,于是乎我就去google了一下,确实找到了

在配置文件中location里加入如下代码

if (-d $request_filename){
    rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
}

这样再对http://www.wenzi.cn/wordpress请求,nginx就会进行判断了,如果请求的是一个文件夹,会自动在最后加上/符号,如果请求的是一个文件,则不会改变原有url

接下来对这段代码进行一个解释

1,if (-d $request_filename),如果请求的是一个文件夹,则为真,进到if语句中执行
2,rewrite是执行url重写操作
3,^/(.*)([^/])$表示以/符号开始并紧跟着任何字符,同时不是以/为结束的字符串,在我的url中,(.*)表示的wordpres,([^/])表示的s
4,http://$host/$1$2/ 表示的重写后的地址,$host是请求的域名,$1是前面第一个括号里的内容,在我的url里就是wordpres $2是前面第二个括号里的内容,在我的url里是s
5,permanent表示,返回值是301

 

阅读全文

上次我说了使用squid自己的堆叠机制实现提高squid使用率的方法,这次再来说说和nginx搭配使用提高多台squid的使用率,目标当然是使用有限的squid服务器,缓存住更多的静态文件。

首先进到nginx的目录
执行patch -p0 < /path/to/upstream/hash/directory/nginx.patch

然后在安装的时候加上
–add-module=path/to/upstream/hash/directory

我的测试环境vmvare 模拟3个linux
ip分别:nginx 192.168.211.130
squid01 192.168.211.128
squid02 192.168.211.129
测试网站我反向代理www.tgbus.com

这样nginx上编译完成需要配置,内容如下

http {

upstream www.tgbus.com {
server 192.168.211.128;
server 192.168.211.129;
hash $request_uri;
}
server {
listen 80;
server_name www.tgbus.com;
location / {
proxy_pass http: / /bbs.tgbus.com;
}
}
}

然后启动nginx

两个squid就配置成标准的反向代理就可以了,主要配置如下

cache_peer 61.152.242.1 parent 80 0 no -digest no -query originserver name=www
cache_peer_domain www www.tgbus.com

然后启动squid

修改自己电脑的hosts,把www.tgbus.com的ip指向到nginx那台虚拟机的ip上,接下来就可以测试了
打开两台squid的日志,用tail -f的方式,然后访问www.tgbus.com,可以看到两边的日志的内容是不一样的,从其中一台squid的日志中找一条静态文件的url,通过ie 打开,可以发现,这个url的访问只投到同一台squid上,如此实现了,squid缓存的内容不同,从而增加了squid的缓存容量
当然,如果中间只使用一台nginx,自然这台会成为单点而造成隐患,所以可是使用heartbeat做成双机,增加系统的可靠性。
阅读全文