文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一篇文章让你搞懂 Nginx 的负载均衡

2024-12-11 18:04

关注

负载均衡

所谓负载均衡,就是 Nginx 把请求均匀的分摊给上游的应用服务器,这样即使某一个服务器宕机也不会影响请求的处理,或者当应用服务器扛不住了,可以随时进行扩容。

[[335400]]

 

 

Nginx 在 AKF 可扩展立方体上的应用

 

 

这就是 Nginx 的负载均衡功能,它的主要目的就是为了增强服务的处理能力和容灾能力。

反向代理

反向代理和负载均衡在某种程度上是密不可分的。

Nginx 支持多种协议的反向代理。四层的反向代理比较简单,无论是 UDP 还是 TCP 的流量过来,转发到上游的依然是 UDP 或 TCP 的流量。

而到了应用层时,就不太相同了,因为 HTTP 的 Header 中包含了大量的业务信息,需要根据 HTTP 的头部转换成不同的协议。

 

 

反向代理与缓存

缓存这个问题分为两类,一类是时间缓存,一类是空间缓存。

 

 

upstream 与 server 指令

  1. Syntax: upstream name { ... } 
  2. Default: — 
  3. Context: http 
  4.  
  5. Syntax: server address [parameters]; 
  6. Default: — 
  7. Context: upstream 

功能:指定一组上游服务器地址,地址可以是域名、IP 地址或者 Unix Socket 地址。可以在域名或者 IP 地址后加端口,如果不加端口,那么默认使用 80 端口。

通用参数:server 后可以添加的参数backup:指定当前 server 为备份服务,仅当非备份 server 不可用时,请求才会转发到该 server表示某台服务已经下线,不再服务

负载均衡算法

加权 Round-Robin 负载均衡算法

Round-Robin(rr) 负载均衡算法发给上游服务器的请求是轮询发送的,相当于所有上游服务器根据顺序依次处理发来的请求。

有些情况下上游服务器性能不同,比如 4C8G 和 8C16G 的服务器都有,那么这时候就可以对服务器设置一些权重,让性能好的承担更多的请求。

对上游服务使用 keepalive 长连接

Nginx 与上游服务一般是在内网中的,所以开启 keepalive 后效果后更明显。

对上游服务器的 HTTP 头部设定

  1. proxy_http_version 1.1; 
  2. proxy_set_header Connection ""

upstream_keepalive 的指令

  1. Syntax: keepalive connections; 
  2. Default: — 
  3. Context: upstream 
  4. # 1.15.3 非稳定版本新增命令 
  5. Syntax: keepalive_requests number; 
  6. Default: keepalive_requests 100;  
  7. Context: upstream 
  8. Syntax: keepalive_timeout timeout; 
  9. Default: keepalive_timeout 60s;  
  10. Context: upstream 
  1. keepalive connections; 

指定上游服务域名解析的 resolver 指令

当使用域名访问上游服务时,可以指定一个 DNS 解析的地址,还可以设置超时等,这个时候就要用到 resolver 指令。

  1. Syntax: resolver address ... [valid=time] [ipv6=on|off]; 
  2. Default: — 
  3. Context: http, server, location 
  4.  
  5. Syntax: resolver_timeout time
  6. Default: resolver_timeout 30s;  
  7. Context: http, server, location 

实战

下面我起了两个 Nginx 的进程,一个作为上游服务器,监听 8011 和 8012 端口,另一个作为反向代理向上游服务器发请求。

