Nginx [ engine x] 是一款HTTP请求服务器反向代理服务器,它还是邮件代理服务器和一个通用的TCP/UDP代理服务器。它是有俄罗斯人Igor Sysoev开发。

Nginx主要用于Web服务、反向代理或负载均衡服务、前端业务数据缓存服务。

特点

Nginx模块化架构,以事件驱动的方式编写,拥有非常好的性能,同时也是个非常高效的反向代理、负载均衡服务器。

基础的HTTP服务特点:

  1. 提供静态和索引文件自动索引文件缓存
  2. [反向代理]加速(https://nginx.org/en/docs/http/ngx_http_proxy_module.html)及数据缓存。
  3. 负载均衡和容错
  4. 支持高速缓存FastCGIuwsgiSCGImemcached
  5. 支持SSLTLS、 SNI。
  6. 支持HTTP/2
  7. 支持 3xx-5xxHTTP状态码重定向
  8. 支持rewrite模块,支持URI重写及正则表达式匹配。
  9. 支持基于客户端IP地址和HTTP基本认证访问控制。
  10. 支持同一IP地址的并发连接和请求数限制。

Nginx采用一个主(master)进程和多个工作(worker)进程架构模式。


master进程用于管理worker进程。当worker进程退出或异常,会自动重启新的worker进程。

因为这个架构Nginx可以不中断服务的进行重启和升级。
支持高并发,资源消耗小,可以做HTTP反向代理及加速缓存,Nginx已经成为现在服务器首选。

安装

Nginx 支持windows 和 Linux平台。
linux安装Nginx之前需要安装它的依赖包:

1
2
$ yum install pcre pcre-devel -y
$ rpm -qa pcre pcre-devel

pcre 全称perl compatible regular expressions(perl兼容正则表达式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ yum install -y openssl openssl-devel
$ rpm -qa openssl openssl-devel
$ wget -q https://nginx.org/download/nginx-1.12.2.tar.gz
$ tar -xf nginx-1.12.2.tar.gz
$ cd nginx-1.12.2
$ ./configure \
--prefix=/application/nginx-1.12.2 \
--sbin-path=/usr/sbin/nginx \
--conf-path=/application/nginx-1.12.2/nginx.conf \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-pcre \
--with-file-aio \
--with-http_realip_module \
$ make
$ make install
$ ln -s /application/nginx-1.12.2 /application/nginx

Nginx配置有几十个选项。--with-xx-xx表示默认是不启用的,在配置时加入表示启用。--without-xx-xx默认是启用的配置,在配置时加上表示禁止启用。
·
创建 service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

文件名为ngxin.service, 存放路径:/usr/lib/systemd/system/nginx.service
执行下面命令将nginx 启动并添加到开机启动:

1
2
3
$ sudo systemctl daemon-reload
$ sudo systemctl start nginx.service
$ sudo systemctl enable nginx.service

命令

重新加载配置文件,你可以停止或重启NGINX,或者发信号给主进程。
一个信号可以通过nginx命令行发送(调用NGINX可执行文件)使用 -s 作为参数:

1
nginx -s signal

这个signal值可以是下面这些:

  • quit – 温和停止
  • reload – 重新加载配置文件
  • reopen – 打开日志文件
  • stop – 立刻停止

你也可以通过kill命令给主进程发送信号。进程ID是被写进nginx.pid 文件中。默认地址/usr/local/nginx/logs或者/var/run目录中。

配置文件

NGINX是有个个模块组成,每个模块实现特定的功能。将这些模块组织在一起就是通过配置文件。NGINX默认配置文件文件名为 nginx.conf

配置文件有指令和它们的参数组成。简单的指令是单行组成,以分号结尾。而有些指令是有多个相关联的指令组成,它们用{}包裹起来。

模块功能的实现就是在配置文件给它们提供的指令赋值。

指令还可以写在单独的文件中通过include命令引入主配置文件中。推荐将不同的指令写入不同的文件中,这样便已管理和扩展。

1
2
3
inclued conf.d/http;
include conf.d/stream;
inclued conf.d/exchange-enhanced;

指令上下文

nginx.conf指令根据其通途是有上下文关系和作用域。
顶级指令包含各种指令用来实现功能,顶级指令有:

  • events - 处理连接指令
  • http - http协议模块
  • mail - 邮件模块
  • stream - TCP模块

一些Nginx服务配置的指令不属于这些顶级指令,和它们同级写在main 上下文。

main上下文包含指令:

  • user - 使用用户名
  • worker_processes - work进程数,默认是CPU核数
  • error_log - 错误日志位置
  • events
  • http
  • mail

http上下文中包含的指令有:

  • server - 一个域名或IP请求处理方式
  • sendfile - 开启快速传输
  • mail上下文包含指令有:
  • server - 一个邮件服务
  • auth_http
  • imap_capabilities

server上下文包含指令:

  • listen - 监听端口
  • server_name - 服务域名
  • access_log 交互日志存放地址
  • location - 同个域名或IP不同地址处理配置
  • proxy
  • protocol
  • smtp_auth
  • xclient

location上下文包含指令:

  • index
  • root

配置文件结构如下:

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
user  nobody; 
worker_processes 1;
error_log logs/error.log info;

events {
worker_connections 1024;
}

http {
server {
listen 80;
server_name www.linuxidc.com;
access_log logs/linuxidc.access.log main;
location / {
index index.html;
root /var/www/linuxidc.com/htdocs;
}
}

server {
listen 80;
server_name www.Androidj.com;
access_log logs/androidj.access.log main;
location / {
index index.html;
root /var/www/androidj.com/htdocs;
}
}
}

mail {
auth_http 127.0.0.1:80/auth.php;
pop3_capabilities "TOP" "USER";
imap_capabilities "IMAP4rev1" "UIDPLUS";

server {
listen 110;
protocol pop3;
proxy on;
}
server {
listen 25;
protocol smtp;
proxy on;
smtp_auth login plain;
xclient off;
}
}

gzip

http中常用的优化手段就是使用gzip压缩返回值。但是因为压缩是发生在运行时,所以它会带来很大的处理开销影响性能上面的影响。

ngx_http_gzip_module

NGINX gzip功能是通过ngx_http_gzip_module实现。

gzip;

是否开启 gzip 压缩。

  • 格式: gizp on|off;
  • 默认: off
  • 上下文:http、server、location

gizp_buffers

设置压缩返回值的缓存数量和大小。当gzip去压缩返回值时,需要从系统申请内存用于缓存压缩后的值。
number表示申请内存数量,size代表大小。

  • 格式:gizp_buffers number size;
  • 默认: 32 4K | 16 8K gzip默认申请原文件大小的内存,4K 还是 8K大小取决于系统。
  • 上下文:http、server、location

gzip_comp_level

压缩等级(1-9)。1 压缩最快,9压缩慢但压缩比大。

  • 格式:gzip_comp_level level;
  • 默认:gzip_comp_level 1;
  • 上下文:http、server、location

gzip_disable

如果请求User-Agent匹配设定的字段,就不进行压缩。一般用于针对不支持gzip浏览器设定。

  • 格式:gzip+disable regex….
  • 默认值:无
  • 上下文:http、server、location

gzip_min_length

设定压缩最小长度的返回值,这个长度从Content-Length字段读取。有些太小的文件无需压缩。

  • 格式: gzip_min_length length;
  • 默认值: gzip_min_length 20;
  • 上下文:http、server、location

gzip_http_version

设定压缩最低HTTP版本。

  • 格式:gzip_http_version 1.0 | 1.1
  • 默认值:1.1
  • 上下文: http、server、location

gzip_proxied

Nginx作为反向代理的时候启用或关闭gzip。如果启动则在请求和返回值中包含指定的字段。
此指令可以包含多个参数。

  • 格式: gzip_proxied off off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth

    • off - 禁止压缩,忽略其它参数
    • expired - 启用压缩,如果header头中包含 “Expires” 头信息
    • no-cache - 启用压缩,如果header头中包含 “Cache-Control:no-cache” 头信息
    • no-store - 启用压缩,如果header头中包含 “Cache-Control:no-store” 头信息
    • private - 启用压缩,如果header头中包含 “Cache-Control:private” 头信息
    • no_last_modified - 启用压缩,如果header头中不包含 “Last-Modified” 头信息
    • no_etag - 启用压缩 ,如果header头中不包含 “ETag” 头信息
    • auth - 启用压缩 , 如果header头中包含 “Authorization” 头信息
    • any - 无条件启用压缩
  • 默认:gzip_proxied off

  • 上下文: http、server、location

gzip_types

匹配MIME类型进行压缩。’*’匹配任意MIME type

  • 格式:gzip_types mime-type … | * (0.8.29)
  • 默认值: gzip_types text/html
  • 上下文:http、server、location

gzip_vary

gzipgzip_staticgunzip指令被激活,是否向头部插入Vary:Accept-Encoding

  • 格式:gzip_vary on|off
  • 默认:gzip_vary off;
  • 上下文:http、server、location

ngx_http_gzip_static_module

如果传输文件时,是可以进行预压缩将原文件压缩为.gz结尾。这需要使用模块ngx_http_gzip_static_module

此模块不是默认模块需要在配置编译时做参数--with-http_gzip_static_module传入。

gzip_static

是否启动文件压缩

  • 格式:gzip_static on | off | always(1.3.6)
  • 默认值:gzip_static off;
  • 上下文:http、server、location

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
http {
gzip on;
gzip_disable "msie6";

gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types *;
server {
location ~ ^/assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
}
}

虚拟服务器

通过Nginx虚拟服务器,一台物理服务器可以同时开启多个服务。
Nginx虚拟服务有三种配置方式:

  • 域名 根据域名来跟踪服务
  • 端口 同一域名不同端口跟踪服务
  • IP地址+端口 通过IP地址和端口跟踪服务

Nginx服务定义在http指令中,具体的服务请求处理方式是在server指令中定义。
一个http上下文中可以定义多个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
worker_processes 1;
events {
worker_connections 1024; #最大连接数
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80; # 定义监听的IP和端口
server_name www.example.com; # 定义域名
location / {
root html/www;
index index.html index.htm index.php;
}
}
server {
listen 82;
server_name www.example.com;
location / {
root html/admin;
index index.html index.htm index.php;
}
}
server {
listen 10.0.0.8:83;
server_name www.example.com;
location / {
root html/www;
index index.html index.htm index.php;
}
}
}

server最主要三个指令是listenserver_namelocation

location

location指令用于匹配uri进行的处理。一个server可以设置多个location用于处理不同的uri。

  • 格式: location [=||*|^~] uri {}
  • 上下文:server、location
    location指令有两种参数形式:前缀字符串或正则表达式。如果某个请求的URI以某个前缀字符串开始,则与改location匹配。例如:
    1
    2
    3
    location /some/path/ {
    ....
    }
    上面location前缀字符串将匹配以/some/path/开头的请求URI,例如 /some/path/document.html 但它并不匹配 /my-site/some/path

如果用正则表达式定义 ~* 表示忽略大小写,____ 表示不忽略大小写,__^\__ 表示前缀字符串匹配后不做在做这条正则表达式匹配。

1
2
3
location ~ \.html? {
...
}

上面lcation是不忽略大小写的正则表达式,它将匹配到URI包含__.html__或__.htm__的请求。

NGINX首先会将URI于location的前缀字符串进行匹配,然后在于正则表达式匹配。正则表达式拥有优先级,除非前缀字符串用__^~__修饰。
在匹配的前缀字符串中,NGINX选择其中最长及完整的前缀字符串所对应的location。

常用正则表达式:

  • ~ 匹配区分大小写
1
2
3
location ~ /js/ {
//如果是JS大写的是不会匹配到的
}
  • ~ 匹配不区分大小写
1
2
3
location ~* /js/ {
//JS大写或者小写都可以匹配到
}
  • ^ 匹配字符串的开始标识
  • $ 匹配字符串的结束标识
  • . 点符号匹配除换行符以外的任意字符
  • * 重复零次或更多次 + 重复一次或更多次 ? 重复零次或一次
  • ^~ 注意: Nginx将在这个字符串匹配后停止进行正则表达式的匹配(location指令中正则表达式的匹配的结果优先使用) ,一般这种情况用来匹配目录
1
2
3
4
5
6
location ^~ /img/ {
// 这个则匹配的目录, 当匹配到此规则即可终止往下匹配
}
location ~* \.(gif|jpg|jpeg)${
// 这个规则则是访问的具体的文件 , 如xxxx.jpg等
}
  • =精确匹配
1
2
3
4
5
6
location = / {
// 指定某一个规则进行精确的匹配 ,只能匹配" / "
}
location / {
// 这个进行全部匹配
}
  • @定义一个命名的 location,使用在内部定向时使用
1
2
3
4
5
6
// 例如出现异常400等 ,可以直接跳转到 单独定义的异常处理的location
error_page 404 = @fetch;

location @fetch(
proxy_pass http://fetch;
)
  • [^x] 匹配除了x以外的任意字符 , [^abcde] 匹配除了abcde这几个字母以外的任意字符

    [/] 这个匹配所有的

查找location过程:

  1. 将URI与所有前缀字符串进行比较
  2. 修饰符 = 表示与前缀字符串必须精确匹配。如果能够精确匹配,则结束查找。
  3. 如果在匹配的最长的前缀字符串前添加了^~修饰符,则不会再检查正则表达式。
  4. 保存匹配的最长的前缀字符串。
  5. 测试URI和正则表达式的匹配情况。
  6. ^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。
    最后匹配理带有””和”*”的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。

root

为require请求设置root目录。例如:

1
2
3
location /i/ {
root /data/w3;
}

这个 /data/w3/i/top.gif 会作为 /i/top.gif 请求的返回值。

变量

nginx.conf 配置文件可以使用变量。变量的值在运行时进行计算。可作为指令的参数使用。
变量用 __$__符号开头。
许多变量时 core HTTP 定义好了。你也可以通过 set mapgeo指令进行变量自定义

返回指定状态码

一些requireURIs需要立即返回状态码或重定向。这时就可以通过return指令来完成。例如:

1
2
3
4
5
6
location /wrong/url {
return 404;
}
location /permanently/moved/url {
return 301 http://www.example.com/moved/here;
}

return

停止处理返回指定的状态给客户端。

  • 格式:
    • return code [text];
    • return code URL;
    • return URL;
  • 上下文:server、location、if

return 第一个参数时响应码,第二个参数是可选的,可以是重定向的URL(301,302,303和307),或者是放入body的一段文本。

URI重写

通过使用rewrite指令,可以一个requireURI能够被编辑多次在一次请求过程中。

  • 格式:rewrite regex replacement [tag]
  • 上下文:server、location、if

rewrite指令使用需要至少接收两个参数,第一个参数是匹配URI中字符串的正则表达式,第二个参数是代替匹配到的URI字符串。第三个参数是可选的,用于终止进一步的rewrite操作,或者发送重定向(301或302)给客户端。例如:

1
2
3
location /users/ {
rewrite ^/users/(.*)$ /show?user=$1 break;
}

tag 值有这些:

  • last - 不在执行后面rewrite指令,立即匹配新地址的location,如果匹配到的location有rewrite指令可以继续处理。
  • break - 不在执行后面rewrite指令,立即匹配新地址的location,如果匹配到的location有rewrite指令可也不再处理。
  • redirect - 返回302临时重定向,浏览器地址栏会显示跳转后的URL地址。如果替换的不是http://https://$scheme开始。
  • permanent - 返回一个永久的301重定向,浏览器地址栏会显示跳转后的URL地址。

处理错误

通过error_page指令,你可以配置NGINX给错误状态码返回定制页,或替换返回值中的错误码,或发送重定向指令给浏览器,指向不同的URl地。

  • 格式: error_page code …[=[response]] uri
  • 上下文: http、server、location、if in location
1
error_page 404 /404.html

上面例子中,error_page 指令指定了/404.html页面和404状态码一起返回给客户端。
要注意的是,这个指令不是立即返回该错误给客户端(这是 return 指令做的事),这只是定义了如果处理该错误。该 error code 可来自于一个后端服务器,或者在 nginx 做一些处理时出现(例如,当 nginx 不能找到请求的文件时,将返回 404 错误)。

1
2
3
location /old/path.html {
error_page 404 =301 http:/example.com/new/path.html;
}

error_page 可以改变来有错误状态码,上面例子中,code 404替换成code 301并返回一个重定向地址给客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
...
location /images/ {
# Set the root directory to search for the file
root /data/www;

# Disable logging of errors related to file existence
open_file_cache_errors off;

# Make an internal redirect if the file is not found
error_page 404 = /fetch$uri;
}

location /fetch/ {
proxy_pass http://backend/;
}
}

