上一个章节,我们学习了负载均衡的理论知识,那么是不是把应用部署多套,前面挂一个负载均衡的软件或硬件就可以应对高并发了?其实还有很多问题需要考虑。比如:

1. 当一台服务器挂掉,请求如何转发到其他正常的服务器上?
2. 挂掉的服务器,怎么才能不再访问?
3. 如何保证负载均衡的高可用性? 等等等等... 让我们带着这些问题,实战学习一下 Nginx 的配置和使用。

1. 前置概念

在正式介绍 Nginx 之前,首先让我们先了解一下概念。

1. 中间件

干 IT 太累了,我准备辞职开了个烧烤摊,卖羊肉串;

卖羊肉串首先就得有羊肉,于是我就联系了很多养殖场,我又是一个比较负责任的人,为了保证羊肉的质量,我就去考察了一家又一家养殖场,同时我也是个“小气”的人,所以我考察过程中,和对方谈判、比价,最终选了一个养殖场作为我的羊肉供应商,为我提供羊肉。

经营了一阵子,这个养殖场提供的羊肉质量没有以前好了,那么我就重新考察、谈判、比价,如此反复,我投入了大量的时间和精力。

于是我找到了一个信得过的代理公司,约定要羊肉的质量和数量,谈好价钱,以后我只找代理商拿货,具体代理商找的哪家养殖场我不去过问,甚至代理商可以送货上门。

在这个例子里面,卖烧烤就是业务,我的烧烤摊是业务端,养殖场是底层,而 这个信得过的代理公司,就是中间件。

2. 正向代理和反向代理

正向代理:我住在北京,但是想回老家买套房,但是我没办法亲自回老家考察,于是我就派我的管家回老家考察;管家就是正向代理服务器;正向代理服务器代表了客户端,在正向代理的过程中,服务端只和代理服务器打交道(房东只和我的管家谈),并不知道真正的客户端是谁。

反向代理:我住在北京,但是想回老家买套房,但是我没办法亲自回老家考察,于是我打个电话联系了老家的房屋中介去办这件事儿;房屋中介就是反向代理;这里的反向代理,代表的是房东,在反向代理的过程中,客户端只和反向代理服务器打交道,并不知道真正的服务端是谁。

当然,我的管家也可以联系我老家的房屋中介,那么架构图就会变成:

2. Nginx 的概念

了解完上面的几个概念,那么 Nginx 的概念理解起来就简单很多了:

Nginx 就是一个开源的、高性能的、可靠的 Http 中间件; 它经常被用作 Http 代理、反向代理、负载均衡等等,当然它也能做正向代理,但是实际很少有这么用的。

3. 最简单的 Nginx 使用示例

本章节项目的代码:chapter3

Step 1. 部署多套环境

我们将章节 1 中的项目 chapter1 复制出来一份,改名为 chapter3,表示是第 3 章节的项目,同时修改:

1. pom.xml 中的 artifactId 修改为 chapter3

2. application.yml 中的 server.port 修改成 8089

这样我们分别启动 chapter1 和 chapter3,这样就相当于把相同的项目部署了两套,端口分别是 8088 和 8089 。

Step 2. 下载 Nginx

我们可以在 Nginx 的官网 下载我们所需的版本,因为我使用 windows 环境开发,所以我在这里就选择了 nginx/Windows-1.14.2 这个版本。

下载完成解压缩,不需要额外的安装,可以直接使用。

Step 3. 配置 Nginx

进入 nginx-1.14.2\conf 目录下,用文本编辑器打开 nginx.conf,对配置文件进行如下修改:

1. 在 http 中增加 upstream,并配置两台环境的地址;

2. 在 http.server.location 中增加 proxy_pass 的配置;

http {
... #增加 upstream 的配置,其中 myserver 是自己起的名字
upstream myserver{
server 127.0.0.1:8088; #有几套环境,就配置几条
server 127.0.0.1:8089;
} server {
listen 80;
server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / {
root html;
index index.html index.htm;
proxy_pass http://myserver; #增加,其中 http://myserver 的 myserver 要和上文对应
} }
}
...
}