上游服务器的配置如下,当请求是到达 8011 端口就返回 8011 server response. ,当请求到达 8012 端口返回 8012 server response. 。

  1. server { 
  2.     listen 8011; 
  3.     default_type text/plain; 
  4.     return 200 '8011 server response.\n'
  5.  
  6. server { 
  7.     listen 8012; 
  8.     default_type text/plain; 
  9.     # client_body_in_single_buffer on
  10.     return 200 '8012 server response.\n'

作为反向代理的 Nginx 服务器配置是这个样子的:

这里面 8011 端口和 8012 端口的区别在于 8011 端口设置了权重和对应的参数。

  1. upstream rrups { 
  2.     server 127.0.0.1:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5; 
  3.     server 127.0.0.1:8012; 
  4.     keepalive 32; 
  5.  
  6. server { 
  7.     server_name rrups.ziyang.com; 
  8.     error_log myerror.log info; 
  9.  
  10.     location /{ 
  11.         proxy_pass http://rrups; 
  12.         proxy_http_version 1.1; 
  13.         proxy_set_header Connection ""
  14.     } 

两个 Nginx 都配置好之后,来测试一下:

  1. ➜  nginx curl rrups.ziyang.com 
  2. 8011 server response. 
  3. ➜  nginx curl rrups.ziyang.com 
  4. 8011 server response. 
  5. ➜  nginx curl rrups.ziyang.com 
  6. 8012 server response. 

由于 8011 端口的权重设置的是 2,所以根据 rr 算法,每次都是先两个连接负载到 8011 端口上然后是 8012 端口。

这一节讲了 rr 负载均衡算法,rr 算法是所有负载均衡算法的基础,在其他负载均衡算法失效的情况下,Nginx 也会使用 rr 算法进行负载均衡。

负载均衡哈希算法,ip_hash 与 hash 模块

rr 轮询算法没有办法保证请求由某一台指定的服务器去处理,只能轮询处理请求,在 AKF 立方体中只能在 x 轴方向上进行水平扩展。如果基于 z 轴扩展,就可以采用哈希算法保证某一类请求只由特定的服务器处理。

指令的话比较简单,就是 ip_hash 出现在 upstream 上下文中。

  1. Syntax: ip_hash; 
  2. Default: — 
  3. Context: upstream 

这里面不得不提到的一个模块就是 realip 模块,哈希算法是根据 remote_addr 这个变量的值来进行哈希的,这个变量已经出现了好多次了,可见是多么常用的一个变量。不熟悉的还是到前面Nginx 的 11 个阶段 重新复习一下。

还有另外一个模块 upstream_hash 模块,这个模块可以基于任意的关键字实现 hash 算法的复杂均衡。

基于任意关键字实现 hash 算法的负载均衡:upstream_hash 模块

指令的话就是 hash 指令,后面可以跟关键字作为 key。

  1. Syntax: hash key [consistent]; 
  2. Default: — 
  3. Context: upstream 

实战

配置文件如下所示:

  1. log_format  varups  '$upstream_addr $upstream_connect_time $upstream_header_time $upstream_response_time ' 
  2.                         '$upstream_response_length $upstream_bytes_received ' 
  3.                         '$upstream_status $upstream_http_server $upstream_cache_status'
  4.  
  5. upstream iphashups { 
  6.     ip_hash; 
  7.     #hash user_$arg_username; 
  8.     server 127.0.0.1:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5; 
  9.     server 127.0.0.1:8012 weight=1; 
  10.  
  11. server { 
  12.     set_real_ip_from  127.0.0.1; 
  13.     real_ip_recursive on
  14.     real_ip_header X-Forwarded-For
  15.     server_name iphash.ziyang.com; 
  16.     listen 80; 
  17.     error_log myerror.log info; 
  18.     access_log logs/upstream_access.log varups; 
  19.  
  20.     location /{ 
  21.         proxy_pass http://iphashups; 
  22.         proxy_http_version 1.1; 
  23.         proxy_set_header Connection ""
  24.     } 

实际验证一下,会发现不同的 ip 地址实际上是会被不同的上游服务器处理的,如果是同一个 ip 地址,那么只会被一个上游服务器处理。

  1. ➜  nginx curl -H 'X-Forwarded-For: 10.200.20.20' iphash.ziyang.com 
  2. 8012 server response. 
  3. ➜  nginx curl -H 'X-Forwarded-For: 1.200.20.20' iphash.ziyang.com 
  4. 8011 server response. 

基于 IP 或者基于自定义 key 的 hash 算法有一个严重的问题,那就是当上游服务器挂掉的话,Nginx 依然会向这台服务器发请求,这是因为,如果负载的不同的服务器上去,可能会得到异常的响应,同时还可能导致大量的路由变更。下面的一致性哈希可以解决这个问题。

一致性哈希算法:hash 模块

刚才说了基于 IP 的哈希算法存在一个问题,那就是当有一个上游服务器宕机或者扩容的时候,会引发大量的路由变更,进而引发连锁反应,导致大量缓存失效等问题。那么为什么会造成这种情况呢?

 

 

 

 

而一致性 hash 算法则可以解决这个问题。

 

 

一致性哈希算法的原理是,将一个环分成了 2^32 个区间范围,四个节点将这个环划分成为了四个区间,每个区间的请求都由对应的节点去处理。来看看当扩容的时候会发生什么。

 

 

假设这时候发现 node4 负载过高,因此决定再添加一个节点进去分担压力,那么影响的也只是这个节点之后的请求,可能会缓存失效,而其他的三个节点是不会有任何影响的。

这就是一致性 hash 算法的原理,一致性 hash 算法使用也很简单,只需要将上一节指令中的参数打开即可:

  1. Syntax: hash key [consistent]; 
  2. Default: — 
  3. Context: upstream 

这里只需要指明 consistent 参数即可。

最少连接数算法

再来看一个最少连接数算法。这个算法顾名思义,它会优先选择连接最少的上游服务器,是由 upstream_least_conn 模块提供的。

指令的用法也很简单,直接在 upstream 模块中开启 least_conn 指令即可。

  1. Syntax: least_conn; 
  2. Default: — 
  3. Context: upstream 

负载均衡策略对所有 worker 进程生效:upstream_zone 模块

上面说的所有的负载均衡算法对于 worker 进程来说都是独立的,每个 worker 进程之间并不互通,这样在很多时候并不是我们期望的。

我们期望的应该是负载均衡算法对所有的 worker 进程生效。

功能:分配出共享内存,将其他 upstream 模块定义的负载均衡策略数据、运行时每个上游服务器的状态数据存放在共享内存上,以对所 Nginx worker 进程生效

模块: ngx_http_upstream_zone_module ,通过 --without-http_upstream_ip_hash_module 禁用模块

一个指令,指定 zone 的名字以及对应的大小:

  1. Syntax: zone name [size]; 
  2. Default: — 
  3. Context: upstream 

除此之外,各个负载均衡模块之间是要遵循一定的顺序的:

  1. ngx_module_t *ngx_modules[] = { 
  2.     … … 
  3.     &ngx_http_upstream_hash_module, 
  4.     &ngx_http_upstream_ip_hash_module, 
  5.     &ngx_http_upstream_least_conn_module, 
  6.     &ngx_http_upstream_random_module, 
  7.     &ngx_http_upstream_keepalive_module, 
  8.     &ngx_http_upstream_zone_module, 
  9.     … … 
  10. }; 

注意,这个模块的顺序是从上到下执行的,而不是我们前面过滤模块的从下到上。

可以看到,zone 模块在最后,也就是说,上面各个算法定义的参数和配置,最终 zone 模块会把这些配置放到共享内存里面生效。

这一节介绍了负载均衡的原理以及四种负载均衡算法,也可以说是三种,就是轮询、哈希、最少连接数算法。每一种算法都有各自的应用场景,rr 算法是最基础的负载均衡算法,在某些情况下其他算法失效的时候,会退化为 rr 算法。

upstream 提供的变量

先来介绍一组不含缓存的变量。

来看一下刚才的实战中我们的例子。

在刚才的负载均衡实战中有一条日志的配置:

  1. log_format  varups  '$upstream_addr $upstream_connect_time $upstream_header_time $upstream_response_time ' 
  2.                         '$upstream_response_length $upstream_bytes_received ' 
  3.                         '$upstream_status $upstream_http_server $upstream_cache_status'

这条配置用到了我们上面提到的很多变量,对应输出的实际日志长这个样子:

  1. 127.0.0.1:8012 0.001 0.001 0.001 22 170 200 nginx/1.17.8 - 

大家可以对照日志格式看下分别代表什么意思,这里我就不细说了。

好了,今天这篇文章跟大家介绍了什么是负载均衡,Nginx 主要是通过 upstream 模块来提供对应的功能的,又介绍了负载均衡的四种算法,最后介绍了 upstream 中提供的变量。下一节课我们来说一说 Nginx 的反向代理。

 

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