目录
[ocation 指令说明](#ocation 指令说明)
[Nginx 负载均衡](#Nginx 负载均衡)
反向代理如何配置
1、反向代理实例一
实现效果:使用 Nginx 反向代理,访问 http://localhost:8080/ 直接跳转到 http://192.168.1.130:9090
配置代码
server {
listen 8080;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html; # 解决刷新404
proxy_pass http://192.168.1.130:9090;
}
}
如上配置,我们监听 8080 端口,访问域名为 http://localhost:8080/,故访问该域名时会跳转到 http://192.168.1.130:9090 路径上(不加端口号时默认为 80 端口)。
此处的意思为:nginx 反向代理服务监听 http://localhost/的8080端口,如果有请求过来,则转到proxy_pass配置的对应服务器上,仅此而已。
实验结果:
2、反向代理实例二
实现效果:使用 Nginx 反向代理,根据访问的路径跳转到不同端口的服务中,Nginx 监听端口为 9001。
- 访问 http://192.168.1.130:8080/edu/ 直接跳转到 http://192.168.1.130:9091/;
- 访问 http://192.168.1.130:8080/vod/ 直接跳转到 http://192.168.1.130:9092;
第一步,需要准备两个服务器,一个 9091 端口,一个 9092 端口,并准备好测试的页面
第二步,修改 nginx 的配置文件,在 http 块中配置 server
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html; # 解决刷新404
proxy_pass http://192.168.1.130:9090;
}
location /edu/ {
proxy_pass http://192.168.1.130:9091/;
}
location /vod/ {
proxy_pass http://192.168.1.130:9092/;
}
}
根据上面的配置,当请求到达 Nginx 反向代理服务器时,会根据请求进行分发到不同的服务上。
实验结果
在 Nginx 配置文件中,
location
指令用于定义请求的处理规则。当指定一个location
时,如果路径后面加上斜杠/
,表示匹配该路径及其所有子路径。如果不加斜杠,则只匹配精确的路径。例如:
location /edu
会匹配任何以/edu
开头的请求,但不会匹配/edu/
。location /edu/
会匹配以/edu/
开头的请求,包括/edu/
本身及其所有子路径。在代理配置中,
proxy_pass
指令用于指定请求应该被转发到哪个上游服务器。当你在location
后面加上/
时,Nginx 会将请求转发到指定的上游服务器,并且保持原始请求的路径不变。
ocation 指令说明
该指令用于匹配 URL, 语法如下:
location [ = | ~ | ~* | ^~] uri {
}
=
:用于不含正则表达式的 uri 前,要求请求字符串与 uri 严格匹配, 如果匹配成功,就停止继续向下搜索并立即处理该请求。~
:用于表示 uri 包含正则表达式,并且区分大小写。~*
:用于表示 uri 包含正则表达式,并且不区分大小写。^~
:用于不含正则表达式的 uri 前,要求 Nginx 服务器找到标识 uri 和请求
字符串匹配度最高的 location 后,立即使用此 location 处理请求,而不再使用 location块中的正则 uri 和请求字符串做匹配。
注意:如果 uri 包含正则表达式,则必须要有 ~ 或者 ~* 标识
Nginx 负载均衡
负载均衡(Load Balance),它在网络现有结构之上可以提供一种廉价、有效、透明的方法来扩展网络设备和服务器的带宽,并可以在一定程度上增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性等。用官网的话说,它充当着网络流中"交通指挥官"的角色,"站在"服务器前处理所有服务器端和客户端之间的请求,从而最大程度地提高响应速率和容量利用率,同时确保任何服务器都没有超负荷工作。如果单个服务器出现故障,负载均衡的方法会将流量重定向到其余的集群服务器,以保证服务的稳定性。当新的服务器添加到服务器组后,也可通过负载均衡的方法使其开始自动处理客户端发来的请求。(详情可参考:What Is Load Balancing?)
简言之,负载均衡实际上就是将大量请求进行分布式处理的策略。
负载均衡常用算法
1. 轮询 (round-robin)
轮询为负载均衡中较为基础也较为简单的算法,它不需要配置额外参数。假设配置文件中共有 M 台服务器,该算法遍历服务器节点列表,并按节点次序每轮选择一台服务器处理请求。当所有节点均被调用过一次后,该算法将从第一个节点开始重新一轮遍历。
特点:由于该算法中每个请求按时间顺序逐一分配到不同的服务器处理,因此适用于服务器性能相近的集群情况,其中每个服务器承载相同的负载。但对于服务器性能不同的集群而言,该算法容易引发资源分配不合理等问题。
2、加权轮询
为了避免普通轮询带来的弊端,加权轮询应运而生。在加权轮询中,每个服务器会有各自的 weight
。一般情况下,weight
的值越大意味着该服务器的性能越好,可以承载更多的请求。该算法中,客户端的请求按权值比例分配,当一个请求到达时,优先为其分配权值最大的服务器。
特点:加权轮询可以应用于服务器性能不等的集群中,使资源分配更加合理化。
Nginx 加权轮询源码可见:ngx_http_upstream_round_robin.c,源码分析可参考:关于轮询策略原理的自我理解。其核心思想是,遍历各服务器节点,并计算节点权值,计算规则为 current_weight
与其对应的 effective_weight
之和,每轮遍历中选出权值最大的节点作为最优服务器节点。其中 effective_weight
会在算法的执行过程中随资源情况和响应情况而改变。较为核心的部分如下:
for (peer = rrp->peers->peer, i = 0;
peer; /* peer 为当前遍历的服务器结点*/
peer = peer->next, i++)
{
...
/* 每轮遍历会更新 peer 当前的权值*/
peer->current_weight += peer->effective_weight;
...
/* best 为当前服务器中的最优节点,即本轮中选中的服务器节点*/
if (best == NULL || peer->current_weight > best->current_weight) {
best = peer;
p = i;
}
...
}
3. IP 哈希(IP hash)
ip_hash
依据发出请求的客户端 IP 的 hash 值来分配服务器,该算法可以保证同 IP 发出的请求映射到同一服务器,或者具有相同 hash 值的不同 IP 映射到同一服务器。
特点:该算法在一定程度上解决了集群部署环境下 Session 不共享的问题。
Session 不共享问题是说,假设用户已经登录过,此时发出的请求被分配到了 A 服务器,但 A 服务器突然宕机,用户的请求则会被转发到 B 服务器。但由于 Session 不共享,B 无法直接读取用户的登录信息来继续执行其他操作。
实际应用中,我们可以利用 ip_hash
,将一部分 IP 下的请求转发到运行新版本服务的服务器,另一部分转发到旧版本服务器上,实现灰度发布。再者,如遇到文件过大导致请求超时的情况,也可以利用 ip_hash
进行文件的分片上传,它可以保证同客户端发出的文件切片转发到同一服务器,利于其接收切片以及后续的文件合并操作。
4、其他算法
-
URL hash
url_hash
是根据请求的 URL 的 hash 值来分配服务器。该算法的特点是,相同 URL 的请求会分配给固定的服务器,当存在缓存的时候,效率一般较高。然而 Nginx 默认不支持这种负载均衡算法,需要依赖第三方库。 -
最小连接数(Least Connections)
假设共有 M 台服务器,当有新的请求出现时,遍历服务器节点列表并选取其中连接数最小的一台服务器来响应当前请求。连接数可以理解为当前处理的请求数。
应用场景
说了这么多理论,究竟基于 Nginx 的负载均衡要怎么用呢?接下来,将以加权轮询算法为例,带大家尝试通过自己的一台笔记本 + Nginx + Node 测试一下负载均衡。由于没有多台服务器,于是通过自己笔记本的多个不同端口来模拟不同的服务器。
Step 1:确保自己的电脑中,Nginx 已安装并能够成功启动(以 Mac 为例)
如果你也遇到了像我一样由于端口占用导致 Nginx 启动失败的问题,可以尝试下述步骤修改配置文件中的端口号
-
相关文件路径
- /usr/local/etc/nginx/nginx.conf (配置文件路径)
- /usr/local/var/www (服务器默认路径)
- /usr/local/Cellar/nginx/1.8.0 (安装路径)
-
修改 nginx.conf 文件中的端口
server {
# listen 8080;
listen 8086;
server_name localhost;
} -
Nginx 配置文件 nginx.conf 中主要包含以下几个部分:
- server:主机服务相关设置,主要用于指定虚拟主机域名、IP 和端口
- location:URL 匹配特定位置后的设置,反向代理设置
- upstream:负载均衡相关配置
-
暂停 Nginx 并重启
// 暂停 Nginx 服务
sudo nginx -s stop
// 启动 Nginx 服务
nginx
打开 http://localhost:8086/ 测试是否成功,如果显示下图,则证明启动成功~
Step 2:基于 Node + Express 框架来搭建简单的服务器
Express 是一个简洁而灵活的轻量级 node.js Web 应用框架(详情可了解 Express),如果第一次使用,请先安装。
-
安装 Express
npm i express
-
新建 index.js 文件,并写入代码
const express = require('express');
const app = express();// 定义要监听的端口号
const listenedPort = '8087';app.get('/', (req, res) => res.send(
Hello World! I am port ${listenedPort}~
));// 监听端口
app.listen(listenedPort, () => console.log(success: ${listenedPort}
)); -
启动服务器
node index.js
此处可以多起几个服务,分别让 Node 监听 8087,8088,8089 端口,每个服务中通过 send
不同的文案用以区分不同的 Server。
Step 3:在 nginx.conf 文件中配置好需要轮询的服务器和代理
-
轮询的服务器,写在 http 中的 upstream 对象里:
upstream testServer {
server localhost:8087 weight=10;
server localhost:8088 weight=2;
server localhost:8089;
} -
代理地址,写在 http 中的 server 对象里:
location / {
root html;
index index.html index.htm;
proxy_pass http://testServer; // testServer 为自己定义的服务器集群
}
Step 4:查看结果
-
重启 Nginx 服务
通过多次刷新可以发现,由于设置了不同的 weight
,端口号为 8087 的服务器出现的次数最多,同时证实了权值越高,服务器处理请求几率越大的规则。
总结
Nginx 作为一款优秀的反向代理服务器,可以通过不同的负载均衡算法来解决请求量过大情况下的服务器资源分配问题。较为常见的负载均衡算法有轮询、加权轮询、IP 哈希等等,可分别应对不同的请求场景
Nginx实现动静分离
简介: 前面介绍了Nginx的负载均衡,一般来说,都需要将动态资源和静态资源分开,这样可以很大程度的提升静态资源的访问速度,同时在开过程中也可以让前后端开发并行可以有效的提高开发时间,也可以有些的减少联调时间 。接下来介绍什么是动静分离以及如何使用Nginx实现动静分离。
前面介绍了Nginx的负载均衡,一般来说,都需要将动态资源和静态资源分开,这样可以很大程度的提升静态资源的访问速度,同时在开过程中也可以让前后端开发并行可以有效的提高开发时间,也可以有些的减少联调时间 。接下来介绍什么是动静分离以及如何使用Nginx实现动静分离。
一、什么是动静分离
在Web开发中,通常来说,动态资源其实就是指那些后台资源,而静态资源就是指HTML,JavaScript,CSS,img等文件。
动静分离,说白了,就是将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用服务器的请求。后台应用服务器只负责动态数据请求。
优势:分担负载,减轻web服务器的压力,适用于大负载。静态资源放置cdn,同时还可以通过配置缓存到客户浏览器中,这样极大减轻web服务器的压力。
劣势:网络环境不佳时,ajax回应很慢,导致页面出现空白,出错处理会不好看。不利于网站SEO(搜索引擎优化),增加了开发复杂度。
二、实现方案
动静分离就是根据一定规则静态资源的请求全部请求Nginx服务器,后台数据请求转发到Web应用服务器上。从而达到动静分离的目的。目前比较流行的做法是将静态资源部署在Nginx上,而Web应用服务器只处理动态数据请求。这样减少Web应用服务器的并发压力。具体如下图所示:
三、配置Nginx动静分离
- 修改nginx.conf配置,其中第一个location负责处理后台请求,第二个负责处理静态资源, nginx 的其他配置,请参考前之前的文章。 具体如下所示:
#拦截静态资源
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css)$ {
root static;
expires 30d;
}
上面的示例,主要是配置image、js、css等资源文件的路径和地址。然后设置缓存失效的时间。
完成的Nginx配置如下所示:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
#拦截后台请求
location / {
proxy_pass http://localhost:81;
proxy_set_header X-Real-IP $remote_addr;
}
#拦截静态资源
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css)$ {
root static;
expires 30d;
}
}
}
- 在Nginx 下 创建 static 目录,将图片,js, css 等文件 拷贝到该目录下
- 重启Nginx,使用命令: ./nginx -s reload 重新启动Nginx。
四、验证测试
Nginx 配置完成之后,在浏览器中访问:http://localhost/ 查看页面的请求效果。
通过浏览器的调试工具,通过图中红框内容都可以看出来引用静态资源成功了。动态请求转发到了81端口的web应用服务器,而静态的资源文件,访问的是80端口。说明Nginx的动静分离配置成功。