Nginx

首先看一下Nginx的工作模式
master进程负责管理worker,处理客户端请求.

配置文件组成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
main # 全局设置
events { # Nginx工作模式
....
}
http { # http设置
....
upstream myproject { # 负载均衡服务器设置
.....
}
server { # 主机设置
....
location { # URL匹配
....
}
}
server { #其他主机
....
location {
....
}
}
....
}

main 模块

1
2
3
4
5
user nobody nobody;
worker_processes 2;
error_log /usr/local/var/log/nginx/error.log notice;
pid /usr/local/var/run/nginx/nginx.pid;
worker_rlimit_nofile 1024;

user 来指定Nginx Worker进程运行用户以及用户组,默认由nobody账号运行。

worker_processes 来指定了Nginx要开启的子进程数。每个Nginx进程平均耗费10M~12M内存。根据经验,一般指定1个进程就足够了,如果是多核CPU,建议指定和CPU的数量一样的进程数即可。我这里写2,那么就会开启2个子进程,总共3个进程。

error_log 来定义全局错误日志文件。日志输出级别有debug、info、notice、warn、error、crit可供选择,其中,debug输出日志最为最详细,而crit输出日志最少。

pid 来指定进程id的存储文件位置。

worker_rlimit_nofile 来指定一个nginx进程可以打开的最多文件描述符数目,这里是65535,需要使用命令“ulimit -n 65535”来设
置。

events模块

events模块来用指定nginx的工作模式和工作模式及连接数上限,一般是这样:

1
2
3
4
events {
use epoll; #Linux平台
worker_connections 1024;
}

use 用来指定Nginx的工作模式。Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll。其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中,因为Mac基于BSD,所以Mac也得用这个模式,对于Linux系统,epoll工作模式是首选。

worker_connections 用于定义Nginx每个进程的最大连接数,即接收前端的最大请求数,默认是1024。最大客户端连接数由 worker_processes和worker_connections决定,即Max_clients = worker_processes * worker_connections,在作为反向代理时,Max_clients变为:Max_clients = worker_processes * worker_connections / 4

进程的最大连接数受Linux系统进程的最大打开文件数限制,在执行操作系统命令“ulimit -n 65536”后worker_connections的设置才能生效。

http模块

http模块可以说是最核心的模块了,它负责HTTP服务器相关属性的配置,它里面的server和upstream子模块,至关重要,等到反向代理和负载均衡以及虚拟目录等会仔细说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /usr/local/var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 10;
#gzip on;
upstream myproject {
.....
}
server {
....
}
}

include用来设定文件的mime类型,类型在配置文件目录下的mime.type文件定义,来告诉nginx来识别文件类型。

default_type设定了默认的类型为二进制流,也就是当文件类型未定义时使用这种方式,例如在没有配置asp的locate 环境时,Nginx是不予解析的,此时,用浏览器访问asp文件就会出现下载窗口了。

log_format用于设置日志的格式,和记录哪些参数,这里设置为main,刚好用于access_log来纪录这种类型。
main的类型日志如下:也可以增删部分参数。

127.0.0.1 - - [21/Apr/2015:18:09:54 +0800] “GET /index.php HTTP/1.1” 200 87151 “-“ “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36”
access_log

用来纪录每次的访问日志的文件地址,后面的main是日志的格式样式,对应于log_format的main。

sendfile用于开启高效文件传输模式。将tcp_nopush和tcp_nodelay两个指令设置为on用于防止网络阻塞。

keepalive_timeout设置客户端连接保持活动的超时时间。在超过这个时间之后,服务器会关闭该连接。

server模块

server模块是http的子模块,它用来定一个虚拟主机,我们先讲最基本的配置,这些在后面再讲。我们看一下一个简单的server是如何做的?

1
2
3
4
5
6
7
8
9
10
11
server {
listen 8080;
server_name localhost 192.168.12.10 www.yangyi.com;
# 全局定义,如果都是这一个目录,这样定义最简单。
root /Users/yangyi/www;
index index.php index.html index.htm;
charset utf-8;
access_log usr/local/var/log/host.access.log main;
error_log usr/local/var/log/host.error.log error;
....
}

server 标志定义虚拟主机开始。

