工作,学习,生活,这里将会有一些记录. 备用域名:http://meisw.wdlinux.cn 注册 | 登陆
浏览模式: 标准 | 列表分类:nginx

Nginx 简单的负载均衡配置示例

user  www www;

worker_processes 10;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

#最大文件描述符
worker_rlimit_nofile 51200;

events
{
      use epoll;

      worker_connections 51200;
}

http
{
      include       conf/mime.types;
      default_type  application/octet-stream;

      keepalive_timeout 120;

      tcp_nodelay on;

      upstream  www.s135.com  {
              server   192.168.1.2:80;
              server   192.168.1.3:80;
              server   192.168.1.4:80;
              server   192.168.1.5:80;
      }

      upstream  blog.s135.com  {
              server   192.168.1.7:8080;
              server   192.168.1.7:8081;
              server   192.168.1.7:8082;
      }

      server
      {
              listen  80;
              server_name  www.s135.com;

              location / {
                       proxy_pass        http://www.s135.com;
                       proxy_set_header   Host             $host;
                       proxy_set_header   X-Real-IP        $remote_addr;
                       proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
              }

              log_format  www_s135_com  '$remote_addr - $remote_user [$time_local] $request '
                                '"$status" $body_bytes_sent "$http_referer" '
                                '"$http_user_agent" "$http_x_forwarded_for"';
              access_log  /data1/logs/www.log  www_s135_com;
      }

      server
      {
              listen  80;
              server_name  blog.s135.com;

              location / {
                       proxy_pass        http://blog.s135.com;
                       proxy_set_header   Host             $host;
                       proxy_set_header   X-Real-IP        $remote_addr;
                       proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
              }

              log_format  blog_s135_com  '$remote_addr - $remote_user [$time_local] $request '
                                '"$status" $body_bytes_sent "$http_referer" '
                                '"$http_user_agent" "$http_x_forwarded_for"';
              access_log  /data1/logs/blog.log  blog_s135_com;
      }
}

Nginx实践1 利用proxy_store实现高效的静态文件分布缓存服务器

曾经写过是否要放弃使用varnish/squid, 经过几天的实验,终于找到一种比较理想的解决方案:
直接使用proxy模块的proxy_store来实现分布mirror.

首先说说我的需求:

1. 我需要将一些静态文件从应用服务器剥离, 负载到其他的节点.
2. 这些文件主要是静态Html和图片,包括缩略图. 这些文件一旦创建,更新的频率很少.
3. 在某些时候需要手动立即从各个分布节点删除或更新某些文件
4. 尽可能减少应用服务器的请求, 进而减少内网的流量

之前,我分别使用了squid和varnish.
最初用的squid,还凑合.不过,squid在高负载下会出现停滞甚至crash或者是空白页.
于是换成varnish.
varnish也是老毛病,偶尔也会crash.

二者的共同点,就是当cache快满的时候,效率会急剧下降, 同时,对主服务器的请求甚至都
阻塞了整个内网.

要解决这个情况,varnish需要手动重启, squid则需要清除整个缓存目录.

对于varnish, 由于是纯内存的加速,因此,无法将cache设置太大,否则用上swap, 基本上是几倍的速度下降,
而且很容易就段违例了. 于是,当bots访问网站的时段, 就是噩梦产生的时候, 由于爬虫遍历太多的文件,
造成缓存很快溢出,于是频繁的invalid,此时,内网的带宽占用能达到100m以上….

可能有人说,为什么不用NFS. NFS的问题主要是锁的问题. 很容易造成死锁, 只有硬件重启才能解决.

为了脱离这个噩梦,我决定试验nginx的proxy_store. 如果使用Lighty,倒是非常简单,因为有mod_cache,配合lua,
会很灵活. 不过nginx的proxy_store并非是一个cache,因为它不具备expires, 新的cache模块仍在开发中.
不过经过仔细考量, 我惊喜的发现,其实这正是我想要的, 因为在我的需求中,绝大多数的文件都是不过期的,因而也无必要
去和后端服务器验证是否过期.

