Nginx

Nginx

Nginx 是一个高性能的 HTTP/反向代理服务器和 IMAP/POP3/SMTP 代理服务器。

核心功能

  1. Web服务器
  • 处理静态资源请求
  • 支持 HTTP/2 和 Websocket
  • 每秒可处理 10 万+ 并发请求
  1. 反向代理
  • 隐藏真实服务信息
  • 负载均衡
  • 缓存常用响应内容
  1. 安全网关
  • SSL/TLS 加密
  • 防止DDos攻击
  • 基于IP的访问控制

Nginx安装

源码编译安装

1.1 安装好依赖

gcc、gcc-c++、pcre-devel、zlib-devel、openssl、openssl-devel、wget

1
yum -y install gcc pcre-devel zlib-devel openssl openssl-devel gcc-c++ wget

1.2 解压nginx

1
tar -xvf nginx-1.12.2.tar.gz

进入nginx-1.12.2目录,进行检出

1
./configure --prefix=/root/nginx

–prefix:指定nginx检出目录

执行make回车、然后执行make install,进行编译

1
make install

最后会发现/root/下面会多了一个nginx目录,这个目录就是nginx的执行目录

1.3 nginx命令

  • ./nginx:启动nginx
  • ./nginx -s stop:关闭nginx
  • ./nginx -s reload:重启nginx
1
./nginx   #启动nginx

此时浏览器访问依旧不行。那是因为Linux的防火墙默认不让外界范围,必须要在防火墙中开放端口

1.4 防火墙开放80端口

1、查看所有开放的端口

1
firewall-cmd --zone=public --list-ports

2、开放80端口

1
firewall-cmd --zone=public --add-port=80/tcp --permanent

3、重新加载防火墙

1
firewall-cmd --reload

关闭防火墙:sudo systemctl stop firewalld 本次关闭防火墙(下次启动时防火墙又会开启)

禁用防火墙:sudo systemctl disable firewalld (每次启动时防火墙都关闭。需要重启生效)

查看防火墙状态:sudo systemctl status firewalld

1.5 设置nginx启动用户

nginx启动的用户默认为nobody,我们需要将其改为root(当前登录用户)

编辑/root/nginx/conf/nginx.conf

1
2
3
# user nobody
改为
user root; # 当前启动nginx的用户

1.6 测试访问

http://192.168.170.128

包管理器安装

CentOS7为例

1
yum install -y nginx

包管理器安装特点:

  • 自动解决依赖关系
  • 安装路径遵循系统规范(如 /etc/nginx)
  • 适合快速部署标准版本
  • 版本可能较旧

配置文件详解

完整配置文件

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
user  root;				
worker_processes 1;

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

#pid logs/nginx.pid;


events {
worker_connections 1024;
}


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 logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;

server {
listen 80;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root html;
index index.html index.htm;
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}


# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;

# location / {
# root html;
# index index.html index.htm;
# }
#}


# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;

# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;

# location / {
# root html;
# index index.html index.htm;
# }
#}
}

nginx.conf配置文件主要分为三部分。

2.1 main块

1
2
3
4
5
6
7
user  root;			# 工作进程worker所属用户		
worker_processes 1;
worker_rlimit_nofile 65535;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;

主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等

  • user:设置worker进程运行的用户或用户组,默认是nobody用户(注意:nginx启动默认有两个进程,一个为master,另一个为worker)

  • worker_processes:nginx要开启的工作进程数量,一般开启一个即可,如果服务器上配置有多个CPU可适当提高(一般保持和CPU核心数一致即可)

  • worker_rlimit_nofile:nginx单个进程最大的打开文件数

  • pid:指定master进程的存储文件位置

    • 查看master进程:
    1
    ps -ef|grep nginx

  • error_log:指定错误日志的存放位置

    • 格式如下:
    1
    2
    3
    4
    5
    6
    error_log path [level]
    实例:
    error_log logs/error.log
    error_log logs/error.log debug
    error_log logs/error.log notice
    error_log logs/error.log info
    • 日志等级level的值有debuginfonotice, warnerrorcrit, alertemerg,错误等级由低到高,debug等级最低(日志信息最多,但会带来较大的磁盘IO开销),emerg等级最高(日志信息最少) ,一般的日志是由 warn | error | crit 这三个场景产生。

