Nginx

服务器水平拓展,服务器集群。一个域名跟一台服务器绑定,如果要拓展服务器。所以用到反向代理,负载均衡服务器,Nginx。把请求分发到具体的服务器中去。

tomcat 并发量在 200-500,Nginx 并发量 5万。

搭建Nginx高可用环境,Nginx是一个高性能的 HTTP 和 反向代理服务器,也是一个 IMAP/POP3/SMTP服务器。使用 Nginx+keepalived 搭建高可用环境。

反向代理 && 负载均衡


nginx 起到反向代理的作用,将请求转发给我们的 tomcat 服务器。传统客户端/个人访问网络,需要通过代理服务器。而如今,网络访问服务器,需要通过反向代理服务器 nginx,nginx 就起到了反向代理的作用。

负载均衡策略,默认是轮询策略。
使用硬件负载均衡,如F5,Array等负载均衡器
使用软件进行负载均衡,阿里云服务器均衡SLB,Nginx+Keepalived

淘宝基于 Nginx 拓展,Tengine 开源项目。

环境搭建


  1. 进行安装:tar -zxvf nginx-1.6.2.tar.gz
  2. 下载依赖库文件:
1
2
3
4
yum install pcre -y
yum install pcre-devel -y
yum install zlib -y
yum install zlib-devel -y
  1. 进行 configure 配置,查看是否报错
1
2
cd nginx-1.6.2
./configure --prefix=/usr/local/nginx
  1. 编译安装 make && make install
  2. 在 /usr/local/nginx 目录下,可以看到如下4个目录: conf 配置文件,html网页文件,logs日志文件,sbin主要二进制程序
  3. 启动命令:/usr/local/nginx/sbin/nginx,关闭命令:/usr/local/nginx/sbin/nginx -s stop,重启命令:/usr/local/nginx/sbin/nginx -s reload
  4. 可以使用 netstat -ano | grep 80 查看端口
  5. 访问浏览器 http://192.168.122.133(看到欢迎页面说明没问题)

注意:如果出现这个错误: ./configure: error: C compiler cc is not found 执行命令:yum -y install gcc gcc-c++ autoconf automake make

检查防火墙状态:firewall-cmd --statestop firewallddisable firewalld

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206

#user nobody;

#开启进程数 <=CPU数 
worker_processes 1;

#错误日志保存位置
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#进程号保存文件
#pid logs/nginx.pid;

#每个进程最大连接数(最大连接=连接数x进程数)每个worker允许同时产生多少个链接,默认1024
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压缩
#gzip on;

#设定请求缓冲
#client_header_buffer_size 1k;
#large_client_header_buffers 4 4k;

#设定负载均衡的服务器列表
#upstream myproject {
#weigth参数表示权值,权值越高被分配到的几率越大
#max_fails 当有#max_fails个请求失败,就表示后端的服务器不可用,默认为1,将其设置为0可以关闭检查
#fail_timeout 在以后的#fail_timeout时间内nginx不会再把请求发往已检查出标记为不可用的服务器
#}

#webapp
#upstream myapp {
# server 192.168.122.133:8080 weight=1 max_fails=2 fail_timeout=30s;
# server 192.168.122.134:8080 weight=1 max_fails=2 fail_timeout=30s;
#}

#配置虚拟主机,基于域名、ip和端口
server {
#监听端口
listen 80;
#监听域名
server_name localhost;

#charset koi8-r;

#nginx访问日志放在logs/host.access.log下,并且使用main格式(还可以自定义格式)
#access_log logs/host.access.log main;

#返回的相应文件地址
location / {
#设置客户端真实ip地址
#proxy_set_header X-real-ip $remote_addr;
#负载均衡反向代理
#proxy_pass http://myapp;

#返回根路径地址(相对路径:相对于/usr/local/nginx/)
root html;
#默认访问文件
index index.html index.htm;
}

#配置反向代理tomcat服务器:拦截.jsp结尾的请求转向到tomcat
#location ~ \.jsp$ {
# proxy_pass http://192.168.122.133:8080;
#}

#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;
#}
}

