Nginx应该都不陌生,作为“上古时期”服务器四大件LNMP(Linux、Nginx、Mysql、PHP)之一,已经证明了它的强大之处,直到今天Nginx仍然有着相当强大的作用与价值。
那么Nginx能帮我们解决那些问题呢?
HTTP服务器:Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器。
反向代理:反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端。
负载均衡:负载均衡其意思就是分摊到多个操作单元上进行执行。
动静分离:把动态请求和静态请求分离开,合适的服务器处理相应的请求,使整个服务器系统的性能、效率更高。
在大概了解作用之后我们正式开始学习(Nginx安装不讲,百度上有各种教程)
反向代理
原理
开始反向代理之前先来说一下什么是正向代理。由于谷歌已经退出中国市场,所以所有的访问谷歌服务器的请求均会被防火墙拦截下来
像这样直接访问是拿不到响应的,这时候我们可以使用代理服务器。假设我们有一个代理服务器(proxy.com)做转发,将我们的所有请求以代理服务器发出,再将收到的响应返回用户,这便是正向代理
其实这就是VPN的工作原理,理论上VPN代理可以获取我们发出去的所有请求,所以VPN不可以随便使用,那些免费的VPN风险系数相当大。
正向代理知道了,那什么是反向代理呢?
反向代理的过程用户是无感知的,它不像正向代理那样需要用户选择代理服务器,反向代理是服务方自己的代理,暴露出去的是代理服务器地址,从而隐藏了真实的服务器地址,此外可以用来解决跨域问题,反向代理的过程大致如下
反向代理最常用的场景就是,你只有一个域名,指向一台主机,然后有两个服务跑在两个端口,我们都知道如果http地址不带端口号默认是80端口,要让这两个服务都跑在主域名下,不带端口号,此时就可以使用反向代理了,通过反向代理,将不同的二级域名映射到不同的端口号上
配置
准备工作
开始配置之前,我们要先准备一个运行的服务,简要的搭建一个node服务端程序,代码如下
运行这个脚本
如果对nginx配置不熟悉可以看一下后面的配置介绍
反代一
然后我们开始配置反向代理,我们的程序跑在9000端口,我们要直接访问ip地址(默认80端口)
server {
listen 80;
server_name 127.0.0.1;
location / {
# root html;
# index index.html index.htm;
proxy_pass http://127.0.0.1:9000;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
效果如下
反代二
在现在的开发中,后端一般都是使用微服务架构,不同的服务模块运行在不同的服务器(192.168.1.45、192.168.1.46)或者同一服务器的不同端口下(192.168.1.45:8080、192.168.1.45:8081),我们可以使用nginx反向代理来将不同的服务代理到统一域名的不同路径下(192.168.1.45/module1、192.168.1.45/module2)
我们需要将原来的node脚本复制一份,端口改为9001,然后运行起来。然后修改nginx.conf
server {
listen 80;
serve_rname 127.0.0.1
location ~ module1 {
proxy_pass http://127.0.0.1:9000;
}
location ~ module2 {
proxy_pass http://127.0.0.1:9001;
}
}
location配置规则
location [ = | ~ |
* | ^] uri {}
- =: 用于不含正则表达式的uri前,要求请求字符串与uri严格匹配,如果匹配成功,就停止继续向下搜索并立即处理该请求
- ~: 用于表示uri包含正则表达式,并且区分大小写
- ~*: 用于表示uri包含正则表达式,并且不区分大小写
- ^~: 用于不含正则表达式的uri前,要求Nginx服务器找到标识uri和请求字符串匹配度最高的location后,立即使用此location处理请求,而不再使用location块中的正则uri和请求字符串做匹配
- !: 对匹配结果取非
- 注意: 如果uri包含正则表达式,则必须要有
或者*标识。
此时我们分别访问module1和module2
反代三
如果是不同的应用,但我们想用同一个域名,这时候就需要使用二级域名,然后通过反向代理来指向不同的应用
这里我们需要使用域名,所以在host文件中添加host,文件路径如下(需要管理员权限)
添加如下两条记录
127.0.0.1 www.proxy.com
127.0.0.1 test.proxy.com
然后修改我们的nginx配置文件,依旧是指向我们之前的两个node服务,区别于的第二个案例的是这里要添加的是两个server,通过server_name来区分虚拟主机
server {
listen 80;
server_name www.proxy.com;
location / {
proxy_redirect off;
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_pass http://127.0.0.1:9000;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 80;
server_name test.proxy.com;
location / {
proxy_redirect off;
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_pass http://127.0.0.1:9001;
}
}
效果如下
负载均衡
原理
在没有配置负载均衡时我们的服务器网络架构是这样的
非常简单,就是接受用户请求然后处理返回,但是当用户量上去之后,一台服务器无法处理大量的请求,这时我们我们想让多台服务器来共同处理,这时就需要负载均衡,通过Nginx服务器分发到不同的服务器上,可以根据不同的服务器性能等依据来划分服务器处理的请求数量。
使用负载均衡后,我们的网络架构如下
使用负载均衡时,一般会使用到反向代理
思考题:使用负载均衡后,怎么保持数据库的一致性?
配置
这里依旧是使用前面反向代理的两个node程序,分别运行在9000和9001端口
在配置负载均衡时需要在http下,server同层级使用upstream
配置一个服务器列表然后命名,然后在location中添加反向代理的配置http://服务器列表名
upstream module {
server 127.0.0.1:9000;
server 127.0.0.1:9001;
}
server {
listen 80;
server_name 127.0.0.1;
location / {
proxy_redirect off;
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_pass http://module;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
重新应用配置之后去浏览器访问,可以看见服务器控制台日志如下
请求被平均分配到了两台服务器上,这其实是nginx负载均衡的默认策略——轮询,除此之外Nginx还有其他的负载均衡策略
- 轮询:默认,将请求按照请求时间平均分配到列表中的服务器上
- 权重:使用weight声明权重,权重和访问率成正比,使用权重来解决服务器之间性能不同的差异
- ip_hash:每个请求按访问ip的hash结果分配, 这样每个访客固定访问一个后端服务器,可以解诀session的问题
- fair:(需引入第三方插件)按后端服务器的响应时间来分配请求,响应时间短的优先分配
四种策略的声明模式如下
# 轮询
upstream module {
server 127.0.0.1:9000;
server 127.0.0.1:9001;
}
# 权重
upstream module {
server 127.0.0.1:9000 weight=2;
server 127.0.0.1:9001 weight=1;
}
# ip_hash
upstream module {
ip_hash;
server 127.0.0.1:9000;
server 127.0.0.1:9001;
}
# fair
upstream module {
fair;
server 127.0.0.1:9000;
server 127.0.0.1:9001;
}
动静分离
原理
为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速
度。降低原来单个服务器的压力。过程如下
配置
这里动静分离并不是简单地动态页面和静态页面的分离,而是动态请求和静态请求的分离。这里我们需要重新做一下准备,准备一个文件夹www用于存放静态资源,然后我们所有的请求进行分类,静态资源访问/asserts/xxx,动态请求走/api/xxx
location /api {
proxy_redirect off;
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_pass http://127.0.0.1:9000;
}
location /images/ {
root /Nginx/www/; # Window下要用绝对路径
autoindex on;
}
效果如下
注意:这里在配置location中的root时Windows要设置绝对路径,不然会404;在访问文件时查找路径为root+location+文件名
,如果不使用此种模式可以设置alias来替换root,在访问文件时就是alias+文件名
配置解析
Nginx的配置文件一共有三个大块
- 全局块:设置一些运行指令,例如
worker_processes
用来设置支持的并发数量 - events块:影响Nginx服务器与用户的网络连接,例如
worker_connections
用来设置最大连接数 - http(s)块:Nginx配置中最常用的块
- http全局块:包括文件引入、日志自定义、超时时间等等
- http server块:和虚拟主机有密切关系,一个server块就相当于一个虚拟主机。我们的配置工作主要集中在server块中
server详解
我们只对最常使用的server块配置项进行介绍,其他部分如有需要可以面向百度/Google
listen:监听的端口
server_name:主机名,一般是二级域名
location:路径中包含某个设定值就做相应的操作
proxy_pass:设置被代理服务器的端口或套接字,以及URL
将代理服务器收到的用户的信息传到真实服务器上
- 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状态 location /NginxStatus { stub_status on; access_log on; auth_basic "NginxStatus"; auth_basic_user_file conf/htpasswd; # 需要使用htpasswd生成密码文件 }
deny all;禁止访问匹配中的location