上面代码中,如果在 __/image/some/file__没有找到,它会替换成 /fetch/images/some/file 这个新URI,NGNIX会查找新URI匹配的location。

反向代理

用户A访问服务器B,服务B根据请求的地址设置的location将请求转发给服务器C。
服务C接收到请求后,将响应返回给服务器B,服务器B最后将响应发送给用户A。
从用户A来看,他请求的是服务器B,但实际上处理他请求的是服务C。这就是反向代理。发起者不知道实际处理他请求的是谁。

Nginx除了支持HTTP代理外,还支持FastCGIuwsgiSCGImemcached。这里只讲HTTP代理配置。

proxy_pass

proxy_pass指令定义再location中,指定需要代理的HTTP服务器。

  • 格式:proxy_pass URL;
  • 上下文:location、if in location,limit_except

URL包含代理服务器协议和地址,也可包含端口号。如果包含有URI,这location匹配的URI会被代理URI替换掉。例如:

1
2
3
location /some/path/ {
proxy_pass http://www.example.com/link/;
}

请求的URI为: /some/path/pag.html ,它与location匹配部分为 /some/paht ,这部分会被 __/link/ 替换掉。因此转发给代理服务器地址是: http://www.example.com/link/page.html

如果proxy_pass没有指定URI,请求URI将以原始请求处理时的客户端发送的相同形式传递给服务器,如果有修改则将修改后的URI传给服务器。