2.2 events块

events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。

1
2
3
4
5
6
7
events {
multi_accept on;
worker_connections 1024;
open_file_cache max=3000 inactive=120s;
open_file_cache_valid 30s;
open_file_cache_min_uses 5;
}
  • multi_accept:设置一个进程是否同时接受多个网络连接,默认为off
  • worker_connections:每个进程允许的最大连接数
  • nginx服务器最大连接数= worker_process * worker_connection
  • open_file_cache max=3000 inactive=120s
  • open_file_cache:设置打开文件的缓存数量(worker_rlimit_nofile:设置单个进程打开文件的最大数量)
    • max:最大缓存文件数量
    • inactive:文件在指定时间内未被请求,达到删除缓存条件
  • open_file_cache_valid 30s:30s检查一次文件缓存,如果发现有文件在120s内没有被使用,则清空该文件的缓存
  • open_file_cache_min_uses 5:120s内如果有文件没有使用5次,那么则清空该文件的缓存

2.3 http块

http 模块主要定义代理、缓存和日志定义等功能。

2.3.1 http 全局配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
http{
include /root/a.conf;
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 logs/access.log main;

sendfile on;
#tcp_nopush on;
tcp_nodelay on;
#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;
}
  • include:加载其他位置的nginx配置文件(互补配置)
  • default_type:当服务器未识别请求资源的类型时,默认以该类型响应
  • keepalive_timeout:HTTP 有一个 KeepAlive 模式,它告诉 web服务器在处理完一个请求后保持这个 TCP 连接的打开状态。若接收到来自客户端的其它请求,服务端会利用这个未被关闭的连接,而不需要再建立一个连接。KeepAlive 在一段时间内保持打开状态,它们会在这段时间内占用资源。占用过多就会影响性能。Nginx 使用 keepalive_timeout 来指定 KeepAlive 的超时时间(timeout)。指定每个 TCP 连接最多可以保持多长时间。Nginx 的默认值是 75 秒,有些浏览器最多只保持 60 秒,所以可以设定为 60 秒。若将它设置为 0,就禁止了 keepalive 连接。

2.3.2 server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

error_page 404 405 406 /40x.html;

location /40x.html {
root html;
}
}
  • listen:监听的端口
  • server_name:访问的服务名(ip地址)
  • error_page:错误页面
1
2
3
4
error_page   404 405 406 /40x.html		# 如果出现404 405 406错误则调到40x.html页面处理错误
location /40x.html { # 来到 html/40x.html处理
root html;
}

tips:error_page处理的是nginx代理时出现的404问题,如nginx已经代理成功到对应的服务器上,因服务器上没有资源而404,则error_page不处理。

2.3.2.1 location

语法:

1
location [=|~|~*|^~] /uri/ { … }

示例:

1
2
3
4
5
location / {
root html;
index index.html index.htm;
#alias /etc/www/image/;
}

location的uri匹配规则:

  • / :无修饰符匹配,代表以 / 开头的所有uri都符合
1
2
3
4
5
6
7
8
9
location /abc {

}
success:
http://baidu.com/abc
http://baidu.com/abc?p=1
http://baidu.com/abc/
http://baidu.com/abc/def
http://baidu.com/abcdef
  • = :精确匹配,
1
2
3
4
5
6
7
8
9
10
11
location = /abc {

}
success:
http://baidu.com/abc
http://baidu.com/abc?p=1

error:
http://baidu.com/abc/
http://baidu.com/abc/def
http://baidu.com/abcdef
  • ~ :匹配正则表达式(区分大小写)
1
2
3
4
5
6
7
8
location ~ \.(jpg|png|bmp)$ {
proxy_pass http://localhost:8080/images;
}
success:
http://baidu.com/1.bmp

error:
http://baidu.com/1.Bmp
  • ~* :匹配正则表达式(不区分大小写)
1
2
3
4
5
6
7
8
9
10
location ~* \.(jpg|png|bmp)$ {
proxy_pass http://localhost:8080;
}
success:
http://baidu.com/1.bmp
http://baidu.com/1.Bmp

error:
http://baidu.com/abc/1.bmp
http://baidu.com/abc/1.Bmp