#虚拟主机配置:基于域名、ip和端口
server {
# 监听端口
listen 1234;
# 监听域名
server_name wolfcode.cn;
location / {
#正则表达式匹配uri方式:在/usr/local/nginx/wolfcode.cn下 建立一个test123.html 然后使用正则匹配
#location ~ test {
## 重写语法:if return (条件 = ~ ~*)
#if ($remote_addr = 192.168.122.1) {
# return 401;
#}

#if ($http_user_agent ~* firefox) {
# rewrite ^.*$ /firefox.html;
# break;
#}

root wolfcode.cn;
index index.html;
}
server {
access_log logs/lizhaoloveit.access.log main(输出格式);
listen 8088;
server_name localhost;
location / {
root lizhaoloveit;
index index.html
}
}

#location /goods {
# rewrite "goods-(\d{1,5})\.html" /goods-ctrl.html;
# root wolfcode.cn;
# index index.html;
#}

#配置访问日志
access_log logs/wolfcode.cn.access.log main;
}



# 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。

日志文件


nginx 访问日志放在 log/host.access.log 下,并且使用 main 格式(支持自定义格式)

main 格式配置如下

1
2
3
4
# 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;

查看日志内容命令:tail -n 100 -f access.log

根据每个结点,设置其单独的日志文件。

系统运行起来后,我们需要对 nginx 日志分析,得到响应耗时的 url 请求时间,以及这段时间的请求量和并发量,通过分析找到优化系统的方案,所以需要运维人员对 nginx 的日志进行切割和分析处理,我们会通过定时器定时将日志按 天/小时备份。

实现定时备份日志:

  1. 分析如何去实现日志切分,编写shell脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh

BASE_DIR=/usr/local/nginx
BASE_FILE_NAME=lizhaoloveit.cn.access.log

CURRENT_PATH=$BASE_DIR/logs
BAK_PATH=$BASE_DIR/datalogs

CURRENT_FILE=$CURRENT_PATH/$BASE_FILE_NAME
BAK_TIME=`/bin/date -d yesterday +%Y%m%d%H%M`
BAK_FILE=$BAK_PATH/$BAK_TIME-$BASE_FILE_NAME

mv $CURRENT_FILE $BAK_FILE
$BASE_DIR/sbin/nginx -s reopen
  1. 定时任务对脚本进行调度:crontab -e

* */1 * * * sh /usr/local/nginx/sbin/backuplog.sh
每分钟的用户访问记录做了一个备份

crontab 执行时间计算:

/12 表示每隔12小时做一次操作

注意:注意:将脚本从window拷贝到 linux,执行脚本的时候可能会出现$'\r': command not found,需要转换一下格式:yum install dos2unix -y dos2unix 为脚本文件,必须加权限 chmod 755 sbin/backuplog.sh

Location 配置


语法规则: location [=|~|~*|^~] /uri/ { … }

= 开头表示精确匹配
^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。
~ 开头表示区分大小写的正则匹配
* 开头表示不区分大小写的正则匹配
!
和!*分别为区分大小写不匹配及不区分大小写不匹配 的正则
/ 通用匹配,任何请求都会匹配到。
首先匹配 =,其次匹配^
, 其次是按文件中顺序的正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
location = / {
# 规则A
}
location = /login {
# 规则B
}
location ^~ /static/ {
# 规则C
}
location ~ \.(gif|jpg|png|js|css)$ {
# 规则D ~ 区分大小写开头, \. 表示转义
}
location ~* \.png$ {
# 规则E ~* 不区分大小写的正则匹配
}
location !~ \.xhtml$ {
# 规则F
}
location !~* \.xhtml$ {
# 规则G
}
location / {
# 规则H
}

案例,访问根目录,

http://localhost/ #规则A
http://localhost/login #规则B
http://localhost/static/a.html #规则C
http://localhost/a.gif, http://localhost/b.jpg #规则D
http://localhost/a.PNG 规则 E
http://localhost/a.CSS 规则 F
http://localhost/a.xhtml 规则 H
http://localhost/cateory/id/111 规则 H

直接匹配网站根,通过域名访问网站首页比较频繁,使用 location 会加速处理,官网。
第一个必选规则

1
2
3
location = / {
proxy_pass http://tomcat:8080/index
}

第二个必选规则是处理静态文件请求,这是 nginx 作为 http 服务器的强项,目录匹配或者后缀匹配,任选其一或者搭配使用