下面情况下,不确定被替换的请求URI是那部分:

  1. 当location被正则表达式指定,并在location内部时。这种情况下prox_pass不应该指定URI。
  2. 当URI在location内部被rewrite修改,这是rewrite应该用 break标记处理。
  3. proxy_pass上有变量时,则用指令指定的URI替换原来的URI。

proxy_http_version

指定代理请求的HTTP协议。

  • 格式: proxy_http_version 1.0 | 1.1
  • 默认值: proxy_http_version 1.0
  • 上下文:http, server,location

如果默认值设为1.1,需要和keepalive一起使用。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream http_backend {
server 127.0.0.1:8080;

keepalive 16;
}

server {
...

location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}

proxy_set_header

允许重新定义或添加发往后端服务器的请求头。

  • 格式: proxy_set_header field value;
  • 默认值:
    • proxy_set_header Host $proxy_host;
    • proxy_set_header Connection close;
  • 上下文:http、server、location

对于请求转发,Nginx默认会修改头部两个字段: HostConnection
Host 字段会被设置为 $proxy_host (后端服务器地址和端口)变量值。 Connection 字段会被设置为 close。
如果某个字段值被设为空字符串,该字段将被删除。

如果你不想修改 Host 值,可以这么设置:

1
proxy_set_header Host       $http_host;