listen 用于指定虚拟主机的服务端口。

server_name 用来指定IP地址或者域名,多个域名之间用空格分开。

root 表示在这整个server虚拟主机内,全部的root web根目录。注意要和locate {}下面定义的区分开来。

index 全局定义访问的默认首页地址。注意要和locate {}下面定义的区分开来。

charset 用于设置网页的默认编码格式。

access_log 用来指定此虚拟主机的访问日志存放路径,最后的main用于指定访问日志的输出格式。

location模块

location模块是nginx中用的最多的,也是最重要的模块了,什么负载均衡啊、反向代理啊、虚拟域名啊都与它相关。

location根据它字面意思就知道是来定位的,定位URL,解析URL,所以,它也提供了强大的正则匹配功能,也支持条件判断匹配,用户可以通过location指令实现Nginx对动、静态网页进行过滤处理。像我们的php环境搭建就是用到了它。

我们先来看这个,设定默认首页和虚拟机目录

1
2
3
4
location / {
root /Users/yangyi/www;
index index.php index.html index.htm;
}

location / 表示匹配访问根目录。

root 指令用于指定访问根目录时,虚拟主机的web目录,这个目录可以是相对路径(相对路径是相对于nginx的安装目录)。也可以是绝对路径。

index 用于设定我们只输入域名后访问的默认首页地址,有个先后顺序:index.php index.html index.htm,如果没有开启目录浏览权限,又找不到这些默认首页,就会报403错误。
location 还有一种方式就是正则匹配,开启正则匹配这样:location ~。后面加个~

下面这个例子是运用正则匹配来链接php。我们之前搭建环境也是这样做:

1
2
3
4
5
6
location ~ \.php$ {
root /Users/yangyi/www;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}

.php$ 熟悉正则的我们直到,这是匹配.php结尾的URL,用来解析php文件。里面的root也是一样,用来表示虚拟主机的根目录。

fastcgi_pass 链接的是php-fpm的地址。其他几个参数我们以后再说。

location 还有其他用法,等讲到实例的时候,再看吧。

upstream模块

upstream 模块负责负载均衡模块,通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。先学习怎么用,具体的使用实例以后再说。

1
2
3
4
5
6
7
upstream iyangyi.com{
ip_hash;
server 192.168.12.1:80;
server 192.168.12.2:80 down;
server 192.168.12.3:8080 max_fails=3 fail_timeout=20s;
server 192.168.12.4:8080 backup;
}

在上面的例子中,通过upstream指令指定了一个负载均衡器的名称iyangyi.com。这个名称可以任意指定,在后面需要的地方直接调用即可。里面是ip_hash这是其中的一种负载均衡调度算法,下面会着重介绍。紧接着就是各种服务器了。用server关键字表识,后面接ip。

Nginx的负载均衡模块目前支持4种调度算法:

  • weight 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。weight。指定轮询权值,weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。

  • ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。

  • fair(第三方)。比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。

  • url_hash(第三方)。按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx的hash软件包。

在HTTP Upstream模块中,可以通过server指令指定后端服务器的IP地址和端口,同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有:

  • down,表示当前的server暂时不参与负载均衡。
  • backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
  • max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。

    注意:当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。

配置实战

基于域名的虚拟主机

假设我们在本地开发有3个项目,分别在hosts里映射到本地的127.0.0.1上:

127.0.0.1 www.iyangyi.com iyangyi.com
127.0.0.1 api.iyangyi.com
127.0.0.1 admin.iyangyi.com
有这样3个项目,分别对应于web根目录下的3个文件夹,我们用域名对应文件夹名字,这样子好记:

/Users/yangyi/www/www.iyangyi.com/
/Users/yangyi/www/api.iyangyi.com/
/Users/yangyi/www/admin.iyangyi.com/
每个目录下都有一个index.php文件,都是简单的输入自己的域名。

下面我们就来搭建这3个域名的虚拟主机,很显然,我们要新建3个server来完成。建议将对虚拟主机进行配置的内容写进另外一个文件,然后通过include指令包含进来,这样更便于维护和管理。不会使得这个nginx.conf内容太多:

1
2
3
4
5
6
7
8
main
events {
....
}
http {
....
include vhost/*.conf
}

include:主模块指令,实现对配置文件所包含的文件的设定,可以减少主配置文件的复杂度。

既然每一个conf都是一个server,前面已经学习了一个完整的server写的了。下面就开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#cat www.iyangyi.conf
server {
listen 80;
server_name www.iyangyi.com iyangyi.com;
root /Users/yangyi/www/www.iyangyi.com/;
index index.php index.html index.htm;
access_log /usr/local/var/log/nginx/www.iyangyi.access.log main;
error_log /usr/local/var/log/nginx/www.iyangyi.error.log error;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
#cat api.iyangyi.conf
server {
listen 80;
server_name api.iyangyi.com;
root /Users/yangyi/www/api.iyangyi.com/;
index index.php index.html index.htm;
access_log /usr/local/var/log/nginx/api.iyangyi.access.log main;
error_log /usr/local/var/log/nginx/api.iyangyi.error.log error;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
#cat admin.iyangyi.conf
server {
listen 80;
server_name admin.iyangyi.com;
root /Users/yangyi/www/admin.iyangyi.com/;
index index.php index.html index.htm;
access_log /usr/local/var/log/nginx/admin.iyangyi.access.log main;
error_log /usr/local/var/log/nginx/admin.iyangyi.error.log error;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}

这样3个很精简的虚拟域名就搭建好了。重启下nginx,然后打开浏览器访问一下这3个域名,就能看到对应的域名内容了。

反向代理

首先看一张图,区分反向代理和正向代理的区别

主要是客户端和 代理服务器的区域划分问题

Nginx 使用反向代理,主要是使用location模块下的proxy_pass选项。

来个最简单的。当我访问 mac 上的nginx 的 centos.iyangyi.com 的内容时候, 就反向代理到虚拟机centos上的 apache 192.168.33.10 的index.html页面。

192.168.33.10 中的html 是很简单的一句输出:

centos apache2 index.html
在hosts里新加上这个域名:

vi /etc/hosts
127.0.0.1 centos.iyangyi.com
在vhost目录中新建一个conf server:

1
2
3
4
5
6
7
8
9
10
11
12
#centos.iyangyi.conf
server {
listen 80;
server_name centos.iyangyi.com;
access_log /usr/local/var/log/nginx/centos.iyangyi.access.log main;
error_log /usr/local/var/log/nginx/centos.iyangyi.error.log error;
location / {
proxy_pass http://192.168.33.10;
}
}

重启下nginx,访问一下就会有效果了
安装官方文档,反向代理共有一下参数

1
2
3
4
5
6
7
8
9
10
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;

负载均衡

别被这个名字给吓住了,以为是什么很牛逼的东西的。其实不然。也很简单。

先简单说下负载均衡是干嘛的?举个例子:我们的小网站,刚开始就一台nginx服务器,后来,随着业务量增大,用户增多,一台服务器已经不够用了,我们就又多加了几台服务器。那么这几台服务器如何调度?如何均匀的提供访问?这就是负载均衡。

负载均衡的好处是可以集群多台机器一起工作,并且对外的IP和域名是一样的,外界看起来就好像一台机器一样。

基于 weight 权重的负载

先来一个最简单的,weight权重的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
upstream webservers{
server 192.168.33.11 weight=10 max_fails=2 fail_timeout=30s;;
server 192.168.33.12 weight=10;
server 192.168.33.13 weight=10;
}
server {
listen 80;
server_name upstream.iyangyi.com;
access_log /usr/local/var/log/nginx/upstream.iyangyi.access.log main;
error_log /usr/local/var/log/nginx/upstream.iyangyi.error.log error;
location / {
proxy_pass http://webservers;
proxy_set_header X-Real-IP $remote_addr;
}
}

]

max_fails : 允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。

fail_timeout : 在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用,进行健康状态检查。

down: 表示这台机器暂时不参与负载均衡。相当于注释掉了。

backup: 表示这台机器是备用机器,是其他的机器不能用的时候,这台机器才会被使用,俗称备胎

基于 ip_hash 的负载

这种分配方式,每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。

upstream webservers{
ip_hash;
server 192.168.33.11 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.33.12 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.33.13 down;
}
ip_hash 模式下,最好不要设置weight参数,因为你设置了,就相当于手动设置了,将会导致很多的流量分配不均匀。

ip_hash 模式下,backup参数不可用,加了会报错,为啥呢?因为,本身我们的访问就是固定的了,其实,备用已经不管什么作用了。

页面缓存

页面缓存也是日常web 开发中很重要的一个环节,对于一些页面,我们可以将其静态化,保存起来,下次请求时候,直接走缓存,而不用去请求反相代理服务器甚至数据库服务了。从而减轻服务器压力。

nginx 也提供了简单而强大的下重定向,反向代理的缓存功能,只需要简单配置下,就能将指定的一个页面缓存起来。它的原理也很简单,就是匹配当前访问的url, hash加密后,去指定的缓存目录找,看有没有,有的话就说明匹配到缓存了。

我们先来看一下一个简单的页面缓存的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http {
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=cache_zone:10m inactive=1d max_size=100m;
upstream myproject {
.....
}
server {
....
location ~ *\.php$ {
proxy_cache cache_zone; #keys_zone的名字
proxy_cache_key $host$uri$is_args$args; #缓存规则
proxy_cache_valid any 1d;
proxy_pass http://127.0.0.1:8080;
}
}
....
}

下面我们来一步一步说。用到的配置参数,主要是proxy_*前缀的很多配置。

首先需要在http中加入proxy_cache_path 它用来制定缓存的目录以及缓存目录深度制定等。它的格式如下:

proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];
path是用来指定 缓存在磁盘的路径地址。比如:/data/nginx/cache。那以后生存的缓存文件就会存在这个目录下。

  • levels用来指定缓存文件夹的级数,可以是:levels=1, levels=1:1, levels=1:2, levels=1:2:3 可以使用任意的1位或2位数字作为目录结构分割符,如 X, X:X,或 X:X:X 例如: 2, 2:2, 1:1:2,但是最多只能是三级目录。
    那这个里面的数字是什么意思呢。表示取hash值的个数。比如:

现在根据请求地址localhost/index.php?a=4 用md5进行哈希,得到e0bd86606797639426a92306b1b98ad9

levels=1:2 表示建立2级目录,把hash最后1位(9)拿出建一个目录,然后再把9前面的2位(ad)拿来建一个目录, 那么缓存文件的路径就是/data/nginx/cache/9/ad/e0bd86606797639426a92306b1b98ad9

以此类推:levels=1:1:2表示建立3级目录,把hash最后1位(9)拿出建一个目录,然后再把9前面的1位(d)建一个目录, 最后把d前面的2位(8a)拿出来建一个目录 那么缓存文件的路径就是/data/nginx/cache/9/d/8a/e0bd86606797639426a92306b1b98ad9

  • keys_zone 所有活动的key和元数据存储在共享的内存池中,这个区域用keys_zone参数指定。zone_name指的是共享池的名称,zone_size指的是共享池的大小。注意每一个定义的内存池必须是不重复的路径,例如:

    1
    2
    3
    proxy_cache_path /data/nginx/cache/one levels=1 keys_zone=one:10m;
    proxy_cache_path /data/nginx/cache/two levels=2:2 keys_zone=two:100m;
    proxy_cache_path /data/nginx/cache/three levels=1:1:2 keys_zone=three:1000m;
  • inactive 表示指定的时间内缓存的数据没有被请求则被删除,默认inactive为10分钟。inactive=1d 1小时。inactive=30m 30分钟。

  • max_size 表示单个文件最大不超过的大小。它被用来删除不活动的缓存和控制缓存大小,当目前缓存的值超出max_size指定的值之后,超过其大小后最少使用数据(LRU替换算法)将被删除。max_size=10g表示当缓存池超过10g就会清除不常用的缓存文件。

  • clean_time 表示每间隔自动清除的时间。clean_time=1m 1分钟清除一次缓存。
    好。说完了这个很重要的参数。我们再来说在server模块里的几个配置参数:

  • proxy_cache 用来指定用哪个keys_zone的名字,也就是用哪个目录下的缓存。上面我们指定了三个one, two,three 。比如,我现在想用one 这个缓存目录 : proxy_cache one

  • proxy_cache_key 这个其实蛮重要的,它用来指定生成hash的url地址的格式。根据这个key映射成一个hash值,然后存入到本地文件。proxy_cache_key $host$uri表示无论后面跟的什么参数,都会访问一个文件,不会再生成新的文件。 而如果proxy_cache_key $is_args$args,那么传入的参数 localhost/index.php?a=4 与localhost/index.php?a=44 将映射成两个不同hash值的文件。

proxy_cache_key 默认是 "$scheme$host$request_uri"。但是一般我们会把它设置成:$host$uri$is_args$args 一个完整的url路径。

  • proxy_cache_valid

它是用来为不同的http响应状态码设置不同的缓存时间。
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
表示为http status code 为200和302的设置缓存时间为10分钟,404代码缓存1分钟。 如果只定义时间:

proxy_cache_valid 5m;
那么只对代码为200, 301和302的code进行缓存。 同样可以使用any参数任何相响应:

proxy_cache_valid 200 302 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid any 1m; #所有的状态都缓存1小时
好。缓存的基本一些配置讲完了。也大致知道了怎么使用这些参数。现在开始实战!我们启动一台vagrant linux 机器 web1 (192.168.33.11) 用作远程代理机器,就不搞复杂的负载均衡了。

先在Mac本地加一个域名cache.iyangyi.com, 然后按照上面的配置在vhost 下新建一个proxy_cache.iyangyi.conf 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
proxy_cache_path /usr/local/var/cache levels=1:2 keys_zone=cache_zone:10m inactive=1d max_size=100m;
server {
listen 80;
server_name cache.iyangyi.com;
access_log /usr/local/var/log/nginx/cache.iyangyi.access.log main;
error_log /usr/local/var/log/nginx/cache.iyangyi.error.log error;
add_header X-Via $server_addr;
add_header X-Cache $upstream_cache_status;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_cache cache_zone;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 1m;
proxy_pass http://192.168.33.11;
}
}

打开审核元素或者firebug。看network网络请求选项,我们可以看到,Response Headers,在这里我们可以看到:

1
2
X-Cache:MISS
X-Via:127.0.0.1

X-cache 为 MISS 表示未命中,请求被传送到后端。因为是第一次访问,没有缓存,所以肯定是未命中。我们再刷新下,就发现其变成了HIT, 表示命中。它还有其他几种状态:

  • MISS 未命中,请求被传送到后端
  • HIT 缓存命中
  • EXPIRED 缓存已经过期请求被传送到后端
  • UPDATING 正在更新缓存,将使用旧的应答
  • STALE 后端将得到过期的应答
  • BYPASS 缓存被绕过了

我们再去看看缓存文件夹 /usr/local/var/cache里面是否有了文件:

1
2
ls
/usr/local/var/cache/a/13

我们在url 后面随便加一个什么参数,看会不会新生成一个缓存文件夹及文件:http://cache.iyangyi.com/?w=ww55 。因为我们使用的生成规则是全部url转换(proxy_cache_key $host$uri$is_args$args;)

location 正则模块

这一小节,主要来学习nginx中的URL重写怎么做。url重写模块,主要是在location模块面来实现,我们一点一点的看。

首先看下location 正则匹配的使用。还记得之前是如何用location来定位.php文件的吗?

1
2
3
4
5
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}

我们用~来表示location开启正则匹配, 这样:location ~。还可以用这个来匹配静态资源,缓存它们,设置过期时间:

1
2
3
4
5
6
location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|mp3|mp4|swf){
expires 15d;
}
location ~ .*\.(css|js){
expires 12h;
}

location

  • =
  • ~ 正则区分大小写
  • ~* 正则不区分大小写
  • ^~ 找到匹配就处理

expires 用来设置HTTP应答中的Expires和Cache-Control的头标时间,来告诉浏览器访问这个静态文件时,不用再去请求服务器,直接从本地缓存读取就可以了。
语法: expires [time|epoch|max|off]
默认值: expires off
作用域: http, server, location
可以在time值中使用正数或负数。“Expires”头标的值将通过当前系统时间加上您设定的 time 值来获得。可以设置的参数如下:

epoch 指定“Expires”的值为 1 January, 1970, 00:00:01 GMT。

max 指定“Expires”的值为 31 December 2037 23:59:59 GMT,“Cache-Control”的值为10年。

-1 指定“Expires”的值为 服务器当前时间 -1s,即永远过期。

负数:Cache-Control: no-cache。

正数或零:Cache-Control: max-age = #, # 会转换为指定时间的秒数。比如:1d、2h、3m。

off 表示不修改“Expires”和“Cache-Control”的值。
比如再看个例子: 控制图片等过期时间为30天

location ~ .(gif|jpg|jpeg|png|bmp|ico)$ {
expires 30d;
}
我们还可以控制哪一个文件目录的时间,比如控制匹配/resource/或者/mediatorModule/里所有的文件缓存设置到最长时间。

location ~ /(resource|mediatorModule)/ {
root /opt/demo;
expires max;
}

URL重写模块

重写模块与很多模块一起使用。先看一下是怎么用的,看2个例子,然后我们再一点一点讲每个的使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location /download/ {
if ($forbidden) {
return 403;
}
if ($slow) {
limit_rate 10k;
}
rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;
......
}
location / {
root html;
index index.html index.htm;
rewrite ^/bbs/(.*)$ http://192.168.18.201/forum/$1;
}

上面2个例子就是利用rewrite来完成URL重写的。我们慢慢来看它的用法。

break

break和编程语言中的用法一样,就是跳出某个逻辑。

使用字段:server, location, if
if (!-f $request_filename) {
break;
}
上面这个例子就是在if里面使用break,意思是如果访问的文件名不存在,就跳出。后续会有更多的例子。

if

if 判断一个条件,如果条件成立,则后面的大括号内的语句将执行,相关配置从上级继承。

使用字段:server, location
可以在判断语句中指定下列值:

一个变量的名称;不成立的值为:空字符传”“或者一些用“0”开始的字符串。

一个使用=或者!=运算符的比较语句。

使用符号~*和~模式匹配的正则表达式:

~为区分大小写的匹配。

~*不区分大小写的匹配(firefox匹配FireFox)。

!~和!~*意为“不匹配的”。

使用-f和!-f检查一个文件是否存在。

使用-d和!-d检查一个目录是否存在。

使用-e和!-e检查一个文件,目录或者软链接是否存在。

使用-x和!-x检查一个文件是否为可执行文件。
$http_user_agent变量获取浏览器的agent,使用~ 来匹配大小写。用户如果使用的IE 浏览器,就执行if里面的操作。

if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
$request_method变量获取请求的方法,使用=来判断是否等于POST 。如果复合,就执行if 里面的操作。

1
2
3
if ($request_method = POST ) {
return 405;
}

$request_filename变量获取请求的文件名,使用!-f来匹配文件,如果不是一个文件名,就执行if 里面的逻辑。

1
2
3
4
if (!-f $request_filename) {
break;
proxy_pass http://127.0.0.1;
}

return

这个指令结束执行配置语句并为客户端返回状态代码,可以使用下列的值:204,400,402-406,408,410, 411, 413, 416与500-504。此外,非标准代码444将关闭连接并且不发送任何的头部。

语法:return code

默认值:none

使用字段:server, location, if

rewrite

语法:rewrite regex replacement flag

默认值:none

使用字段:server, location, if
rewrite用来重写url,有3个位置:

regex 表示用来匹配的正则

replacement 表示用来替换的

flag 是尾部的标记
flag可以是以下的值:

last - url重写后,马上发起一个新的请求,再次进入server块,重试location匹配,超过10次匹配不到报500错误,地址栏url不变

break - url重写后,直接使用当前资源,不再执行location里余下的语句,完成本次请求,地址栏url不变

redirect - 返回302临时重定向,url会跳转,爬虫不会更新url。

permanent - 返回301永久重定向。url会跳转。爬虫会更新url。

为空 - URL 不会变,但是内容已经变化,也是永久性的重定向。
上面的正则表达式的一部分可以用圆括号,方便之后按照顺序用$1-$9来引用。

我们来看几个例子:

需要将/photos/123456重写成/path/to/photos/12/1234/123456.png
可以这样:

rewrite “/photos/([0-9] {2})([0-9] {2})([0-9] {2})” /path/to/photos/$1/$1$2/$1$2$3.png;
下面是一些简单的常见的重写:

rewrite ^/js/base.core.v3.js /js/base.core.v3.dev.js redirect;
rewrite ^/js/comment.frame.js /js/comment.frame.dev.js redirect;
rewrite ^/live-static/(.*)$ http://live.bilibili.com/public/$1 last;

配置整理

在此记录下Nginx服务器nginx.conf的配置文件说明, 部分注释收集与网络:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# 运行用户
user www-data;
# 启动进程,通常设置成和cpu的数量相等
worker_processes 1;
# 全局错误日志及PID文件
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
# 工作模式及连接数上限
events {
use epoll; #epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能
worker_connections 1024; #单个后台worker process进程的最大并发链接数
# multi_accept on;
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
#设定mime类型,类型由mime.type文件定义
include /etc/nginx/mime.types;
default_type application/octet-stream;
#设定日志格式
access_log /var/log/nginx/access.log;
#sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,
#必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.
sendfile on;
#将tcp_nopush和tcp_nodelay两个指令设置为on用于防止网络阻塞
tcp_nopush on;
tcp_nodelay on;
#连接超时时间
keepalive_timeout 65;
#开启gzip压缩
gzip on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
#设定请求缓冲
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
#设定负载均衡的服务器列表
upstream mysvr {
#weigth参数表示权值,权值越高被分配到的几率越大
#本机上的Squid开启3128端口
server 192.168.8.1:3128 weight=5;
server 192.168.8.2:80 weight=1;
server 192.168.8.3:80 weight=6;
}
server {
#侦听80端口
listen 80;
#定义使用www.xx.com访问
server_name www.xx.com;
#设定本虚拟主机的访问日志
access_log logs/www.xx.com.access.log main;
#默认请求
location / {
root /root; #定义服务器的默认网站根目录位置
index index.php index.html index.htm; #定义首页索引文件的名称
fastcgi_pass www.xx.com;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
# 定义错误提示页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /root;
}
#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/virtual/htdocs;
#过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
expires 30d;
}
#PHP 脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
location ~ \.php$ {
root /root;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/www$fastcgi_script_name;
include fastcgi_params;
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
}
#禁止访问 .htxxx 文件
location ~ /\.ht {
deny all;
}
}
#第一个虚拟服务器
server {
#侦听192.168.8.x的80端口
listen 80;
server_name 192.168.8.x;
#对aspx后缀的进行负载均衡请求
location ~ .*\.aspx$ {
root /root;#定义服务器的默认网站根目录位置
index index.php index.html index.htm;#定义首页索引文件的名称
proxy_pass http://mysvr;#请求转向mysvr 定义的服务器列表
#以下是一些反向代理的配置可删除.
proxy_redirect off;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m; #允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k; #设定缓存文件夹大小,大于这个值,将从upstream服务器传
}
}
}

系统优化

修改系统最多打开文件数

打开/etc/security/limits.conf,里面有很详细的注释,找到如下设置(如果没有就插入)

  • soft nofile 51200
  • hard nofile 51200

网络以及TCP优化

每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.core.netdev_max_backlog = 862144
web 应用中listen 函数的backlog 默认会给我们内核参数的net.core.somaxconn 限制到128,而nginx 定义的NGX_LISTEN_BACKLOG 默认为511,所以有必要调整这个值。
net.core.somaxconn = 262144

系统中最多有多少个TCP 套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。
这个限制仅仅是为了防止简单的DoS 攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个

net.ipv4.tcp_max_orphans = 327680
表示SYN队列的长度,默认为1024,加大队列长度为10200000,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_syn_backlog = 1020000
时间戳可以避免序列号的卷绕。一个1Gbps 的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。
net.ipv4.tcp_timestamps = 0
为了打开对端的连接,内核需要发送一个SYN 并附带一个回应前面一个SYN 的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK 包的数量。

net.ipv4.tcp_synack_retries = 1
在内核放弃建立连接之前发送SYN 包的数量。
net.ipv4.tcp_syn_retries = 1

参考
http://freeloda.blog.51cto.com/2033581/1288553
http://www.jianshu.com/p/558455228c43