1
2
3
4
5
6
7
location ^~ /static/ {
root /webroot/static/; # 静态资源
}

location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/; # 资源路径
}

第三个规则是通用规则,用来转发动态请求到后端应用服务器,非静态文件请求就默认是动态请求。

1
2
3
location / {
proxy_pass http://tomcat:8080/
}

nginx + lua 可以实现更高级的语法,比如 配置白名单,配置黑名单等等。

rewrite 语法


1
2
3
4
5
if(条件为: =~~*) return、break、rewrite
if ($remote_addr = 192.168.122.1) {
return 401;
}
# 如果 ip 为122.1 则返回401 权限受限,限制访问,起到禁 ip 的效果

全局变量


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
# 官方配置:http://nginx.org/en/docs
$args #请求中的参数值
$query_string #同 $args
$arg_NAME #GET请求中NAME的值
$is_args #如果请求中有参数,值为"?",否则为空字符串
$uri #请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/foo/bar.html"。
$document_uri #同 $uri
$document_root #当前请求的文档根目录或别名
$host #优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名
$hostname #主机名
$https #如果开启了SSL安全模式,值为"on",否则为空字符串。
$binary_remote_addr #客户端地址的二进制形式,固定长度为4个字节
$body_bytes_sent #传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的"%B"参数保持兼容
$bytes_sent #传输给客户端的字节数
$connection #TCP连接的序列号
$connection_requests #TCP连接当前的请求数量
$content_length #"Content-Length" 请求头字段
$content_type #"Content-Type" 请求头字段
$cookie_name #cookie名称
$limit_rate #用于设置响应的速度限制
$msec #当前的Unix时间戳
$nginx_version #nginx版本
$pid #工作进程的PID
$pipe #如果请求来自管道通信,值为"p",否则为"."
$proxy_protocol_addr#获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串
$realpath_root #当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径
$remote_addr #客户端地址
$remote_port #客户端端口
$remote_user #用于HTTP基础认证服务的用户名
$request #代表客户端的请求地址
$request_body #客户端的请求主体:此变量可在location中使用,将请求主体通过proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass传递给下一级的代理服务器
$request_body_file #将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off,uwsgi_pass_request_body off,or scgi_pass_request_body off
$request_completion #如果请求成功,值为"OK",如果请求未完成或者请求不是一个范围请求的最后一部分,则为空
$request_filename #当前连接请求的文件路径,由root或alias指令与URI请求生成
$request_length #请求的长度 (包括请求的地址,http请求头和请求主体)
$request_method #HTTP请求方法,通常为"GET"或"POST"
$request_time #处理客户端请求使用的时间; 从读取客户端的第一个字节开始计时
$request_uri #这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:"/cnphp/test.php?arg=freemouse"
$scheme #请求使用的Web协议,"http" 或 "https"
$server_addr #服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中
$server_name #服务器名
$server_port #服务器端口
$server_protocol #服务器的HTTP版本,通常为 "HTTP/1.0" 或 "HTTP/1.1"
$status #HTTP响应代码
$time_iso8601 #服务器时间的ISO 8610格式
$time_local #服务器时间(LOG Format 格式)
$cookie_NAME #客户端请求Header头中的cookie变量,前缀"$cookie_"加上cookie名称的变量,该变量的值即为cookie名称的值
$http_NAME #匹配任意请求头字段;变量名中的后半部分NAME可以替换成任意请求头字段,如在配置文件中需要获取http请求头:"Accept-Language",$http_accept_language即可
$http_cookie #cookie 信息
$http_post
$http_referer #引用地址
$http_user_agent #客户端代理信息
$http_x_forwarded_for#相当于网络访问路径。http://www.cnblogs.com/craig/archive/2008/11/18/1335809.html
$sent_http_NAME #可以设置任意http响应头字段;变量名中的后半部分NAME可以替换成任意响应头字段,如需要设置响应头Content-length,$sent_http_content_length即可
$sent_http_cache_control
$sent_http_connection
$sent_http_content_type
$sent_http_keep_alive
$sent_http_last_modified
$sent_http_location
$sent_http_transfer_encoding

反向代理配置


配置反向代理:proxy_pass url;