但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。 这种情况下,更好的方式是使用$host变量——它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名

1
proxy_set_header Host       $host;

proxy_buffers

nginx 从后端服务器获得响应后,默认会将其缓存起来。响应报文被存储在内部缓存中,直到客户端接收完整个报文。使用缓存可以提高 nginx 的代理性能。当遇到某些客户端接收数据的速度较慢时,如果 nginx 将响应报文同步的转发给客户端,这会浪费 nginx 的时间。而启用缓存之后,nginx 可更快速的处理来自后端服务器的响应报文。等客户端接收完成,nginx 就可以删除缓存的响应报文。

proxy_buffers,为每个链接设置缓存数量和大小。

  • 格式: proxy_buffers number size;
  • 默认值: proxy_buffers 8 4k|8k
  • 上下文:http、server、lcoation

为每个连接设置缓冲区的数量为number,每块缓冲区的大小为size。这些缓冲区用于保存从被代理的服务器读取的响应。每块缓冲区默认等于一个内存页的大小。这个值是4K还是8K,取决于平台。

proxy_buffer_size

指令负责设置接收第一部分响应报文的缓存的大小。

  • 格式:proxy_buffer_size size;
  • 默认值: proxy_buffer 4k|8k;
  • 上下文:http、server、location

设置缓冲区的大小为size。nginx从被代理的服务器读取响应时,使用该缓冲区保存响应的开始部分。这部分通常包含着一个小小的响应头。该缓冲区大小默认等于proxy_buffers指令设置的一块缓冲区的大小,但它也可以被设置得更小。

