一、Nginx简单了解
Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的免费开源Web和 反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。在高并发访问的情况下,Nginx是Apache服务器不错的替代品。官网数据显示每秒TPS高达50W左右。
Nginx是目前负载均衡技术中的主流方案,Nginx是一个轻量级的高性能HTTP反向代理服务器,同时它也是一个通用类型的代理服务器,支持绝大部分协议,如TCP、UDP、SMTP、HTTPS等。
Nginx与Redis相同,都是基于多路复用模型构建出的产物,因此它与Redis同样具备 「「资源占用少、并发支持高」」 的特点,在理论上单节点的Nginx同时支持5W并发连接,而实际生产环境中,硬件基础到位再结合简单调优后确实能达到该数值。
原理:原本客户端是直接请求目标服务器,由目标服务器直接完成请求处理工作,但加入Nginx后,所有的请求会先经过Nginx,再由其进行分发到具体的服务器处理,处理完成后再返回Nginx,最后由Nginx将最终的响应结果返回给客户端。
二、Nginx环境搭建
window环境安装nginx
01、下载
在nginx的官网地址进行下载,其官网地址如下所示:
点击当前最新版本nginx1.19.6版本链接,然后跳转至如下Linux和Windows操作系统下的1.19.6版本的nginx下载地址
我们需要在windows环境安装nginx,因此单击“nginx/Windows-1.19.6”,然后如下图所示,在浏览器窗口底部出现nginx下载进度小页签显示,等待nginx下载完毕。
02、安装
解压缩下载文件nginx-1.19.6.zip。将解压缩文件nginx-1.19.6剪切到非系统盘。
如下所示,是nginx的目录结构,nginx.exe是nginx的启动工具,nginx的配置文件在conf目录下,logs目录下存放的是nginx的日志文件。
03、启动
启动方式很多,可以双击nginx解压目录下的nginx.exe启动nginx,出现一闪而过的窗口,是正常的,表示nginx服务器已经启动;
也可以在cmd命令窗口输入命令nginx,使用命令到达nginx的加压缩后的目录,然后输入nginx命令,如下所示:
在浏览器地址框输入地址:
- http://localhost:80
- 或者http://127.0.0.1:80
- 或者http://localhost
- 或者http://127.0.0.1
然后浏览器出现如下信息,说明nginx启动成功
04、配置
(1)修改端口号
conf目录下的nginx.conf,默认配置的nginx监听的端口为80,如果80端口被占用可以修改为未被占用的端口即可。
注意:
- 检查80端口是否被占用的命令是:netstat -ano | findstr “80”
- 当我们修改了nginx的配置文件nginx.conf时,不需要关闭nginx后重新启动nginx,只需要执行重新启动nginx命令 nginx -s reload 即可让改动生效。
(2)配置静态资源
在解压缩的nginx目录下新建static目录,在该目录下拷贝粘贴一张图片资源1.jpg:
然后在nginx.conf配置文件中,root修改相对路径为static,如下所示:
然后执行命令 nginx -s reload 即可实现修改生效,然后在浏览器地址栏输入访问地址:http://localhost/1.jpg
05、停止
如果使用cmd命令窗口启动nginx,关闭cmd窗口是不能结束nginx进程的,可使用如下三种方法关闭nginx:
- 输入nginx命令
nginx -s stop (快速停止nginx) 或nginx -s quit(完整有序的停止nginx)。 - 使用taskkill
taskkill /f /t /im nginx.exe - 任务管理器中结束nginx任务
以上是windows环境下常用的下载、安装、启动、配置、停止等操作步骤。
Linux环境:
首先创建 Nginx
的目录并进入:
[xiaoming@localhost]# mkdir /soft && mkdir /soft/nginx/
[xiaoming@localhost]# cd /soft/nginx/
下载 Nginx
的安装包,可以通过 FTP
工具上传离线环境包,也可通过 wget
命令在线获取安装包:
[xiaoming@localhost]# wget https://nginx.org/download/nginx-1.21.6.tar.gz
没有 wget
命令的可通过 yum
命令安装:
[xiaoming@localhost]# yum -y install wget
解压 Nginx
的压缩包:
[xiaoming@localhost]# tar -xvzf nginx-1.21.6.tar.gz
下载并安装 Nginx
所需的依赖库和包:
[xiaoming@localhost]# yum install --downloadonly --downloaddir=/soft/nginx/ gcc-c++
[xiaoming@localhost]# yum install --downloadonly --downloaddir=/soft/nginx/ pcre pcre-devel4
[xiaoming@localhost]# yum install --downloadonly --downloaddir=/soft/nginx/ zlib zlib-devel
[xiaoming@localhost]# yum install --downloadonly --downloaddir=/soft/nginx/ openssl openssl-devel
也可以通过 yum
命令一键下载(推荐上面那种方式):
[xiaoming@localhost]# yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel
执行完成后,然后 ls
查看目录文件,会看一大堆依赖
紧接着通过 rpm
命令依次将依赖包一个个构建,或者通过如下指令一键安装所有依赖包:
[xiaoming@localhost]# rpm -ivh --nodeps *.rpm
进入解压后的 nginx
目录,然后执行 Nginx
的配置脚本,为后续的安装提前配置好环境,默认位于 /usr/local/nginx/
目录下(可自定义目录):
[xiaoming@localhost]# cd nginx-1.21.6
[xiaoming@localhost]# ./configure --prefix=/soft/nginx/
编译并安装 Nginx
:
[xiaoming@localhost]# make && make install
最后回到前面的 /soft/nginx/
目录,输入 ls
即可看见安装 nginx
完成后生成的文件。
修改安装后生成的 conf
目录下的 nginx.conf
配置文件:
[xiaoming@localhost]# vi conf/nginx.conf
修改端口号:listen 80;
修改IP地址:server_name 你当前机器的本地IP(线上配置域名);
制定配置文件并启动 Nginx
:
[xiaoming@localhost]# sbin/nginx -c conf/nginx.conf
[xiaoming@localhost]# ps aux | grep nginx
Nginx
其他操作命令:
sbin/nginx -t -c conf/nginx.conf # 检测配置文件是否正常
sbin/nginx -s reload -c conf/nginx.conf # 修改配置后平滑重启
sbin/nginx -s quit # 优雅关闭Nginx,会在执行完当前的任务后再退出
sbin/nginx -s stop # 强制终止Nginx,不管当前是否有任务在执行
开放 80
端口,并更新防火墙:
[root@localhost]# firewall-cmd --zone=public --add-port=80/tcp --permanent
[root@localhost]# firewall-cmd --reload
[root@localhost]# firewall-cmd --zone=public --list-ports
在 Windows/Mac
的浏览器中,直接输入刚刚配置的 IP
地址访问 Nginx
三、Nginx反向代理-负载均衡
再简单修改一下nginx.conf的配置即可:
upstream nginx_boot{
# 30s内检查心跳发送两次包,未回复就代表该机器宕机,请求分发权重比为1:2
server 192.168.0.000:8080 weight=100 max_fails=2 fail_timeout=30s;
server 192.168.0.000:8090 weight=200 max_fails=2 fail_timeout=30s;
# 这里的IP请配置成你WEB服务所在的机器IP
}
server {
location / {
root html;
# 配置一下index的地址,最后加上index.ftl。
index index.html index.htm index.jsp index.ftl;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 请求交给名为nginx_boot的upstream上
proxy_pass http://nginx_boot;
}
}
至此,所有的前提工作准备就绪,紧接着再启动Nginx,然后再启动两个web服务,第一个WEB服务启动时,在application.properties配置文件中,将端口号改为8080,第二个WEB服务启动时,将其端口号改为8090
Nginx请求分发原理:
客户端发出的请求192.168.12.129最终会转变为:http://192.168.12.129:80/,然后再向目标IP发起请求,流程如下:
- 由于Nginx监听了192.168.12.129的80端口,所以最终该请求会找到Nginx进程;
- Nginx首先会根据配置的location规则进行匹配,根据客户端的请求路径 /,会定位到location /{}规则;
- 然后根据该location中配置的proxy_pass会再找到名为nginx_boot的upstream;
- 最后根据upstream中的配置信息,将请求转发到运行WEB服务的机器处理,由于配置了多个WEB服务,且配置了权重值,因此Nginx会依次根据权重比分发请求。
四、Nginx动静分离
动静分离应该是听的次数较多的性能优化方案,那先思考一个问题: 为什么需要做动静分离呢?它带来的好处是什么?
其实这个问题也并不难回答,当你搞懂了网站的本质后,自然就理解了动静分离的重要性。先来以淘宝为例分析看看: 当浏览器输入www.taobao.com
访问淘宝首页时,打开开发者调试工具可以很明显的看到,首页加载会出现100+的请求数,而正常项目开发时,静态资源一般会放入到resources/static/目录下:
在项目上线部署时,这些静态资源会一起打成包,那此时思考一个问题: 假设淘宝也是这样干的,那么首页加载时的请求最终会去到哪儿被处理?
答案毋庸置疑,首页100+的所有请求都会来到部署WEB服务的机器处理,那则代表着一个客户端请求淘宝首页,就会对后端服务器造成100+的并发请求。毫无疑问,这对于后端服务器的压力是尤为巨大的。
但此时不妨分析看看,首页100+的请求中,是不是至少有60+是属于 .js、.css、 .html、.jpg.....这类静态资源的请求呢?答案是Yes。 既然有这么多请求属于静态的,这些资源大概率情况下,长时间也不会出现变动,那为何还要让这些请求到后端再处理呢?能不能在此之前就提前处理掉?当然OK,因此经过分析之后能够明确一点:做了动静分离之后,至少能够让后端服务减少一半以上的并发量。到此时大家应该明白了动静分离能够带来的性能收益究竟有多大。
先在部署Nginx的机器,Nginx目录下创建一个目录static_resources:
mkdir static_resources
将项目中所有的静态资源全部拷贝到该目录下,而后将项目中的静态资源移除重新打包。
稍微修改一下nginx.conf的配置,增加一条location匹配规则:
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css){
root /soft/nginx/static_resources;
expires 7d;
}
然后照常启动nginx和移除了静态资源的WEB服务,你会发现原本的样式、js效果、图片等依旧有效
最后解读一下那条location规则:
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)
~
代表匹配时区分大小写.*
代表任意字符都可以出现零次或多次,即资源名不限制\.
代表匹配后缀分隔符.(html|...|css)
代表匹配括号里所有静态资源类型
综上所述,简单一句话概述:该配置表示匹配以.html.css为后缀的所有资源请求。
「最后提一嘴,也可以将静态资源上传到文件服务器中,然后location中配置一个新的upstream指向。」
五、通过Nginx实现前后分离调试
现在很多项目都是前后端分离,在前端与后端不是一个人开发,或者本身并非相同的项目。以前项目较小时,前端的资源文件和后台代码都是放在一块,进行 调试基本上都是启动后台服务就可以进行前端访问。但随着前端技术的成熟与庞大,更多的项目都有一套完整的开发工具与环境,而前端的项目往往都会有一套比较完整的体系,不可能将其拷贝到后台的模块中进行访问,这样调试起来非常不方便,同时会有很多依赖的环境无法满足。
现在可以通过nginx去实现前后端分离时,前端代码对后台的访问。在没有nginx时,我们可能会将前端代码部署到一个类似于apache的服务器中,通过配置端口访问,比如http://localhost:8080进行访问,而后台代码又要启动,此时不可能使用相同的端口,比如8082,那么在前台调用后台接口时,由于ip相同端口不同,则存在跨域问题。
通过nginx配置:
server{
listen 80;
server_name localhost;
location / {
root D:/file/front-proj;#前端静态页面路径
index index.html index.htm;#默认起始页
}
location /api { #后台接口
proxy_pass http://localhost:8081/;
}
}
这样我们在前端调地址变成了:localhost/xxx,调用后台的接口变成了localhost/api/xxx
六、常用配置
upstream标签
upstream zlj_jhpt { ip_hash; //负载均衡策略:ip_hash,ip_url,轮询,权重,fails server XXXX.70:443 weight=1 max_fails=10 fail_timeout=120s; server XXXX.70:6443 weight=1 max_fails=10 fail_timeout=120s; #server XXXX.72:8080 weight=1 max_fails=10 fail_timeout=120s; keepalive 64; }
server标签
server { listen 7443 ssl;#监听的端口 server_name XXXX:7443;#监听ip及端口 ssl_certificate D:/zlj_ssl/_.XXXX_bundle.crt;#ssl证书 ssl_certificate_key D:/zlj_ssl/.XXXX_RSA.XXXX_RSA.key;#ssl证书 ssl_session_cache shared:SSL:1m; #所有工作进程之间共享缓存 ssl_session_timeout 5m; #ssl_ciphers HIGH:!aNULL:!MD5; ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; charset ISO-88509-1; #前端页面:https://XXXX:7443/zhejiang-social-assistance/zhejiang-social-assistance.html#/five-help/how-help #接口地址:https://XXXX:7443/zlj_jhpt/api/five-help/help-how-going/count #接口地址映射 location /api/ { proxy_pass https://XXXX:7443/zlj_jhpt/api/; proxy_set_header X-Real-IP $remote_addr; } #前端页面地址映射 location /zhejiang-social-assistance/ { root D:\working\yw_szzfdp\web; expires 12h; add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; } #静态资源反向代理配置,比如将项目中的图片放到nginx服务器上 location /stwx/happyCode/images { alias D:\zly_cache\stwx\happlyCode\images; expires 12h; add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; } #Tomcat项目映射及跨域问题解决 location /zlj_jhpt { proxy_pass https://zlj_jhpt; #写死一个的话配置:ip地址+端口号+项目名称 ;负载均衡的话就用upsteam标签 include proxy.conf; # 配置html以文件方式打开 if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' *; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' *; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; } } }
其他配置分析
#user nobody;
#worker_processes: CPU核心数,(双核4线程,可以设置为4,但是我这台服务器还有一个tomcat所以我配置3)
worker_processes 3;
#debug | info | notice | warn | error | crit
error_log logs/error.log warn;
pid logs/nginx.pid;
#worker_rlimit_nofile 65535;
#单个工作进程可以允许同时建立外部连接的数量
events {
worker_connections 8192;
}
http {
include mime.types;
default_type application/octet-stream;
fastcgi_intercept_errors on;
log_format main '"$upstream_addr" $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;
access_log off;
open_log_file_cache max=1000 inactive=20s min_uses=2 valid=1m;
server_names_hash_bucket_size 128;
large_client_header_buffers 4 64k;
client_header_buffer_size 32k;
client_body_buffer_size 5120k;
client_max_body_size 100m;
server_tokens off;
ignore_invalid_headers on;
recursive_error_pages on;
server_name_in_redirect off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_requests 3000;
keepalive_timeout 120;
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
autoindex off;
include gzip.conf;
map_hash_bucket_size 64;
#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 128k;
fastcgi_buffers 8 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
#upstream模块:配置所映射的服务器项目地址及端口号,5种负载均衡策略:轮询(默认),权重(weight),ip_haph,ip_url,fairs
upstream stwx {
ip_hash;
server XXXX.206:8080 weight=1 max_fails=10 fail_timeout=120s;
#server XXXX.72:8080 weight=1 max_fails=10 fail_timeout=120s;
keepalive 64;
}
upstream zlj_jhpt {
ip_hash;
#交换平台地址
server XXXX.70:443 weight=1 max_fails=10 fail_timeout=120s;
#server XXXX.70:8088 weight=1 max_fails=10 fail_timeout=120s;
#server XXXX.72:8080 weight=1 max_fails=10 fail_timeout=120s;
keepalive 64;
}
#server模块 配置监听的端口,一个server监听一个端口,配置客户端所访问的路径
server {
# 监听了7443端口号
listen 7443 ssl;
# 访问项目的ip地址及端口号
server_name XXXX:7443;
ssl_certificate D:/zlj_ssl/_.XXXX_bundle.crt;
ssl_certificate_key D:/zlj_ssl/.XXXX_RSA.XXXX_RSA.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
#ssl_ciphers HIGH:!aNULL:!MD5;
ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
charset ISO-88509-1;
# 访问项目根路径 比如:https://XXXX:7443/zlj_jhpt就访问到了XXXX.70:443的项目名称位zlj_jhpt的项目
location /zlj_jhpt {
proxy_pass https://zlj_jhpt;
include proxy.conf;
# 配置html以文件方式打开,解决跨域问题
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
location /st {
proxy_pass https://st;
include proxy.conf;
# 配置html以文件方式打开
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
}
server {
listen 80;
server_name localhost XXXX;
charset ISO-88509-1;
location /stwx {
proxy_pass http://stwx;
include proxy.conf;
}
location /nginxstatus {
stub_status on;
access_log on;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
error_page 404 /404.html;
}
server {
listen 80;
server_name localhost shzz.XXXX;
charset ISO-88509-1;
location /switch_stshzz {
proxy_pass http://switch_stshzz;
include proxy.conf;
}
location /nginxstatus {
stub_status on;
access_log on;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
error_page 404 /404.html;
}
server {
listen 8800;
server_name localhost XXXX.206;
return 301 http://XXXX:8089/st;
}
}