http://192.168.133.130/1.png

  • ^~ :类似于无修饰符匹配,但优先级比无修饰符高(本质上也是一种无修饰符匹配,不可以和无匹配修饰符同时使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
location = /1.png {				# 1 精确匹配
root /root/html/a/;
}

location ^~ /1.png { # 2 类似于无修饰符匹配,但优先级比无修饰符高
root /root/html/b/;
}

location ~ \.(png)$ { # 3 正则表达式匹配
root /root/html/c/;
}

location /1.png { # 4 无修饰符匹配(精确匹配)
root /root/html/d/;
}

location / { # 5 无修饰符匹配(模糊匹配)
root /root/html;
}

测试:访问http://192.168.10.131/1.png,查看优先级。

http://192.168.18.132/1.png

查找顺序和优先级

1:带有“=“的精确匹配优先

2:^~ 匹配

3:正则表达式匹配

4:无修饰符匹配(精确匹配)

5:无修饰符匹配(模糊匹配)

2.3.3 root和alias的区别:

  • root:访问的资源去哪个目录下寻找
  • index:首页配置
  • alias:别名配置

http://localhost/abc/1.png

1
2
3
4
5
6
7
8
9
location /abc/ {
alias /etc/image/;
}
# 如果访问abc目录下的文件,则去/etc/image 目录下找

location /abc/ {
root /etc/image/;
}
# 如果访问abc目录下的文件,则去/etc/image/abc 目录下找

Tips:alias后面必须要用”/“结尾!否则会找不到文件,root可有可无

2.3.4 自定义日志格式

1
2
3
4
5
6
7
8
9
10
11
12
13
http {
# 自定义日志格式(在http块中添加)
log_format custom_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'响应时间:$upstream_response_time';

# 应用自定义格式(在server块中添加)
server {
access_log logs/access.log custom_log; # 替换原有的 access_log 配置
# ... 其他 server 配置 ...
}
}

常用的日志参数说明:

  • $remote_addr:客户端的IP地址
  • $remote_user:客户端用户名(基本身份验证时显示)
  • $time_local:服务器时间([访问时间] 格式)
  • $request:完整的原始请求(包含方法、URI和协议版本)
  • $status:HTTP状态码
  • $body_bytes_sent:发送给客户端的body字节数
  • $http_referer:请求来源页面(从哪个链接跳转过来)
  • $http_user_agent:客户端浏览器信息
  • $http_x_forwarded_for:经过代理服务器时的客户端原始IP(需配置代理服务器转发)
  • $upstream_response_time:后端服务器响应时间(反向代理时特别有用)
  • $request_time:从客户端到Nginx的请求时间(单位:秒)
  • $upstream_addr:上游服务器的IP地址
  • $upstream_status:上游服务器的HTTP状态码
  • $upstream_response_length:上游服务器返回的字节数
  • $upstream_cache_status:上游服务器的缓存状态
  • $upstream_connect_time:Nginx与上游服务器建立连接的时间(单位:秒)
  • $upstream_header_time:Nginx从上游服务器接收响应头的时间(单位:秒)
  • $upstream_response_time:Nginx从上游服务器接收完整响应的时间(单位:秒)
  • $upstream_sent_time:Nginx将响应发送给客户端的时间(单位:秒)
  • $upstream_total_time:Nginx与上游服务器的总时间(单位:秒)
  • $upstream_request_time:Nginx与上游服务器的总时间(单位:秒)
  • $upstream_bytes_sent:Nginx发送给上游服务器的字节数
  • $upstream_bytes_received:Nginx从上游服务器接收的字节数
  • $upstream_cache_status:上游服务器的缓存状态

配置完成后重新加载nginx配置:

1
nginx -s reload

Json格式日志示例:

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
http {
# 定义 JSON 格式日志
log_format json_escape escape=json
'{'
'"timestamp": "$time_iso8601",' #请求时间,ISO 8601 格式(如 2023-10-01T12:34:56+08:00)
'"remote_addr": "$remote_addr",' #客户端 IP 地址
'"remote_user": "$remote_user",' #HTTP 基本认证的用户名(未启用认证时为 -)
'"request_method": "$request_method",' #HTTP 请求方法(如 GET/POST)
'"request_uri": "$request_uri",' #完整请求 URI(包含参数,如 /index.html?param=1)
'"status": "$status",' #HTTP 响应状态码(如 200/404/500)
'"body_bytes_sent": "$body_bytes_sent",' #发送给客户端的响应体大小(字节)
'"http_referer": "$http_referer",' #请求来源页面的 URL(直接访问时为 -)
'"http_user_agent": "$http_user_agent",' #客户端浏览器或工具标识(如 Mozilla/5.0 ...)
'"request_time": "$request_time",' #请求处理时间(秒,精度到毫秒,如 0.123)
'"upstream_response_time": "$upstream_response_time",' #反向代理时上游服务器的响应时间(未代理时为 -)
'"scheme": "$scheme",' #请求协议(http 或 https)
'"host": "$host",' #请求的域名(如 example.com)
'"server_name": "$server_name",' #匹配请求的 server 块名称
'"http_x_forwarded_for": "$http_x_forwarded_for",' #客户端原始 IP(通过代理时记录,未代理时为 -)
'"connection": "$connection",' #连接序列号(用于跟踪长连接)
'"connection_requests": "$connection_requests",' #当前连接上的请求数(长连接复用次数
'"ssl_protocol": "$ssl_protocol",' #SSL/TLS 协议版本(如 TLSv1.3,非 HTTPS 请求为 -)
'"ssl_cipher": "$ssl_cipher"' #SSL/TLS 加密套件(如 ECDHE-RSA-AES256-GCM-SHA384,非 HTTPS 为 -)
'}';

# 应用自定义格式(在server块中添加)
server {
access_log logs/access.log json_escape; # 替换原有的 access_log 配置
# ... 其他 server 配置 ...
}
}

反向代理

3.1 准备工作

在线下载jdk并安装:

1
yum -y install java-1.8.0-openjdk

准备两个tomcat,一个为8080端口,另一个为8081端口

在防火墙中开放8080、8081端口

1
2
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --zone=public --add-port=8081/tcp --permanent

启动两台tomcat:

1
./catalina.sh run

3.2 示例一

1
2
3
4
5
6
7
8
server {
listen 80; #监听的端口
server_name 192.168.170.128;

location / {
proxy_pass http://192.168.170.128:8080; # 代理的端口
}
}

3.3 示例二

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80; #监听的端口
server_name 192.168.170.128;

location /list {
proxy_pass http://192.168.170.128:8080; # 代理的端口
}
location /item {
proxy_pass http://192.168.170.128:8081; # 代理的端口
}
}