负载均衡

当访问量很大一台机器已经无法支持,我们可以部署多台机器做支持。用户的请求被那台服务器由NGINX来分配。这个分配请求到后面服务器的技术就是负载均衡。和反向代理类式。

upstream

一组服务器定义在 upstream指令大括号中。服务器可以监听不同的端口。而且,监听在TCP和UNIX域套接字的服务器可以混用。

  • 格式: upstream name {…}
  • 上下文:http

例子:

1
2
3
4
5
6
7
8
9
10
11
12
http {
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
server 192.0.0.1 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
}

上面代码所示,upstream中定义了一组服务器,当有请求被定义在server中的location匹配到时会被代理proxy_pass指令中声明的upstream名字,转向 定义好的upstream中。

server

定义服务器地址(address)和其它参数(parameters)。

  • 格式: server address [parameters]
  • 上下文:upstream

地址可以时域名或IP地址,端口是可选的。或者指定”unix:”前缀的UNIX域套接字的路径。
参数有如下:

  • weight=number 设定服务器的权重。默认是1。权重越高被分配的概率越大
  • max_fails=number 设定NGINX与服务器通信失败尝试的次数。在fail_timeout参数定义的时间段内,如果失败次数达到此值,NGINX会认为此服务器不可用。在下一个fail_timeout时间段,服务器不会再被尝试。失败的尝试次数默认值是1。设为0就会停止统计尝试次数,认为服务器一直可用。
  • faile_timeout=time (10s)
    • 统计失败尝试次数的时间段。这个时间段中,服务器失败次数达到指定的尝试次数,服务器就被认为不可用。
    • 服务器被认为不可用的时间段。
  • backup 标记服务器为备用。当主服务器不可用后,请求才会被传给这些服务器。
  • down 标记服务器不永久不可用,可以个ip_hash一起使用。