配置其实并不太复杂,但是过程有些曲折, 基本的思路是:
nginx首先检查本地是否有请求的文件,如果有直接送出,没有则从后端请求,并将结果存储在本地.

第一个方案,是基于error_page来实现的:

upstream backend{
server 192.168.8.10:80;
}
server {
listen 80;
access_log /logs/cache.log main;
server_name blog.night9.cn www.night9.cn night9.cn;
proxy_temp_path /cache/temp;
root /cache/$host;
location / {
index index.shtml;
error_page 404 = /fetch$uri;
}
ssi on;
location /fetch {
internal;
proxy_pass http://backend;
proxy_store on;
proxy_store_access user:rw group:rw all:rw;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Via "s9/nginx";
alias /cache/$host;
}
#对于请求目录的情况下要特殊对待
location ~ /$ {
index index.shtml;
error_page 403 404 = @fetch;
}
location @fetch {
internal;
proxy_pass http://backend;
proxy_store /cache/$host${uri}index.shtml;
proxy_store_access user:rw group:rw all:rw;
proxy_set_header Host $host;
proxy_set_header Via "s9/nginx";
proxy_set_header X-Real-IP $remote_addr;
}
}

这个方案对于普通的情况下,基本满足.

缓存是做到了,但是如何实现更新呢?
其实很简单,只要将指定url的从本地cache目录删除即可.
因为proxy_store会按照实际请求的url地址建立相应的目录结构.

于是,我写了一个fastcgi, 只要将需要清楚的url传递给它,从cache目录中删除.
其实可以用perl_module实现,但是考虑到独立fastcgi服务更为稳定,还是和以前的统计一样,
用perl的CGI::Fast模块实现, 替换了10几行代码就搞定了.

事情本来就该告一段,不过,由于主服务器上使用了SSI, 新的问题就来了:
我们希望SSI的解析是在子节点上进行,而不是在主服务器上进行, 这样我们可以独立更新相应
区块的文件即可, 否则就需要清除所有的shtml文件,这是比较可怕的.

但是,Nginx对于SSI的subrequest无法使用error_page来重定向.(不确定是否是bug,不过如果允许
的确容易造成死循环).

于是,一个更为简单的方案就诞生了:

set $index 'index.shtml';
set $store_file $request_filename;
if ($uri ~ /$ ){
set $store_file $request_filename$index;
rewrite (.*) $1index.shtml last;
}
location / {
index index.shtml;
proxy_store on;
proxy_temp_path /cache/temp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Via "s9/nginx";
proxy_store_access user:rw group:rw all:rw;
if ( !-e $store_file ) {
proxy_pass http://backend;
}
}

Wow! 更为简单.
应该感谢Nginx的Rewrite模块, 这点也是我用Nginx替换Lighttpd的一个主要原因.

好了,我可以忘掉varnish,squid了.

如果有兴趣的人想使用, 请一定注意:
这个方案对静态文件更为有效,如果要加速动态请求,还是要用varnish

说道加速, 利用Memcached和nginx配合可以迅速提升访问动态页面的速度,
有时间再说.

NGINX: expires浏览器本地缓存设置

expires浏览器本地缓存设置
expires
语法:expires [time|epoch|max|off]
默认值:expires off
使用字段:http, server, location
在应答头中是否开启对“Expires”和“Cache-Control”的增加和修改操作。
可以指定一个正或负的时间值,Expires头中的时间根据目前时间和指令中指定的时间的和来获
得。
epoch表示自1970年一月一日00:00:01 GMT的绝对时间,max指定Expires的值为2037年12月31日
23:59:59,Cache-Control的值为10 years。
Cache-Control头的内容随预设的时间标识指定:
·设置为负数的时间值:Cache-Control: no-cache。
·设置为正数或0的时间值:Cache-Control: max-age = #,这里#的单位为秒,在指令中指定。
参数off禁止修改应答头中的"Expires"和"Cache-Control"。
注意:expires仅仅适用于200, 204, 301, 302,和304应答