负载均衡

nginx负载均衡内置有4总算法,分别为轮询、权重(weight)、hash、fair等,其中轮询是nginx默认使用的算法

准备工作:

在两个tomcat下的webapps下创建aaa文件夹,并且创建index.html

4.1 轮询

默认选项,当weight不指定时,各服务器weight相同,每个请求按时间顺序逐一分配到不同的后端服务器

1
2
3
4
5
6
7
8
9
10
11
12
upstream myserver{
server 192.168.170.128:8080;
server 192.168.170.128:8081;
}
server {
listen 80;
server_name 192.168.170.128;

location / {
proxy_pass http://myserver;
}
}

访问:http://192.168.170.128/aaa

查看是否有轮询效果。

4.2 权重(weight)

指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。每台服务器的默认weight为1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream myserver{
server 192.168.170.128:8080 weight=2;
server 192.168.170.128:8081;
}
server {
listen 80;
server_name 192.168.170.128;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
proxy_pass http://myserver;
}
}

4.3 哈希(ip_hash)

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session不能跨服务器的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
upstream myserver{
ip_hash;
server 192.168.170.128:8080;
server 192.168.170.128:8081;
}
server {
listen 80;
server_name 192.168.170.128;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
proxy_pass http://myserver;
}
}

4.4 url_hash

根据url的hash结果分配,同一个url访问的是同一台机器。一般用于下载服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
upstream myserver{
hash $request_uri;
server 192.168.170.128:8080;
server 192.168.170.128:8081;
}
server {
listen 80;
server_name 192.168.170.128;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
proxy_pass http://myserver;
}
}