例子:

1
2
3
4
5
6
7
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;

server backup1.example.com:8080 backup;
}

ip_hash

指定服务器组的负载均衡方法,请求基于客户端的IP地址在服务器间进行分发。

  • 格式:ip_hash
  • 上下文: upstream

IPv4地址的前三个字节或者IPv6的整个地址,会被用来作为一个散列key。 这种方法可以确保从同一个客户端过来的请求,会被传给同一台服务器。除了当服务器被认为不可用的时候,这些客户端的请求会被传给其他服务器,而且很有可能也是同一台服务器。
很多时候我们需要一个客户只访问一个服务器,那么就需要用ip_hash了,ip_hash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。

1
2
3
4
5
upstream test {
ip_hash;
server localhost:8080;
server localhost:8081;
}

least_conn

指定服务器组负载均衡的方法,根据其权重值,将请求发送给活跃连接数量最少的那台服务器。如果这样的服务器有多台,那就采取权重的轮询方法进行尝试。

  • 格式: least_conn;
  • 上下文:upstream;

least_time

指定服务器负载均衡的方法,其中请求被传递给服务器的平均响应时间最少,活动连接数最少,同时考虑到服务器的权重。如果这样服务器有多台,就采取权重轮询的方法进行尝试。

  • 格式: least_time header | last_byte [inflight];
  • 上下文:upstream
  • 本版:1.7.10