反向代理之后,获取客户端 ip 地址其实是 nginx 服务器地址,这里需要 nginx 进行 forward,设置真实的ip 地址作为请求头传递给 服务器地址。

1
2
# 设置客户端真实地址
proxy_set_header X-real-ip $remote_addr;
1
2
remote ip: <%--<%=request.getHeader("X-real-ip") %> --%>
nginx server ip: <%=request.getRemoteAddr() %>

负载均衡配置


1
2
3
4
5
6
7
8
9
10
11
12
#设定负载均衡的服务器列表
#upstream myproject {
#weigth参数表示权值,权值越高被分配到的几率越大
#max_fails 当有#max_fails个请求失败,就表示后端的服务器不可用,默认为1,将其设置为0可以关闭检查
#fail_timeout 在以后的#fail_timeout时间内nginx不会再把请求发往已检查出标记为不可用的服务器
#}

#webapp
#upstream myapp {
# server 192.168.122.133:8080 weight=1 max_fails=2 fail_timeout=30s;
# server 192.168.122.134:8080 weight=1 max_fails=2 fail_timeout=30s;
#}

例如下面的配置文件

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
server {
listen 80;
server_name test.phoneacceapi.2dream.cn;
location ^~ /static/ {
proxy_pass http://112.73.82.214:8080;
root /usr/local/apache-tomcat-7.0.100/webapps/ROOT;
index index.html;
break;
}
location /api/ {
proxy_pass http://112.73.82.214:8080/;
proxy_connect_timeout 10;
proxy_send_timeout 300;
proxy_read_timeout 300;
proxy_buffer_size 32k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_redirect off;
proxy_hide_header Vary;
proxy_set_header Accept-Encoding '';
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
break;
}
}

static 静态资源直接访问tomcat,api 接口资源可以直接访问 tomcat。其他路径无法访问 tomcat。

worker_cpu_affinity


nginx 默认是没有开启利用多核 cpu 的配置的,需要通过增加 worker_cpu_affinity 配置参数充分利用多核 cpu,cpu 是任务处理,当计算费时的资源的时候,cpu 核使用上的越多,性能就越好。

配置 nginx 多核 cpu,worker_cpu_affinity 使用方法和范例:

2核cpu,开启2个进程

1
2
worker_processes     4;
worker_cpu_affinity 01 10 01 10;

开启了4个进程,它们分别对应着开启2个 CPU 内核

4个cpu,开启4个进程

1
2
worker_processes     4;
worker_cpu_affinity 0001 0010 0100 1000;

0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推

4核 cpu,开启2个进程

1
2
worker_processes     2;
worker_cpu_affinity 0101 1010;

0101表示开启第一个和第三个内核,1010表示开启第二个和第四个内核;2个进程对应着四个内核;worker_cpu_affinity配置是写在/etc/nginx/nginx.conf里面的;2核是 01,四核是0001,8核是00000001,有多少个核,就有几位数,1表示该内核开启,0表示该内核关闭。

8核cpu,开启8个进程

1
0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推;worker_processes最多开启8个,8个以上性能提升不会再提升了,而且稳定性变得更低,所以8个进程够用了。

配置完之后可以重启nginx,用ab工具或者wrk工具,可以进行性能测试,在服务器上执行top,然后按1,就可以看到cpu工作情况,如果多个cpu内核的利用率差不多,就证明nginx已经成功利用了多核cpu,测试结束后,cpu内核的负载都同时降低。

防火墙配置


CentOS7 使用 firewall-cmd 打开关闭防火墙与端口。

  • 启动:systemctl start firewalld
  • 查状态:systemctl status firewalld
  • 停止:systemctl disable firewalld
  • 禁用:systemctl stop firewalld
  • 查看所有打开的端口: firewall-cmd --zone=public --list-ports
  • 添加80端口为允许:firewall-cmd --zone=public --add-port=80/tcp --permanent (–permanent 没有此参数重启后失效)
  • 重新载入:firewall-cmd --reload(添加完后立即生效)
  • 查看:firewall-cmd --zone=public --query-port=80/tcp
  • 删除:firewall-cmd --zone=public --remove-port=80/tcp --permanent
文章作者: Ammar
文章链接: http://lizhaoloveit.cn/2020/03/05/Nginx/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ammar's Blog
打赏
  • 微信
  • 支付宝

评论