//对图片,flash文件在浏览器本地缓存30天
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
     {
      expires 30d;
     }

//对js,css文件在浏览器本地缓存1小时
location ~ .*\.(js|css)$
      {
       expires 1h;
      }

nginx的301重定向规则

两种实现方法,第一种方法是判断nginx核心变量host(老版本是http_host):
server {
server_name www.test.com test.com ;
if ($host != 'www.test.com' ) {
rewrite ^/(.*)$ http://www.test.com/$1 permanent;
}
...
}
第二种方法:
server {
server_name test.com;
rewrite ^/(.*) http://www.test.com/$1 permanent;
}
我用的是第一种方法,这两种方法中, permanent是关键,详细说明见nginx重定向规则说明。

last – 基本上都用这个Flag。
break – 中止Rewirte,不在继续匹配
redirect – 返回临时重定向的HTTP状态302
permanent – 返回永久重定向的HTTP状态301

nginx重定向规则详细介绍

Nginx的重定向用到了Nginx的HttpRewriteModule,下面简单解释以下如何使用的方法:

rewrite命令

nginx的rewrite相当于apache的rewriterule(大多数情况下可以把原有apache的rewrite规则加上引号就可以直接使用),它可以用在server,location 和IF条件判断块中,命令格式如下:
rewrite 正则表达式 替换目标 flag标记
flag标记可以用以下几种格式:
last – 基本上都用这个Flag。
break – 中止Rewirte,不在继续匹配
redirect – 返回临时重定向的HTTP状态302
permanent – 返回永久重定向的HTTP状态301

例如下面这段设定nginx将某个目录下面的文件重定向到另一个目录,$2对应第二个括号(.*)中对应的字符串:
location /download/ {
rewrite ^(/download/.*)/m/(.*)\..*$ $1/nginx-rewrite/$2.gz break;
}

nginx重定向的IF条件判断
在server和location两种情况下可以使用nginx的IF条件判断,条件可以为以下几种:
正则表达式

如:
匹配判断
~  为区分大小写匹配; !~为区分大小写不匹配
 ~* 为不区分大小写匹配;!~为不区分大小写不匹配
例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下:
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /nginx-ie/$1 break;
}
文件和目录判断
  -f和!-f判断是否存在文件
 -d和!-d判断是否存在目录
 -e和!-e判断是否存在文件或目录
 -x和!-x判断文件是否可执行
例如下面设定nginx在文件和目录不存在的时候重定向:
if (!-e $request_filename) {
proxy_pass http://127.0.0.1;
}

return
返回http代码,例如设置nginx防盗链:
location ~* \.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.localhost;
if ($invalid_referer) {
return 404;
}
}

set
设置nginx变量

nginx防盗链设置

防止盗链不仅能保护版权,又节约了不少流量。最近和bsdmap交流了下,听说他们通过防盗链节约了近1/3的图片流量。nginx的防盗链设置还是比较简单的,可以分为普通防盗链和ip/cookie based防盗链。其中ip based防盗链需要安装nginx的module,所以相对麻烦一些。

nginx最简单的防盗链设置如下
location ~* .(gif|jpg|png|swf|flv)$ {
valid_referers none blocked localhost;
if ($invalid_referer) {
return 403;
}
}
通过nginx的重定向方式返回403错误。

NginxHttpAccessKeyModule实现防盗链
需要先安装nginx的NginxHttpAccessKeyModule模块。其运行方式是:如我的nginx目录下有一个file.gz 的文件。对应的URI 是http://localhost/nginx/file.gz
若用ngx_http_accesskey_module 后则根据用户的IP生成一个key值,如下的链接来访问http://localhost/download/file.zip?key=23497sdf897. 只有给定的key值正确了,才能够下载nginx目录下的file.gz,这样就可以避免被盗链了。

Records:301234