hash

指定服务器负载均衡的方法。根据提供的key值进行客户端和服务器映射产生联系。

  • 格式:hash key [consistent];
  • 默认值:upstream
  • 版本:1.7.2

key 值可以是文本也可以是变量。

1
2
3
4
5
6
upstream backend { 
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}

静态内容服务

作为一个WEB服务器,NGINX有个很重要任务是将静态文件发送给客户端。而静态文件的路径,和性能优化是基础。

root

为请求设置根目录。

  • 格式:root path;
  • 默认值 root html;
  • 上下文:http、server、location、if in location。
1
2
3
location /i/ {
root /data/w3;
}

上面的代码,如果请求路径是 /i/top.gif 则NGINX查找文件路径将是 /data/w3/i/top.gif

try_file

try_files 指令用于检测指定的文件或目录是否存在,如果不存在,就做内部重定向,或者返回指定的状态码。

  • 格式:
    • try_files file … uri;
    • try_files file … =code;
  • 上下文:server、location
1
2
3
4
5
6
server {
root /www/data;
location /images/ {
try_files $uri /images/default.gif;
}
}

上面代码,如果请求URI是 /images/top.gif 而这个文件不存在, try_files指令会将原来的URI重定向到 /images/default.gif 。NGINX进行重新路径匹配,最后返回 __/www/data/images/default.gif__文件。

try_files 指令最后参数可以是一个状态码或一个 locationde 名字。

1
2
3
location / {
try_files $uri $uri/ $uri.html =404;
}

上面例子中,如果 try_files指令的所有参数都没解析一个存在的文件或目录那么就返回404错误。

1
2
3
4
5
6
location / {
try_files $uri $uri/ @backend;
}
location @backend {
proxy_pass http://backend.example.com;
}

上面代码,如果原始URI,以及URI/不能解析为一个存在的文件或目录,该请求将被重定向到一个命名的 location,该location将请求转发给后端服务器。

autoindex

是否将文件列出。

  • 格式: autoindex on|off
  • 默认值:autoindex off;
  • 上下文:http、server、location

sendfile

默认情况下,NGINX再进行文件发送前会将文件拷贝进缓存。通过开启sendfile,可以取消这一步。而是直接将文件拷贝到另外一个。

  • 格式: sendfile on | off;
  • 默认值:sendfile off;
  • 上下文:http、server、location、if in location

sendfile_max_chunk

为了阻止一个快速连接完全占用worker进程,可限制单个sendfile()调用时可以传递的数据大小。

  • 格式: sendfile_max_chunk size;
  • 默认值:sendfile_max_chunk 0;
  • 上下文:http、server、location。

tcp_nopush

开启或关闭使用 TCP_NODELAY 操作再 FreeBSD中。或 TCP_CORK 套接字操作在Linux。
这个操作只能与 sendfile一起使用。

  • 格式: tcp_nopush on | off;
  • 默认值:tcp_nopush off;
  • 上下文:http、server、location