完整配置文件请参考:nginx.conf

Step 4. 启动 Nginx

我们可以直接双击 nginx-1.14.2 目录下的 nginx.exe 启动;也可以通过 cmd 命令打开控制台,进入 nginx-1.14.2 目录执行如下命令启动 Nginx:

start nginx //启动 Nginx ;启动后可能一闪而过,我们可以看一下任务管理器是否有名字叫做 nginx.exe 的进程

nginx.exe -s stop //停止 Nginx
nginx.exe -s quit //停止 Nginx

Step 5. 测试 Nginx

让我们测试一下 Nginx 是否配置并启动成功,打开浏览器输入:

http://127.0.0.1/queryAdmin

注意这里并没有加端口号,是因为 url 中没有端口号的时候表示端口号为 80,而我们 Nginx 的配置文件中,监听的正是 80 端口 (listen 80);我们可以在浏览器中看到服务返回的结果:

User : Admin

这就说明 Nginx 已经转发了我们的请求到了服务端,并正确返回,那么负载均衡是如何体现的呢?让我们多刷新几次浏览器,然后看看后台日志:

我前后一共调用了 5 次服务,可以看到两个服务端分别接收到了 2 次和 3 次请求,负载均衡达到了效果。

4. Nginx 常见的路由策略

1. 轮询法

最简单的轮询法,多余的配置不需要增加。

upstream myserver{
server 127.0.0.1:8088; # 有几套环境,就配置几条
server 127.0.0.1:8089;
}

2. 源地址哈希法

使用 ip_hash 关键字,每一个请求,都按 hash(IP) 的结果决定访问哪台服务器;

upstream myserver{
ip_hash; # hash(IP)
server 127.0.0.1:8088; # 有几套环境,就配置几条
server 127.0.0.1:8089;
}

如果我们本地测试,多次访问接口,可以发现请求永远落到同一个服务上,因为本地 IP 一直没有改变。

3. 加权轮询法

使用 weight 关键字,设置每台服务器的权重;

upstream myserver{
server 127.0.0.1:8088 weight=1; # 20% 请求会发给8088
server 127.0.0.1:8089 weight=4;
}

4. 最小连接数法

根据每个服务器节点的连接数,动态地选择当前连接数最少的服务器转发请求;

upstream myserver{
least_conn;
server 127.0.0.1:8088;
server 127.0.0.1:8089;
}

5. 最快响应速度法

根据每个服务器节点的响应时间(请求的往返延迟),动态地选择当前响应速度最快的服务器转发请求;需要额外安装 nginx-upstream-fair 模块。

upstream myserver{
fair; # 额外安装 nginx-upstream-fair 模块
server 127.0.0.1:8088;
server 127.0.0.1:8089;
}

6. URL 哈希算法

对 URL 进行 Hash 运算,根据结果来分配请求,这样每个 URL 都可以访问到同一个服务端;当服务端有缓存的时候,比较有效。

upstream myserver{
hash $request_uri;
server 127.0.0.1:8088; # 有几套环境,就配置几条
server 127.0.0.1:8089;
}

也可以安装第三方模块,比如我们要使用 URL 一致性哈希算法,那么我们可以安装 ngx_http_upstream_consistent_hash 模块。

upstream myserver{
consistent_hash $request_uri;
server 127.0.0.1:8088;
server 127.0.0.1:8089;
}

参考资料:Upstream Consistent Hash

5. Nginx 常用功能

5.1 请求失败重试

当一台服务器挂掉,请求如何转发到其他正常的服务器上?

我们可以先做个试验,就是关闭 8089 端口的服务,只保留 8088 端口的服务,然后调用几次接口,如果其中一次调用长时间不返回(浏览器访问状态图标一直在打转),表示本次请求发送到了 8089 端口,那么让我们等待一段时间...大约一分钟之后,8080 端口服务的后台日志,打印出来日志,调用端接收到了返回,这说明:

  1. Nginx 默认有失败重试机制;
  2. 默认的超时时间为 60s 。

这里的超时时间是可以修改的,需要在 http.server.location 中增加如下配置:

location / {
root html;
index index.html index.htm;
proxy_pass http://myserver;
proxy_connect_timeout 5; # 连接超时时间
proxy_send_timeout 5; # 发送数据给后端服务器的超时时间
proxy_read_timeout 5; # 后端服务器的相应时间
#proxy_next_upstream off; # 是否要关闭重试机制
}

完整配置文件请参考:设置超时重试时间5秒-nginx.conf

不过这里要注意一点,如果设置了服务器相应超时时间(比如设置了 10s ),万一应用的业务处理时间比较慢(业务处理花费了 15s ),那么会导致 Nginx 超时重试,那么可能会造成重复处理。

5.2 后端服务器节点健康状态检查

如果挂掉一台服务器,路由到这台服务器请求每次都要等到超时时间过去,才能发起重试,如果 Nginx 不再把请求发送给挂掉的服务器,那就省事多了;

这就叫做“后端服务器节点健康状态检查”。

如果不安装第三方模块,可以做如下配置完成“后端服务器节点健康状态检查”:

1. 设置超时时间:

location / {
root html;
index index.html index.htm;
proxy_pass http://myserver;
proxy_connect_timeout 5; # 连接超时时间
proxy_send_timeout 5; # 发送数据给后端服务器的超时时间
proxy_read_timeout 5; # 后端服务器的相应时间
#proxy_next_upstream off; # 是否要关闭重试机制
}

2. 设置尝试重试的次数:

upstream myserver{
server 127.0.0.1:8088 max_fails=1 fail_timeout=100s;
server 127.0.0.1:8089 max_fails=1 fail_timeout=100s;
}

其中 max_fails 表示最多失败次数,fail_timeout 表示在一个时间段内,服务器不会再次尝试访问;上面的配置表示在 100s 内,只要超时失败 1 次,就不再访问该服务器。

完整配置文件请参考:设置超时重试时间5s-失败1次100秒之内不再访问-nginx.conf

除此之外,我们还可以安装第三方模块来实现“后端服务器节点健康状态检查”:

5.3 Nginx 的高可用

以为使用 Nginx ,部署了多台应用服务器,可以保证应用服务器的高可用(挂掉一台,还有其他服务器可以用);

但是如何保证负载均衡的高可用性?也就是万一 Nginx 挂了怎么办?

Nginx 同样也需要部署多台,架构大概是这个样子的:

现在应用比较广泛的是利用 keepalived 实现 Nignx 的高可用:



5.4 其他

除了以上的常见功能,强大的 Nginx 还可以:

  1. 限制 IP 访问频率和带宽占用;
  2. 缓存静态资源;
  3. 文件压缩;
  4. TCP 负载;
  5. 防盗链;
  6. 等等等等...

总结

我们现在的架构已经变成了:

【从单体架构到分布式架构】(三)请求增多,单点变集群(2):Nginx的更多相关文章

  1. JAVA架构师眼中的高并发架构,分布式架构 应用服务器集群

    前言 高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等. 为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适 ...

  2. 庐山真面目之六微服务架构Consul集群、Ocelot网关集群和Nginx版本实现

    庐山真面目之六微服务架构Consul集群.Ocelot网关集群和Nginx版本实现 一.简介      在上一篇文章<庐山真面目之五微服务架构Consul集群.Ocelot网关和Nginx版本实 ...

  3. 庐山真面目之四微服务架构Consul集群和Nginx版本实现

    庐山真面目之四微服务架构Consul集群和Nginx版本实现 一.简介      在上一篇文章<庐山真面目之三微服务架构Consul版本实现>中,我们已经探讨了如何搭建基于单节点Consu ...

  4. 分布式ID系列(4)——Redis集群实现的分布式ID适合做分布式ID吗

    首先是项目地址: https://github.com/maqiankun/distributed-id-redis-generator 关于Redis集群生成分布式ID,这里要先了解redis使用l ...

  5. 大型网站系统架构实践(六)深入探讨web应用集群Session保持

    原理 在第三,四篇文章中讲到了会话保持的问题,而且还遗留了一个问题,就是会话保持存在单点故障, 当时的方案是cookie插入后缀,即haproxy指负责分发请求,应用服务自行保持用户会话,如果应 用服 ...

  6. 高性能网站架构设计之缓存篇(5)- Redis 集群(上)

    集群技术是构建高性能网站架构的重要手段,试想在网站承受高并发访问压力的同时,还需要从海量数据中查询出满足条件的数据,并快速响应,我们必然想到的是将数据进行切片,把数据根据某种规则放入多个不同的服务器节 ...

  7. Rancher首席架构师解读Fleet:它何以管理百万集群?

    作者简介 Darren Shepherd,Rancher Labs联合创始人及首席架构师.在加入Rancher之前,Darren是Citrix的高级首席工程师,他在那里从事CloudStack.Ope ...

  8. Nginx网络架构实战学习笔记(六):服务器集群搭建、集群性能测试

    文章目录 服务器集群搭建 Nginx---->php-fpm之间的优化 302机器 202机器 压力测试 搭建memcached.mysql(数据准备) 今晚就动手-.- 集群性能测试 服务器集 ...

  9. java架构之路-(微服务专题)nacos集群精讲实战

    上次回顾: 上次博客,我们主要说了微服务的发展历程和nacos集群单机的搭建,单机需要-m standalone启动,集群建议使用nginx做一下反向代理,自行保证mysql和ngxin的高可用. 本 ...

随机推荐

  1. Spring 中的事件处理

    Spring 中的事件处理 Spring 的核心是 ApplicationContext,它负责管理 beans 的完整生命周期.当加载 beans 时,ApplicationContext 发布某些 ...

  2. 树状数组区间更新区间查询以及gcd的logn性质

    题目描述 给你一个长为n的序列a m次查询 每次查询一个区间的所有子区间的gcd的和mod1e9+7的结果 输入描述: 第一行两个数n,m之后一行n个数表示a之后m行每行两个数l,r表示查询的区间 输 ...

  3. 仿开源框架从零到一完整实现高性能、可扩展的RPC框架 | 6个月做成教程免费送

    去年年就在写一本付费小册,今年年初基本上就写完了,本来预计计划是春节上线结果由于平台的原因一直拖着没上.五一前跟平台联系给的反馈是五月份能上,结果平台又在重构,停止小册的申请和上线,最后我考虑了一下决 ...

  4. Java——连接MySql数据库

    eclipse项目文件结构 /JavaConnMySqlTest/src/db.properties jdbc.drivers=com.mysql.jdbc.Driver jdbc.url=jdbc: ...

  5. swiper基本使用

    参数名 类型 是否必填 描述 swiperContainer HTMLElement or string 必选 Swiper容器的css选择器,例如".swiper-container&qu ...

  6. vivo产能问题

    生产手机,第一天量产1台,接下来2天(即第二.三天)每天量产2件,接下来3天(即第四.五.六天)每天量产3件 ... ... 以此类推,请编程计算出第n天总共可以量产的手机数量. public int ...

  7. 【Python】组合数据类型

    集合类型 集合类型定义 集合是多个元素的无序组合 集合类型与数学中的集合概念一致 集合元素之间无序,每个元素唯一,不存在相同元素 集合元素不可更改,不能是可变数据类型 理解:因为集合类型不重复,所以不 ...

  8. PAT 1036 Boys vs Girls (25分) 比大小而已

    题目 This time you are asked to tell the difference between the lowest grade of all the male students ...

  9. js函数中的this关键字

    关于这个this关键字,也是很多项目中常常被用到的,那么,有人也许会问,干嘛要用this呢,在函数被调用时,直接指明是什么对象在调用不就行了?还整那么个模模糊糊的概念出来干嘛?不过嘛,存在即真理,既然 ...

  10. 【HIVE高级笔试必备题型】(组内topN、相邻行的值比较问题)求语文大于数学_/_求文科大于理科成绩的学生

    Hive SQL练习之成绩分析 数据:[id, 学号,班级,科目,成绩] 1,1,1,yuwen,80 2,1,1,shuxue,85 3,2,1,yuwen,75 4,2,1,shuxue,70 5 ...