Nginx主要用于1. 静态资源服务器,2. 反向代理,3. 负载均衡,本文主要围绕这三块进行描述。
☀1.Nginx功能介绍
Nginx 是一款高性能的 http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师伊戈尔·西索夫(Igor Sysoev)所开发,官方测试 nginx 能够支支撑 5 万并发链接,并且 cpu、内存等资源消耗却非常低,运行非常稳定。
Nginx 应用场景:
1、http 服务器。Nginx 是一个 http 服务可以独立提供 http 服务。可以做网页静态服务器。
2、虚拟主机。可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机。
3、反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用 nginx 做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。
☀2.下载和安装
☀下载
学习所用相关工具:
修改主机的Host文件:SwitchHosts
☀安装
主要介绍nginx系统中的安装,windows系统,开箱即用。
☀环境准备:
(1)需要安装 gcc 的环境【此步省略】
1 | yum install gcc-c++ |
(2)第三方的开发包。
PCRE
PCRE(Perl Compatible Regular Expressions)是一个 Perl 库,包括 perl 兼容的正则表达式库。nginx 的 http 模块使用 pcre 来解析正则表达式,所以需要在 linux 上安装 pcre 库。
注:pcre-devel 是使用 pcre 开发的一个二次开发库。nginx 也需要此库。
1 | yum install -y pcre pcre-devel |
zlib
zlib 库提供了很多种压缩和解压缩的方式,nginx 使用 zlib 对 http 包的内容进行 gzip,所以需要在 linux 上安装 zlib 库。
1 | yum install -y zlib zlib-devel |
OpenSSL
OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及 SSL 协议,并提供丰富的应用程序供测试或其它目的使用。nginx 不仅支持 http 协议,还支持 https(即在 ssl 协议上传输 http),所以需要在 linux安装 openssl 库。
1 | yum install -y openssl openssl-devel |
☀步骤:
第一步:上传
把 nginx 的源码包nginx-1.8.0.tar.gz上传到 linux 系统
第二步:解压缩
1 | tar zxvf nginx-1.8.0.tar.gz |
第三步:创建配置文件
进入nginx-1.8.0目录 使用 configure 命令创建一 makeFile 文件。
1 | ./configure \ |
执行后可以看到Makefile文件
1 | ---- 知识点小贴士 ---- |
第四步:编译
1 | make |
第五步:安装
1 | make install |
第六步:启动
注意:启动nginx 之前,上边将临时文件目录指定为/var/temp/nginx/client, 需要在/var 下创建此 目录
1 | mkdir /var/temp/nginx/client -p |
进入到Nginx目录下的sbin目录
1 | cd /usr/local/ngiux/sbin |
输入命令启动Nginx
1 | ./nginx |
启动后查看进程
1 | ps aux|grep nginx |
地址栏输入虚拟机的IP即可访问(默认为80端口)
关闭 nginx:
1 | ./nginx -s stop |
或者
1 | ./nginx -s quit |
重启 nginx:
1、先关闭后启动。
2、执行重启指令,刷新配置文件:
1 | ./nginx -s reload |
☀3.配置介绍
nginx.conf
配置文件所在路径:在nginx安装目录的conf目录下。
☀server
server{}
表示代理的某个服务,下方的配置都在这个server括号中。
☀listen
listen 80
表示服务所监听的端口号
☀server_name
server_name
有匹配规则,与浏览器上输入的域名匹配。优先匹配最精确的。
举例:
- ==localhost== 指向本机
- ==www.tangyefei. com== 域名,最终指向本机
☀location
location
匹配规则,在域名ip和端口号后的地址匹配,/表示全部匹配。
==注意:==路径的间隔都使用/
。
location匹配模式及顺序
表示 | 描述 |
---|---|
location = /uri地址 | =开头表示精确匹配,只有完全匹配上才能生效。 |
location ^~ /uri地址 | ^~ 开头对URL路径进行前缀匹配,并且在正则之前。 |
location ~ 正则表达式 | ~开头表示区分大小写的正则匹配。 |
location ~* 正则表达式 | ~*开头表示不区分大小写的正则匹配。 |
location /uri地址 | 不带任何修饰符,也表示前缀匹配,但是在正则匹配之后。 |
location / | 通用匹配,拦截所有,但是优先级最低,只有前面都没有被拦截的情况下,才会被拦截到这里。 |
☀root
root
在location中配置
表示匹配成功后进入主机的目录
相对路径以niginx安装位置为基础,通常是绝对路径。
==注意:路径都使用/
来间隔文件夹。root 路径最后不能为/
结束。==
匹配成功查找资源时,root+地址中的location。
☀index
index
在location中配置 在location中配置
默认打开的页面 如果地址匹配成功,并且进入的是某个目录,而不是具体文件,则打开root+location地址中的index指定的文件。
☀proxy_pass
proxy_pass
反向代理配置 在location中配置
proxy_pass: 127.0.0.1可以换成任何一个通的内网地址,这个ip表示你要真实访问的tomcat所在的位置,proxy_pass的值就表示你真正访问的域名是什么(站在公网服务器角度来说)。
真正要访问并且代理的服务器地址。
可配置方式:
ip+端口或者域名(有默认端口或者映射的端口)
ip+端口+某个路径
一般配置了proxy_pass就不需要配置root了。root指向本机资源。proxy_pass指向代理服务器。
最终访问的方式:
proxy_pass+location
☀proxy_redirect off
在location中配置
☀proxy_set_header
在location中配置
proxy_set_header Host $host
proxy_set_header X-Real-IP $remote_addr
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
☀proxy_connect_timeout
nginx向tomcat发起连接,即第一次握手等待tomcat回应的超时时间,tomcat的这次回应只是说明能正常连接,并没有响应具体请求的内容。
理解为确认连接的时间。
proxy_connect_timeout 3s;
☀proxy_send_timeout
nginx将请求发送给tomcat的超时时间,应该是确认能正常连接之后向tomcat发送真正的业务请求。
理解为建立了连接口,发送请求的时间。
proxy_send_timeout 3s;
☀proxy_read_timeout
tomcat接受到真正业务请求之后,nginx等待tomcat响应具体请求的内容的超时时间。差不多可以理解tomcat处理具体请求时间的最大值,也就是tomcat必须在这个时间内做完业务逻辑处理。
理解为发送请求成功后,处理和响应的时间。
proxy_read_timeout 5s;
☀proxy_cookie_path
作用:将服务器返回的 Set-Cookie
中的path进行修改。
应用场景:转载自:https://www.jb51.net/article/187898.htm
背景
一同事求援:后台系统的登录成功了,但不能成功登进系统,仍然跳转到登录页,但同一套代码另一个环境却没有问题。
经了解,他对同一个项目使用tomcat部署了两个环境,一个在开发服务器上,一个在他本机,两个环境代码配置完全相同。两边通过同一个nginx进行反向代理,nginx配置大致如下,
1 | location /health/ { |
一个反向代理到开发环境,一个反向代理到本机服务。
定位
既然代码配置完全相同,那么问题很大可能就出现在nginx的反向代理上。
因为两边location路径不同(即浏览器路径不同),但是反向代理的服务端路径却相同,结合session的基本原理,如下图,
- 当浏览器第一次打开页面时,服务端会为这次会话创建一个session,并将session id通过response的header传递给浏览器,header一般为 Set-Cookie: JSESSIONID=xxxxx; Path=xxxx
- 浏览器接收到响应后,如果header Set-Cookie 中path的值与浏览器地址路径匹配,则将该header值存于浏览器的Cookie中
- 浏览器在下次请求服务器时,将Cookie中的JSESSIONID值通过request的header上报给服务端,header一般为 Cookie: JSESSIONID=xxxx;
- 服务端可通过该JSESSIONID来定位到对应的session
nginx反向代理按这种方式配置时
1 | location /health-dev/ { |
浏览器访问 http://www.domian.com/health-dev
时,服务端返回的 Set-Cookie
的 Path 值为 /health
(因为中间有反向代理,服务端并不知道代理前的路径是啥,是按最终请求服务端的路径设置),如图
因为浏览器访问地址的路径 /health-dev
与 Set-Cookie
的 Path /health
不匹配,所以浏览器并不会将其值存入Cookie中,如图
因此在下次请求服务器时,浏览器无法设置request Cookie
header的 JSESSIONID
值,服务器无法定位到对应的session,因此会将其当做第一次请求,创建一个新的session,如此反复,因此就算你登录认证通过了,但服务器返回的登录凭证(JSESSIONID)浏览器不会保存,并在下次请求时携带,导致服务器认为你是一个新的请求,当然就会又跳到登录页面了。
解决
nginx有一个命令 proxy_cookie_path
(参考: proxy_cookie_path )可将服务器返回的 Set-Cookie
中的path进行修改,格式为 proxy_cookie_path 原路径 目标路径
,我们在配置中添加 proxy_cookie_path
如下。
1 | location /health-dev/ { |
重启nginx,问题解决。
☀proxy_cookie_domain
作用:修改response中的,set-cookie的domain属性,可以控制cookie的生效域名目标
1 | location /api { |
proxy_cookie_domain的作用是单向的,并不是双向转换的。
浏览器在发送请求的时候,会在request header中带上cookie项(有内容的话),此时的cookie是一个字符串,一个key=value并用分号分割的字符串,
其中并不包含任何域名信息。这是因为浏览器在设置cookie选项的时候,所选取的内容都是缓存中接口域名下的。然后request的只要请求发送出去之后,cookie中有关domain信息其实是不存在的,它只是一个普通的字符串,随便proxy_pass到任何位置,都会正常携带下去。因此在前端到后端的request的过程中,proxy_cookie_domain是没用的
而server端在做响应的时候,通过set-cookie的domain属性,可以控制cookie的生效域名目标,做到诸如二级域名cookie分离等等,如果前端接收到的set-cookie的domain和当前域名不一致,或者一级域名不一致(二级域名可以共享一级域名下的cookie),这个cookie在后续的通信中就是无效的,所以这里才需要去做domain的转换,也就是说response中set-cookie的domain转换才是有意义的,这也正是proxy_cookie_domain的作用所在。
当response的set-cookie中domain不去设置时,cookie顺利传入浏览器中,浏览器会自动设置这个cookie的生效域名为当前域名。
☀add_header
配置在location中。
add_header 是 headers 模块中定义的一个指令,顾名思义就是用来添加 http 响应头的。但请注意他只是「添加」而已,并不是重写。所以如果已经存在某个头,再使用 add_header 就会出问题。而且在低版本的 nginx 中 add_header 还不支持在错误页面中使用。
☀rewrite //TODO
☀return
配置在location中
设置响应的状态信息
1 | location = /b { |
☀default_type
配置在server中。
全局设置response响应的Content-Type参数
1 | default_type 'text/plain'; |
☀upstram XXX{}
与server{}同级配置
表示负载均衡的配置,XXX
轮巡算法默认
权重算法在server中添加 weight = X
ip绑定算法,添加ip_hash
☀server
负载均衡服务器,上游的服务器,通常格式是Ip:Port
☀ip_hash
表示使用负载均衡的ip绑定算法。
☀4.反向代理
==域名可以解析为IP+端口==,猜测如果指向本机,默认端口为80。
**实质:**个人理解反向代理就是nginx拦截动态请求之后转发给某个tomcat。这个在==集群==和==分布式==都可以使用这个来进行配置转发。
作用: 隐藏真实的访问ip地址。我们可以看到流程图中我们访问的最多也就是公网的ip,但是具体tomcat在那个ip是不知道的,这样就能减少tomcat被攻击,提高了服务器的安全性。
☀5.动静分离
☀概念
☀静态资源:
静态资源: html、js、css、图片、音乐、视频等。当用户多次访问这个资源,资源的源代码永远不会改变或者很少改变的资源。
☀动态资源:
动态资源:当用户多次访问这个资源,资源的源代码可能会发生改变。
> 我的理解就是我们所说的接口。这里需要注意的是:themleaf、freemark这些模板引擎的html不是静态资源而应该属于动态资源(个人认为)。
☀动静分离:
动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,简单的概括是:动态文件与静态文件的分离。动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路
☀伪静态
伪静态:网站如果想被搜索引擎搜素到,动态页面静态技术freemarker等模版引擎技术
☀动静分离原因:
- 在我们的软件开发中,有些请求是需要后台处理的(如:.jsp,.do等等),有些请求是不需要经过后台处理的(如:css、html、jpg、js等等文件),这些不需要经过后台处理的文件称为静态文件,否则动态文件。因此我们后台处理忽略静态文件。这会有人又说那我后台忽略静态文件不就完了吗。==当然这是可以的,但是这样后台的请求次数就明显增多了。==在我们对资源的响应速度有要求的时候,我们应该使用这种动静分离的策略去解决。
- 动静分离将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问。这里我们将静态资源放到nginx中,动态资源转发到tomcat服务器中。
- 因此,动态资源转发到tomcat服务器我们就使用到了前面讲到的反向代理了。
之前项目中需要用到百度地图,由于项目的特殊环境,所以需要下载百度的离线地图。我们知道,地图的展示其实就是一张张地图的图片展示,我们在网页上浏览查找位置的时候,其实都是在发送图片请求。这些图片请求相对于jsp,servlet来说就是所谓的静态资源,当然服务中的静态资源不仅仅只是图片,像页面样式css文件,js脚本文件这些都可以看着是静态资源。==tomcat既可以静态资源也可以处理动态资源。但是单节点的tomcat本身处理请求的资源是有限的,如果项目中的tomcat既处理动态请求有要处理大量的静态资源。显然是不合理的,也就是会遇到tomcat的性能瓶颈问题,对于静态资源的处理我们有更好的服务器像Nginx,Apache.他们处理静态资源的能力比Tomcat强很多==,那么我们能不能对请求进行分工呢?静态资源的请求由Nginx来处理,像jsp我们交给tomcat来处理。这样也能减轻tomcat的处理压力。
==个人理解:==
Tomcat也可以处理静态资源,动静分离也可以分两个Tomcat减缓访问压力。Nginx处理静态资源能力更加优秀。
总结:
1.提高用户访问静态代码的速度,降低对后台应用访问,降低后台压力。
2.总体提高资源的响应速度。
☀实现动静分离的两种方法:
☀通过不同域名来拦截
动态请求和静态请求使用不同的域名。比如所有的静态资源都使用static.tuesdayma.com域名来访问,所有的接口都使用www.tuesdayma.com来请求。
图片理解:
==优点:==扩展性比较强,静态资源是什么都可以。
==缺点:==存在跨域问题,所有的html全靠ajax请求来请求接口,后端域名和前端不一致导致跨域问题,实际是因为配置了两个server导致跨域。
☀location来拦截
只配置一个server,然后配置两个location,一个通过正则表达式拦截静态资源,还有一个拦截.do结尾的接口请求。
==优点:==不存在跨域问题。
==缺点:==扩展性太差,静态资源的类型不可确定,每增加一种类型都需要重新修改配置文件并且重启nginx。
☀6.负载均衡
☀原因与作用:
为了解决高并发问题,负载均衡服务器拦截所有的请求,采用负载均衡算法,分配到不同的tomcat上。
作用: 减少单台tomcat的压力
☀三种基本的负载均衡算法:
轮询
nginx==默认==的负载均衡算法,简单来说就是从上到下按顺序轮流(127.0.0.1:8082轮完就轮到127.0.0.1:8081,127.0.0.1:8081轮完就轮到127.0.0.1:8082)。注意:mzd的地方需要保持一致。。。
1
2
3
4upstream mzd {
server 127.0.0.1:8082;
server 127.0.0.1:8081;
}权重
我的理解就是哪台服务器配置好就多轮几次,或者你就想某个服务器多轮几次。简单来说就是轮到次数的比例,数字越大表示轮到的概率越大。(个人认为weight都设置为1的时候和轮询没什么区别)
1
2
3
4upstream mzd {
server 127.0.0.1:8082 weight=2;
server 127.0.0.1:8081 weight=3;
}ip绑定
我的理解就是你第一次访问的时候,nginx会根据你的ip通过哈希算法,算出某个值,然后取分配哪个tomcat,当你第二次访问,第三次访问。。。之后的任何一次访问都是去请求那个第一次访问的tomcat。
1
2
3
4
5upstream mzd {
server 127.0.0.1:8082 ;
server 127.0.0.1:8081 ;
ip_hash;
}
☀7.故障转移机制
在负载均衡下存在故障转移机制
其实nginx有默认故障转移机制的,但是很慢(本人测了一下,默认好像是要60秒左右,一分钟后就有自动发送到其他tomcat上去了
可通过手工配置超时时间:
proxy_connect_timeout
proxy_send_timeout
proxy_read_timeout
☀8.命令
☀Windows
启动
CMD切换到nginx.exe目录下:start nginx
nginx.exe
停止
nginx.exe -s stop
nginx.exe -s quitstop是快速停止nginx,可能并不保存相关信息;quit是完整有序的停止nginx,并保存相关信息。
==注意:==使用停止命令的时候,不能修改nginx.conf文件,在原启动时配置的文件基础上停止。否则可能会报d错。nginx: [error] CreateFile()
测试配置文件是否有效
nginx.exe -t重新载入
nginx.exe -s reload当配置信息修改,需要重新载入这些配置时使用此命令。
重新打开日志文件
nginx.exe -s reopen查看nginx版本
nginx -v
☀Linux
1.启动
cd 到nginx安装路径的sbin目录下
./nginx
2.测试配置文件是否有效
./nginx -t
3.重启nginx
./nginx -s reload
4.查看nginx版本
./nginx -v
☀9.配置案例:
☀1.静态资源服务器
☀root相对路径
1 | server { |
☀域名匹配访问不同资源
1 | server { |
☀2.反向代理
1 | server { |
☀3.动静分离
☀通过不同域名来拦截
1 | #动态请求拦截 |
☀4.负载均衡
☀1.轮询
1 | upstream mzd { |
本机nginx的负载:
1 | upstream tw{ |
☀2.权重
1 | upstream mzd { |
☀3.ip绑定
1 | upstream mzd { |
☀5.配置超时
1 | server { |
☀6.Nginx匹配路径部分替换
nginx 配置 proxy_pass时可以实现URL路径的部分替换。
1.proxy_pass的目标地址,默认不带/,表示只代理域名,url和querystring部分不会变(把请求的path拼接到proxy_pass目标域名之后作为代理的URL)
2.如果在目标地址后增加/,则表示把path中location匹配成功的部分剪切掉之后再拼接到proxy_pass目标地址
1 | server { |
比如请求 /abc/b.html
如上两个匹配成功后,实际代理的目标url分别是
http://server_url/abc/b.html (把/abc/b.html拼接到http://server_url之后)
http://server_url/b.html (把/abc/b.html的/abc去掉之后,拼接到http://server_url/之后)
☀7.Nginx跨域设置
解决场景:
静态资源服务器与nginx服务器不是同一台,nginx代理的服务器,未设置跨域。(简称非同源下的nginx代理)
同源下的代理就不需要设置跨域了。
个人理解可以解决,服务器端设置CORS的cookie缺陷。服务支持多源跨域访问,同时支持cookie。其实就是将服务器设置的CORS转移到代理服务器,变得灵活起来。
一句话:同源下的代理需不要设置跨域,非同源下的代理需要设置跨域。
1 | add_header 'Access-Control-Allow-Origin' '*'; |
生效的方案:
1 | if ($request_method = 'OPTIONS') { |
☀10.常见报错
nginx -s reload 时报错
Nginx错误:nginx: [error] OpenEvent(“Global\ngx_reload_6252”) failed (2: The system cannot find the file specified)
错误原因:Nginx 尚未启动导致,执行 start nginx 命令开启Nginx
访问时报错
ginx1" failed (123: The filename, directory name, or volume label syntax is incorrect), client: 127.0.0.1, server: 127.0.0.1, request: “GET / HTTP/1.0”, host: “tw”
2020/10/28 21:34:14 [crit] 18412#15040: *26 CreateFile() "D:\Data\Html错误原因:配置root路径使用了 \