开启影响有下面两个:

  • 在Linux和FreeBSD 4.*上将响应头和正文的开始部分一起发送;
  • 一次性发送整个文件。

tcp_nodelay

tcp_nodelay操作允许覆盖Nagle’s algorithm算法。这个算法目的是当解决在低网速发送小数据报文的问题。该算法将一定量的小报文整合为一个大数据报文,并以200ms延迟发送。现在网络情况下,当提供很大一个静态文件时,可以无需在意报文的大小,可以立即发送数据报文。

  • 格式: tcp_nodelay on | off;
  • 默认值: tcp_nodelay on;
  • 上下文:http、server、location

该选项仅在连接转换到保持活动状态时启用。例如:

1
2
3
4
5
location /mp3  {
tcp_nodelay on;
keepalive_timeout 65;
...
}

优化Backlog 队列

NGINX很重要一个特点是可以快速处理进来的连接。
一般的规则是当一个连接被确认,它会加入监听的监听套接字 listen 队列。正常情况下这个队列会很小,或者没有。但在高负荷下,这个队列可能显著增长这样的结果就是性能不均衡,连接丢失和延迟。

查看 Listen 队列

1
netstat -Lan

正常情况是这样:

1
2
3
4
5
Current listen queue sizes (qlen/incqlen/maxqlen)
Listen Local Address
0/0/128 *.12345
10/0/128 *.80
0/0/128 *.8080

上面输出显示,在80端口有10个未接收的请求。它连接限制是128个。这是正常的情况。

1
2
3
4
5
Current listen queue sizes (qlen/incqlen/maxqlen)
Listen Local Address
0/0/128 *.12345
192/0/128 *.80
0/0/128 *.8080

在高负载情况下,输出如上显示。有192个连接未被接收这超过了限制的128个连接。这时你需要增加等待队列的上限值。这需要我们调整操作系统的参数已经NGINX的配置参数。

FreeBSD

1
sudo sysctl kern.ipc.somaxconn=4096

Linux

1
2
3
4
5
6
7
sudo sysctl -w net.core.somaxconn=4096

打开 /etc/sysctl.conf 文件
vi /etc/sysctl.conf

添加一行内容如下:
net.core.somaxconn = 4096

配置NGINX

如果你设置的 somaxconn值大于512值,你需要修改 listen指令的 backlog参数。

1
2
3
4
server {
listen 80 backlog 4096;
# The rest of server configuration
}

日志管理

日志分析工具 goaccess

goaccess是一个专业的实时日志分析工具,是用c语言写的,功能强大,能分析nginx,apache等日志。它能够分析访问的来源,访问所有的浏览器,操作系统,它的统计信息不输于一个专业的浏览量统计网站,而且它还能导出成csv、html等格式。

安装
1
2
3
4
5
6
$ wget http://tar.goaccess.io/goaccess-1.2.tar.gz
$ tar -xzvf goaccess-1.2.tar.gz
$ cd goaccess-1.2/
$ ./configure --enable-utf8 --enable-geoip=legacy
$ make
$ make install
使用

客户端输出:

1
goaccess access.log -c

静态页面输出:

1
goaccess access.log -o report.html --log-format=COMBINED

实时静态页输出:

1
goaccess access.log -o /var/www/html/report.html --log-format=COMBINED --real-time-html

日志切割

通过 logrotate服务完成日志切割。
编辑 __/etc/logrotate.d/nginx这个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/var/log/nginx/*.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
[ -s /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}

在线升级/编译模块

因为NGINX一主多work进程架构,升级或编译新模块及其简单。和安装基本一样

  1. ./configure
  2. make
  3. make install
  4. make upgrade

需要新编译自带模块就在 configure时加入例如:--without-http_fastcgi_module
如果安装第三方模块,先将模块下载下来,然后通过--add-module=第三方模块绝对路径引入./configure