url_hash在早期的nginx版本中,nginx内部并没有集成url_hash功能,需要用户自己手动安装url_hash模块

下载地址:https://github.com/evanmiller/nginx_upstream_hash

当你服务端的一个特定url路径会被同一个用户连续访问时,如果负载均衡策略还是轮询的话,那该用户的多次访问会被打到各台服务器上,这显然并不高效(会建立多次http链接等问题)。甚至考虑一种极端情况,用户需要分片上传文件到服务器下,然后再由服务器将分片合并,这时如果用户的请求到达了不同的服务器,那么分片将存储于不同的服务器目录中,导致无法将分片合并。所以,此类场景可以考虑采用nginx提供的ip_hash策略。既能满足每个用户请求到同一台服务器,又能满足不同用户之间负载均衡。

4.5 fair

fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面大小、加载时间长短智能的进行负载均衡。

4.5.1 安装fair模块

fair模块属于第三方插件,功能没有集成在nginx中,因此要额外安装。

(1)安装unzip插件

1
yum -y install unzip

(2)解压nginx-upstream-fair-master.zip

1
unzip nginx-upstream-fair-master.zip

一、在安装nginx时就指定安装fair模块:

(1)进入nginx解压目录(nginx-1.12.2),检出文件

1
./configure --prefix=/root/nginx --add-module=/root/nginx-upstream-fair-master 

(2)编译和安装

1
make install

二、已经安装过nginx后安装fair模块:

(1)进入nginx解压目录(nginx-1.12.2)重新检出文件(地址和原来检出的时候一致)

1
./configure --prefix=/root/nginx --add-module=/root/nginx-upstream-fair-master

(2)编译(只需要编译,如果安装会覆盖原来的)

1
make

(3)覆盖原来的nginx可执行命令

在当前目录中(nginx-1.12.2目录),进入objs目录,替换掉原来nginx的可执行文件

1
2
3
4
5
[root@localhost nginx-1.12.2]# cd objs/
[root@localhost objs]# ls
addon autoconf.err Makefile nginx nginx.8 ngx_auto_config.h ngx_auto_headers.h ngx_modules.c ngx_modules.o src
[root@localhost objs]# cp nginx /root/nginx/sbin/
cp:是否覆盖"/root/nginx/sbin/nginx"? y

4.5.2 使用fair模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
upstream myserver{
fair;
server 192.168.170.128:8080;
server 192.168.170.128:8081;
}
server {
listen 80;
server_name 192.168.170.128;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
proxy_pass http://myserver;
}
}

4.6 常用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http{
# resolver 10.10.8.1;

upstream myserver1{
server 192.168.170.128:8080 weight=3;
server 192.168.170.128:8081 weight=2;
server 192.168.170.128:8082 down;
server 192.168.170.128:8083 max_conns=1000;
server 192.168.170.128:8084 weight=2 max_fails=3 fail_timeout=60;
server 192.168.170.128:8085 backup;
}
server {
listen 80;
server_name 192.168.170.128;
location / {
proxy_pass http://myserver1;
}
}
}
  • resolve:将server中配置的域名,使用指定域名解析器解析。
  • weight:权重,默认为1
  • backup:备份服务器,其他服务器都挂了之后才会生效
  • down:设置当前服务器不可用(不会被分配请求)
  • max_conns:设置服务器的最大连接数量,数量达到后,将不会有请求分配到该服务器,默认为0,代表不限制连接数
  • max_fails:设置服务器运行请求连接失败的次数,超过该次数后,在fail_timeout时间内,不会有请求分配此服务器,默认为1
  • fail_timeout:服务器到达max_fails次失败请求后,在fail_timeout时间内,nginx不会将新的请求分配到此服务器
  • backup:备用服务器,当以上的所有服务器都不可用时,此服务器提供服务;

4.7 总结

4.7.1 轮询

  • 概念

nginx默认的负载均衡机制,将请求轮询派发给每个服务器

4.7.2 权重

  • 概念

给不同的web服务器分配不同的权重,默认每台服务器的权重为1,权重越高,访问几率越大

4.7.3 ip_hash

  • 概念

