Nginx正向/反向代理与负载均衡策略
- 1、Nginx
- 1.1、什么是Nginx
- 1.2、Nignx的应用场景
- 1.3、Nginx安装-Windows
- 1.4、Nginx安装-Linux
- 2、Nginx基础使用
- 2.1、目录结构
- 2.2、基本运行原理
- 2.3、Nginx配置文件
- 2.4、服务配置
- 2.5、泛域名解析
- 3、代理
- 3.1、具体配置
- 3.2、基于反向代理的负载均衡
- 4、负载均衡策略
- 4.1、轮询
- 4.2、动静分离
- 4.3、URLRewrite
- 5、防盗链
- 5.1、防盗链照片
- 5.2、使用curl测试
- 6、高可用
Nginx是一款高性能的http服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。官方测试nginx能够支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。
cmd
窗口,启动nginxlocalhost:80
,看到如下页面即表示启动成功注意:
- 如果使用cmd命令窗口启动nginx, 关闭cmd窗口是不能结束nginx进程的。
- 下述命令请在解压目录路径下进入 cmd 命令行执行
nginx -v # 查看nginx的版本号
nginx -s stop # 快速停止或关闭nginx
nginx -s quit # 正常停止或关闭nginx
nginx -s reload # 配置文件nginx.conf修改重载命令
nginx的配置文件是conf目录下的
nginx.conf
,默认配置的nginx监听的端口为80,如果80端口被占用可以修改为未被占用的端口即可。
当我们修改了nginx的配置文件nginx.conf 时,不需要关闭nginx后重新启动nginx,只需要执行命令 nginx -s reload
即可让改动生效。
在Linux下安装Nginx,需要先安装4个依赖环境,分别是 gcc、pcre、zlib、openssl
yum -y install gcc-c++
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y openssl openssl-devel
.tar.gz
安装包/root
,解压# 1.解压nginx安装包
tar -zxvf nginx-1.24.0.tar.gz
# 2.配置configure
./configure --prefix=/usr/local/nginx # --prefix=/usr/local/nginx 指安装路径
# 3.执行make
make
# 4.执行 make install
make install
# 5. 找nginx目录
whereis nginx
./nginx # 启动nginx
./nginx -s stop # 停止nginx
./nginx -s quit # 安全退出
./nginx -s reload # 重新加载配置文件
ps aux|grep nginx # 查看nginx进程
若 yum 下载太慢,可以尝试换源:https://blog.csdn.net/qq_45773650/article/details/108326429
- wget:无法解析主机地址:https://blog.csdn.net/weixin_45359497/article/details/119104646
根目录/www/server
里面查看nginx进程:
ps aux|grep nginx
宝塔安装的 nginx 是开机自启的,我们只需要在 www/server/nginx/conf/nginx.conf
里面写入:
server {
listen 80;
#
server_name 192.168.6.136;
location / {
root html;
index index.html index.htm;
# 万一访问404,则添加下面代码
# try_files $uri $uri/ /index.html;
}
}
更新nginx配置:./nginx -s reload
, 之后访问:http://192.168.6.136
如果加了上述代码后仍然访问404,可以去看一下
html/index.html
的代码,不知道为何我的代码就是404代码,所以显示404,搞得我排查了好久,天杀的!
- 扩展:检查 nginx 的配置文件是否正确
nginx -t
进入Nginx的主目录我们可以看到这些文件夹:
# 用来存放配置的文件相关
conf
# 用来存放静态文件的默认目录 html、css等
html
# 日志
logs
# nginx 的主程序
sbin
# 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器
uwsgi_temp
# 以下几个文件夹在刚安装后是没有的,主要用来存放运行过程中的临时文件
client_body_temp
fastcgi_temp
proxy_temp
scgi_temp
[root@localhost ~]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp # POST 大文件暂存目录
├── conf # Nginx所有配置文件的目录
│ ├── fastcgi.conf # fastcgi相关参数的配置文件
│ ├── fastcgi.conf.default # fastcgi.conf的原始备份文件
│ ├── fastcgi_params # fastcgi的参数文件
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types # 媒体类型
│ ├── mime.types.default
│ ├── nginx.conf #这是Nginx默认的主配置文件,日常使用和修改的文件
│ ├── nginx.conf.default
│ ├── scgi_params # scgi相关参数文件
│ ├── scgi_params.default
│ ├── uwsgi_params # uwsgi相关参数文件
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp # fastcgi临时数据目录
├── html # Nginx默认站点目录
│ ├── 50x.html # 错误页面优雅替代显示文件,例如出现502错误时会调用此页面
│ └── index.html # 默认的首页文件
├── logs # Nginx日志目录
│ ├── access.log # 访问日志文件
│ ├── error.log # 错误日志文件
│ └── nginx.pid # pid文件,Nginx进程启动后,会把所有进程的ID号写到此文件
├── proxy_temp # 临时目录
├── sbin # Nginx 可执行文件目录
│ └── nginx # Nginx 二进制可执行程序
├── scgi_temp # 临时目录
└── uwsgi_temp # 临时目录
终端PC机在发起请求http://192.168.44.101/index.html
时,Nginx是怎么处理的呢?
Nginx 首先运行/sbin/nginx
可执行文件,开启 Master 进程进行读取并检验配置文件 /conf/nginx.conf
,如果没有错误则会开启一个子进程Worker
进行响应请求。
nginx.conf
,我们可以直接使用Xftp的右键用记事本打开
,也可以下载到本地用编辑器打开配置文件分为三个大模块:
# 全局配置
# 设置worker进程的用户,默认为 nobody
user nobody;
# worker进程工作数设置,一般来说CPU有几个,就设置几个,或者设置为N-1也行,默认为1
worker_processes 1;
# nginx 日志级别: debug | info | notice | warn | error | crit | alert | emerg
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
# 设置 nginx 进程pid
pid logs/nginx.pid;
# 事件:包括最大连接数、线程数等等
events {
# 默认使用epoll
use epoll;
# 每个worker允许连接的客户端最大连接数
worker_connections 1024;
}
# http配置
http {
# http的全局配置
# include 引入外部配置,提高可读性,避免单个配置文件过大
include mime.types;
default_type application/octet-stream;
# 设定日志格式,main为定义的格式名称,如此 access_log 就可以直接使用这个变量了
# $remote_addr:客户端ip $remote_user:远程客户端用户名
# $time_local:时间和时区 $request:请求的url以及method
# $status:响应状态码 $body_bytes_sent:响应客户端内容字节数
# $http_referer:记录用户从哪个链接跳转过来的
# $http_user_agent:用户所使用的代理,一般来时都是浏览器
# $http_x_forwarded_for:通过代理服务器来记录客户端的ip
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使用高效文件传输,提升传输性能。
# 启用后才能使用tcp_nopush,是指当数据表累积一定大小后才发送,提高了效率
# 对于普通应用,必须设为on.如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度。
sendfile on;
tcp_nopush on;
# keepalive_timeout设置客户端与服务端请求的超时时间,保证客户端多次请求的时候不会重复建立新的连接,节约资源损耗。
keepalive_timeout 65;
# gzip启用压缩,html/js/css压缩后传输会更快
gzip on;
# 服务配置
server {
# listen 监听端口
listen 80;
# 服务器名称,默认为localhost
server_name localhost;
#访问地址 / 表示根目录
location / {
# root 表示访问的文件夹,其中默认是html文件夹,可以修改成自己的文件夹
root html;
# index 访问页面,默认访问页面
index index.html index.htm;
}
# 错误页面的配置
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
# 服务配置(虚拟主机配置)
server {
# listen 监听端口
listen 80;
# 服务器名称,默认为localhost
server_name localhost;
#访问地址 / 表示根目录
location / {
# root 表示访问的文件夹,其中默认是html文件夹,可以修改成自己的文件夹
root html;
# index 访问页面,默认访问页面
index index.html index.htm;
}
# 错误页面的配置
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
举个例子来说,一台服务器ip地址为192.168.6.136,有两个域名和对应的空间在这台服务器上,使用的都是192.168.6.136的80端口来提供服务。如果只是简单的将两个域名A和B的域名记录解析到这个ip地址,那么web服务器在收到任何请求时反馈的都会是同一个网站的信息,这显然达不到要求。
接下来我们使用主机头绑定域名A和B到他们对应的空间文件夹C和D。当含有域名A的web请求信息到达192.168.6.136时,web服务器将执行它对应的空间C中的首页文件,并返回给客户端,含有域名B的web请求信息同理,web服务器将执行它对应的空间D中的首页文件,并返回给客户端
server_name
匹配规则:需要注意的是server_name
匹配分先后顺序,写在前面的匹配上就不会继续往下匹配了。
完整匹配:我们可以在同一servername中匹配多个域名
server_name www.qindalin.com nav.qindalin.com;
通配符匹配:精确匹配的优先级大于通配符匹配和正则匹配
server_name *.qindalin.com
通配符结束匹配
server_name www.qindalin.*
正则匹配
server_name ~^[0-9]+\.qindalin\.com$;
- 正则匹配格式,必须以
~
开头,比如server_name ~^www\d+\.example\.net$;
- 如果开头没有
~
,则nginx认为是精确匹配
特殊匹配格式:
server_name ""; # 匹配Host请求头不存在的情况。
匹配顺序:
*
号开头的最长通配符名称,例如 *.example.org
*
号结尾的最长通配符名称,例如 mail.*
示例:
nginx.conf
加入如下配置# 虚拟主机的配置
server {
listen 81;
server_name kuang.study.cn;
location / {
root /www/kuang/study81;
index index.html;
}
}
server {
listen 82;
server_name kuang.study.cn;
location / {
root /www/kuang/study82;
index index.html;
}
}
firewall-cmd --add-port=81/tcp --permanent
firewall-cmd --add-port=82/tcp --permanent
www/kuang/
创建 study81、study82
文件夹并分别创建 index.html
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Welcome to nginx!title>
<style>
style>
head>
<body>
<h1>这是 Study81 页面!h1>
body>
html>
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Welcome to nginx!title>
<style>
style>
head>
<body>
<h1>这是 Study82 页面!h1>
body>
html>
在XShell中刷新配置:systemctl reload nginx
在C:\Windows\System32\drivers\etc
修改 hosts 文件做单机域名
# 测试nginx
# kuang.study.cn 域名是不存在的,映射到 192.168.6.136 处
192.168.6.136 kuang.study.cn
http://kuang.study.cn
(相当于访问http://192.168.6.136:80
)接着可继续访问: http://kuang.study.cn:81 、 http://kuang.study.cn:82
所谓的泛域名解析是指:利用通配符 * 星号来做次级域名以实现所有的次级域名均指向同一IP地址。
好处:
可以让域名支持无限的子域名(这也是泛域名解析最大的用途)
防止用户错误输入导致的网站不能访问的问题
可以让直接输入网址登陆网站的用户输入简洁的网址即可访问网站
代理就相当于中间商,本来A和B是可以直接连接的,但是此时添加了一个C在中间,A跟B不直接连接,而是通过C作为中介进行连接。
例子:最常见的例子就是二手房东,其实很多我们租房子时签约的人不是房子的真正房东,而是房东委托的中介,房东不想管事或者房子太多,只靠自己无法进行管理,所以才会通过中介(代理)进行处理
TIps: 一个完整的请求是由: client(客户端) -> proxy(代理) -> server(服务端) 组成。
正向代理: 顺着请求的方向进行的代理,即代理服务器它是由你配置为你服务,去请求目标服务器地址。
例子:假如我们现在想要访问谷歌,但是由于某些原因,无法直接访问到谷歌,我们可以通过连接一台代理服务器,代理服务将我们的请求提交到谷歌,然后再将谷歌的响应反馈给我们。,对于谷歌而言,它只知道有一个请求过来,但是它并不会知道我们是无法直接访问它的。
作用:
用户通过互联网访问 www.baidu.com ,首先进入机房的网关路由上,网关路由会把请求转发到Nginx服务器上,Nginx 服务器再将所有的请求转发到应用服务器,应用服务器应答返回给 Nginx 服务器, Nginx 服务器再将响应返回给用户。 注: 因为网关路由和应用服务器是不通的,所以需要Nginx服务器做代理。
事实上,正向代理和反向代理的作用都是进行请求和转发,但是为了区别正向代理,所以后出现的就成为反向代理。生活中最常见的例子:
1、正向代理: 卖票的黄牛
2、反向代理: 出租房的二手东
nginx.conf配置文件: 启用proxy_pass,root和index字段就会失效,所以二者不能同时出现
proxy_pass http://baidu.com
http://xxx
,不支持httpsserver {
listen 83;
server_name localhost;
location / {
proxy_pass http://baidu.com
# root /www/kuang/study82;
# index index.html;
}
}
firewall-cmd --add-port=83/tcp --permanent
http://192.168.6.136:81
,会跳转至哔哩哔哩upstream
定义一组地址:访问localhost,访问都会代理到192.168.174.133:80
和192.168.174.134:80
这两个地址之一,每次访问这两个地址轮着切换,因为默认权重相等http{
upstream httpds{
server 192.168.174.133:80; #如果是80端口,可以省略不写
server 192.168.174.134:80;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://httpds;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
先假设一个场景:
我们希望这个代理服务器可以帮助我们接收用户的请求,然后将用户的请求按照规则帮我们转发到不同的服务器节点之上。这个过程用户是无感知的,用户并不知道是哪个服务器返回的结果,我们还希望他可以按照服务器的性能提供不同的权重选择。保证最佳体验!所以我们使用了Nginx。
引出负载均衡:把请求,按照一定算法规则,分配给多台业务服务器(即使其中一个坏了/维护升级,还有其他服务器可以继续提供服务)
默认情况下使用轮询方式,逐一转发,这种方式适用于无状态请求。
weight
权重:指定轮询几率,weight
和访问比率成正比,用于后端服务器性能不均的情况。设置权重:
upstream httpds {
server 127.0.0.1:8050 weight=10 ;
# weight 默认为1,weight越大,负载的权重就越大
server 127.0.0.1:8060 weight=1 ;
}
关闭: down
upstream httpds {
# down 表示当前的 server 暂时不参与负载
server 127.0.0.1:8050 weight=10 down;
}
备用机:如果192.168.174.133:80
出现故障,无法提供服务,就使用backup的这个机器
upstream httpds{
server 192.168.174.133:80 weight=10;
server 192.168.174.134:80 weight=80 backup;
}
其他负载均衡策略(不常用):
ip_hash
:根据客户端的 ip 地址转发同一台服务器,可以保持会话
least_conn
: 最少连接访问
url_hash
:根据用户访问的 url 定向转发请求
fair
:根据后端服务器响应时间转发请求
动静分离:为了提高网站的响应速度,减轻程序服务器Tomcat的负载,对于静态资源,如图片、js、css等文件,可以在反向代理服务器中进行缓存,这样浏览器在请求一个静态资源时,代理服务器就可以直接处理,而不用将请求转发给后端服务器。对于用户请求的动态文件,如servlet、jsp,则转发给Tomcat服务器处理,这就是动静分离。即动态文件与静态文件的分离。
当用户请求时,动态请求分配到Tomcat业务服务器,静态资源请求放在Nginx服务器中
例子:
location/
,/
的优先级比较低,如果下面的location没匹配到,就会走http://xxx这个地址的机器location/css/*
,就会被匹配到nginx的html目录下的css文件夹中(我们把css静态资源放在这个位置)server {
listen 80;
server_name localhost;
# /的优先级比较低,如果下面的location没匹配到,就会走http://xxx这个地址的机器
location / {
proxy_pass http://xxx;
}
# root指的是html文件夹,location/css指的是root下的css,所以地址就是html/css文件夹
location /css {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
location ~*/(js|css|img){
root html;
index index.html index.htm;
}
location
正则:
location = /{}
location /{}
location ~/{}
#1、 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条
location ^~ /images/ {}
# 2、匹配所有以 gif、jpg或jpeg 结尾的请求
# 然而,所有请求 /images/ 下的图片会被 location ^~ /images/ 处理,因为 ^~ 的优先级更高,所以到达不了这一条正则
location ~* \.(gif|jpg|jpeg)$ {}
# 3、最长字符匹配到 /images/abc,优先级最低,继续往下搜索其它 location,会发现 ^~ 和 ~ 存在
location /images/abc {}
# 4、匹配以/images/abc 开头的,优先级次之,只有去掉 location ^~ /images/ 才会采用这一条
location ~ /images/abc {}
# 5、匹配/images/abc/1.html 文件,如果和正则 ~ /images/abc/1.html 相比,正则优先级更高
location /images/abc/1.html {}
优先级总结:
实际网站使用中,至少有三个匹配规则定义:
location = / {
proxy_pass http://127.0.0.1:8080/;
}
location ^~ /static/ {
root kuang/webroot/static/;
}
location ~* \.(html|gif|jpg|jpeg|png|css|js|ico)$ {
root kuang/webroot/res/;
}
3.第三个规则:通用规则,用来转发动态请求到后端应用服务器
location /api/ {
proxy_pass http://127.0.0.1:3000/api/
}
rewrite是实现URL重写的关键指令,根据正则表达式部分内容,重定向到repacement,结尾是flag标记。
格式:
#关键字 正则 替代内容 flag标记
rewrite [flag];
rewrite 参数的标签段位置: server、location、if
URLRewrite的优缺点:
示例:
server {
listen 80;
server_name localhost;
location / {
rewrite ^/([0-9]+).html$ /index.jsp?pageNum=$1 break;
proxy_pass http://xxx;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
浏览器地址栏访问 xxx/123.html
实际上是访问xxx/index.jsp?pageNum=123
当我们请求到一个页面后,这个页面一般会再去请求其中的静态资源,这时候请求头中,会有一个refer字段,表示当前这个请求的来源,我们可以限制指定来源的请求才返回,否则就不返回,这样可以防止别人利用我们的资源。
配置格式:
valid_referers none|server_name
参数值,设置有效的refer值:可以同时携带多个参数,表示多个 referer 头部都生效
http://
或https://
以外的请求http://xxxx
)*
invalid_referer
变量:
示例:这里设置nginx服务器中的img目录下的图片必须refer为http:192.168.174/133
才能访问
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://xxx;
}
location /img{
#如果引用这张图片的页面且refer并没有被设置,图片就无法加载出来。
valid_referers http:192.168.174/133;
#if 后面有个空格,不写就会报错
if ($invalid_referer){#无效的
return 403;#返回状态码403
}
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
示例:
# none:表示没有 referer 的可以访问
# server_names:表示本机 server_name 也就是 referer.test.com 可以访问
# *.test.com:匹配上了正则的可以访问
# www.test.org.cn/nginx/:该页面发起的请求可以访问
server {
server_name referer.test.com;
listen 80;
error_log logs/myerror.log debug;
root html;
location / {
valid_referers none server_names
*.test.com www.test.org.cn/nginx/;
if ($invalid_referer) {
return 403; # 返回错误码
}
return 200 'valid\n';
}
}
将提示图片放在html/img/x.png,访问设置防盗链图片时,就返回这x.png张图
location /img{
valid_referers http:192.168.174/133;
if ($invalid_referer){#无效的
rewrite ^/ /img/x.png break;
}
root html;
index index.html index.htm;
}
我们使用浏览器进行访问测试,浏览器会有缓存,导致测试不准,可以借助 curl 工具
yum install -y curl
测试示例
curl -I http://192.168.44.101/img/logo.png
带引用测试
curl -e "http://baidu.com" -I http://192.168.44.101/img/logo.png
带引用测试需要我们在 valid_referers中添加 baidu.com
location /img{
valid_referers http://192.168.44.101 baidu.com;
if ($invalid_referer){#无效的
rewrite ^/ /img/x.png break;
}
root html;
index index.html index.htm;
}
用户访问时,访问的是一个虚拟IP,keepalived会选定一个主服务器使用这个虚拟IP
每台机器上的keepalived会相互通信,根据其他机器上的keepalived进程是否存在,判断服务器状态,如果默认的Master停止了,就会在剩下的Backup机器中,竞选出一台Nginx服务器作为Master
开始使用:
yum install -y keepalived
/etc/keepalived/keepalived.conf
vrrp_instance
、authentication
、virtual_router_id
、virtual_ipaddress
这几个一样的机器,才算是同一个组里。这个组才会选出一个作为Master机器第一台机器配置:
! Configuration File for keepalived
global_defs {
router_id lb1 # 名字与其他配置了keepalive的机器不重复就行
}
vrrp_instance Augenestern {#vrrp实例名可以随意取
state MASTER #只能有一个默认的Master,其他写BACKUP
interface ens33 # ip addr查看下网卡名,默认是ens33
virtual_router_id 51
priority 100 # 竞争的优先级
advert_int 1 #通信时间
authentication {#分组
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.16 #虚拟的IP
}
}
第二台机器配置:
! Configuration File for keepalived
global_defs {
router_id lb2 # 名字与其他配置了keepalive的机器不重复就行
}
vrrp_instance Augenestern {#vrrp实例名可以随意取
state BACKUP #只能有一个默认的Master,其他写BACKUP
interface ens33 # ip addr查看下网卡名,默认是ens33
virtual_router_id 51
priority 50 # 竞争的优先级
advert_int 1 #通信时间
authentication {#分组
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.16 #虚拟IP
}
}
systemctl start keepalived
ip addr
这样当第一台机器宕机之后,第二台机器会继续接收虚拟此ip地址,从而继续对外提供服务。