为每一个ip地址都计算出一个hash值,nginx根据此hash值选择代理到哪台服务器,由于每一客户端的ip不易变动,因此可以解决集群环境下的session共享问题。

  • 应用场景
    • 当服务端的某个资源被同一客户端多次访问时,如果使用的负载均衡策略还是轮询的话,那么该用户会被轮询到各台服务器,造成资源浪费(会建立多次http连接,keepalive时间)
    • 在作用于文件传输时,如果采用的是断点续传方式,那么则会导致文件最终上传失败。

4.7.4 url_hash

  • 概念

为每一个访问的url都计算出一个hash值,nginx根据此hash值选择代理到哪台服务器

  • 应用场景
    • 缓存集群下载

4.7.5 fair

  • 概念

nginx根据web服务器的响应时间来选择代理到哪台服务器(压力小的服务器优先选择)

Tips:fair功能属于第三方模块,需要手动安装

动静分离

Nginx 动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用 Nginx处理静态页面,Tomcat 处理动态页面。动静分离从目前实现角度来讲大致分为两种。

(1)纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案;

(2)动态跟静态文件混合在一起发布,通过 nginx 来分开。

1
2
3
4
5
6
7
8
9
10
11
12
location /dynamic/ {				# 如果是dynamic下的请求,就代理到后台服务器
proxy_pass http://myserver; # 动态资源
}

location /static/ { # 如果是static下的请求代理到服务器的/root/data/static目录下
root /root/data/;
}

location /images/ { # 如果是image下的请求代理到服务器的/root/data/image目录下
root /root/data/;
autoindex on; # 是否以列表展示文件
}

keepalived搭建高可用集群

6.1 高可用集群

我们在后台搭建了Tomcat集群,使用Nginx做负载均衡处理,这就意味着Nginx是所有请求的”入口“,那么万一Nginx服务器出现故障,那么整个系统将会处于瘫痪过程,我们希望我们系统可以存在一台”备用“Nginx服务器,万一主工作服务器(主服务器)出现故障后,那么备份服务器可以顶替主服务器继续工作,保证我们的系统不会瘫痪,达到系统的高可用效果。

如图:

6.2 keepalived安装

(1)在线下载安装

1
yum -y install keepalived

(2)查看keepalived配置文件,/etc/keepalived/keepalived.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vrrp_script check_ng {
script "/root/nginx_check.sh" # 检测脚本
interval 2 # 间隔执行时间
}
vrrp_instance VI_1 {
state MASTER # 标注是工作状态(master)还是备份状态(backup),路由器组不可以重名
interface ens33 # 网卡
virtual_router_id 6 # 虚拟路由标志,同组的virtual_router_id应该保持一致,主备机保持一致
priority 100 # 设置本节点的优先级,一般master节点较高 (最大值为255)
advert_int 1 # master与backup同步检查的时间间隔
master_down_interval 10 # 检测master多久没有发送心跳过来才认为master节点已经宕机(备份路由器组取集群备份服务器中的最小值)

virtual_ipaddress {
192.168.88.188 # 虚拟ip
}
track_script { # 启动检测脚本
check_ng # 脚本名称
}
}
  • 检测脚本
1
2
3
4
5
6
7
8
A=`ps -C nginx --no-header |wc -l`
if [ $A -eq 0 ];then
/root/nginx/sbin/nginx

if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
killall keepalived
fi
fi
  • 安装killall命令
1
yum -y install psmisc
  • 关闭selinux(关闭限制进程访问的资源)
1
2
3
4
# 临时关闭selinux
setenforce 0
# 永久关闭selinux(需要重启服务器)
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
  • 授权
1
chmod u+x /root/nginx_check.sh /root/keepalived_start.sh /root/keepalived_stop.sh /root/start.sh /root/stop.sh

6.3 keepalived简介

keepalived是集群管理中保证集群高可用的一个服务软件,用来防止单点故障。

keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol,即虚拟路由冗余协议。其作用是检测服务器的状态,如果有一台服务器宕机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。

6.4 keepalived 工作原理

VRRP(Virtual Router Redundancy Protocol)虚拟路由冗余协议是一种容错的主备模式的协议,当网络设备发生故障时,可以不影响主机之间通信情况下进行设备切换,并且相对用户切换过程时透明的(用户无感知)。

路由器(安装了Keepalived的机器)开启VRRP功能后,会根据优先级确定自己在备份组中的角色。优先级高的路由器成为主用路由器,优先级低的成为备用路由器。主路由器拥有虚拟IP与虚拟MAC,实现各种网络功能,并发送VRRP通告报文,通知备用路由器组内的其他路由器自己工作正常;备用路由器则启动定时器等待通告报文。

6.4.1 抢占模式

当备份路由器组长时间(master_down_interval)未接收到master节点的VRRP报文后,备份路由器组则认为master节点已经无法正常提供服务(宕机),那么备份路由器组则会推选出一个优先级较高的backup节点(根据配置文件),作为主节点继续提供服务,当后续master节点(原来的)恢复正常后,备份路由器组接收到原来master节点的VRRP报文则认为master节点恢复正常,backup节点则回到备份路由器组,由master节点提供服务。

当备用路由器组收到VRRP通告报文后,会将自己的优先级与通告报文中的优先级进行比较。如果大于通告报文中的优先级,则成为主用路由器;否则将保持备用状态。

VRRP选举机制

  1. 虚拟IP拥有者,如果某台路由器的IP地址与虚拟路由器的VIP地址一致,那么这台就会被选为主用路由器。
  2. 优先级较高者,如果没有虚拟IP拥有者,优先级数值大的路由器会被选举出,优先级范围0~255。
  3. IP地址较大者,如果优先级一样高,IP地址数值大的路由器会被选举出。

在抢占模式中,优先级高的为master节点,state只是作为标注作用,并非真正意义上的master节点,具体的选举要看优先级

6.4.2 非抢占模式

在非抢占模式下,所有的节点都为backup,先启动的先提供服务(Master),后面的按照优先级顺序提供服务。主要注意的是,如果第一个提供服务的节点(Master)挂了,那么后续优先级高的将出来提供服务,当原来的”Master”节点又恢复正常之后,不会将服务切换为原来的”Master”节点提供,而是继续由现在的服务器节点提供服务。省去了当master节点恢复正常后,本来正常提供的服务节点backup需要将vip(虚拟ip)迁移到master节点的切换操作。

第一个启动的节点为master节点,后面启动的按照优先级分配。优先级高的作为下一个备选master节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vrrp_script check_ng {
script "/root/nginx_check.sh"
interval 1
}
vrrp_instance VI_1 {
nopreempt # 标志模式为 非抢占模式
state BACKUP # 在非抢占模式下,所有的服务器状态都为BACKUP
interface ens33
virtual_router_id 6
priority 120
advert_int 1
master_down_interval 10
virtual_ipaddress {
192.168.170.188
}
track_script { # 启动检测脚本
check_ng # 脚本名称
}
}

Tips:在非抢占模式下,state标注的为Master节点;

Nginx工作原理

7.1 Nginx架构图:

Master的任务:

读取并解析nginx.conf,管理worker进程,通知worker进程来处理请求。

Nginx是多进程单线程架构

Redis也是多进程单线程

Worker的任务:

Master进程发布消息之后,所有的Worker进程都来”抢夺”这个请求。

每一个Worker进程都可以极大的发挥单核CPU的极限性能

每一个Worker进程都是单线程的,这样避免了线程间的切换,Worker进程数一般和CPU的核数相同。

在nginx.conf中,可修改Worker的进程数量。

1
2
3
4
5
6
7
worker_processes  1;			# worker的进程数量

events {
worker_connections 1024; # 每个worker进程最多处理的连接数
...
}
...

nginx的每个worker都会发挥出CPU单核的最大性能极限,因此一般将worker进程的数量设置为cpu的核心数量(线程数),设置少了会浪费CPU性能,设置多了会造成多个worker争抢同一个核心的上下文切换带来的损耗。

7.2 计算nginx并发数

每台nginx能建立的最大连接数为:worker process * worker_connections

但这仅仅是连接数,在http1.1中,浏览器的每次请求都会占用两个连接,因此nginx的并发数为:

worker process * worker_connections / 2

如果nginx作为反向代理服务器,那么nginx出了与浏览器进行连接外,还要与后台的web服务器进行连接(Tomcat)

因此nginx在作为反向代理时,并发量为:worker process * worker_connections / 4