Nginx学习(9)—— 负载均衡模块

2023-05-16

文章目录

  • Nginx负载均衡模块
    • 负载均衡配置
    • 指令
    • 钩子
    • 初始化配置
    • 初始化请求
    • peer.get和peer.free回调函数
  • 小结

Nginx负载均衡模块

负载均衡模块用于从”upstream”指令定义的后端主机列表中选取一台主机。nginx先使用负载均衡模块找到一台主机,再使用upstream模块实现与这台主机的交互。

负载均衡配置

要了解负载均衡模块的开发方法,首先需要了解负载均衡模块的使用方法。因为负载均衡模块与之前提到的模块差别比较大,所以我们从配置入手比较容易理解。

  • 在nginx.conf配置文件中我们如果需要使用ip hash的负载均衡算法。我们需要写一个类似下面的配置:(负载均衡的简单配置可参考https://blog.csdn.net/Stars____/article/details/129381510?spm=1001.2014.3001.5501)
    upstream test {
    	ip_hash;
    	server 192.168.0.1;
    	server 192.168.0.2;
    }
    
    从配置我们可以看出负载均衡模块的使用场景:
    1. 核心指令”ip_hash”只能在upstream {}中使用。这条指令用于通知nginx使用ip hash负载均衡算法。如果没加这条指令,nginx会使用默认的round robin负载均衡模块。
    2. upstream {}中的指令可能出现在”server”指令前,可能出现在”server”指令后,也可能出现在两条”server”指令之间。
      • 两者有什么区别呢:看一下下面这条配置
        upstream test {
        	server 192.168.0.1 weight=5;
        	ip_hash;
        	server 192.168.0.2 weight=7;
        }
        
        此时报错:nginx: [emerg] invalid parameter "weight=7"
        可见ip_hash指令的确能影响到配置的解析的。

指令

看一下ip_hash指令的定义:

static ngx_command_t  ngx_http_upstream_ip_hash_commands[] = {

    { ngx_string("ip_hash"),
      NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,	// NGX_HTTP_UPS_CONF。这个属性表示该指令的适用范围是upstream{}
      ngx_http_upstream_ip_hash,
      0,
      0,
      NULL },

      ngx_null_command
};

钩子

  • ngx_http_upstream_ip_hash函数代码如下:

    static char *
    ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
    {
        ngx_http_upstream_srv_conf_t  *uscf;
    
        uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
    
        if (uscf->peer.init_upstream) {
            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                               "load balancing method redefined");
        }
    
        uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;
    
        uscf->flags = NGX_HTTP_UPSTREAM_CREATE
                      |NGX_HTTP_UPSTREAM_WEIGHT
                      |NGX_HTTP_UPSTREAM_MAX_CONNS
                      |NGX_HTTP_UPSTREAM_MAX_FAILS
                      |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
                      |NGX_HTTP_UPSTREAM_DOWN;
    
        return NGX_CONF_OK;
    }
    

    这段代码中有两点值得我们注意。一个是uscf->flags的设置,另一个是设置init_upstream回调。

    • 设置uscf->flags
      1. NGX_HTTP_UPSTREAM_CREATE:创建标志,如果含有创建标志的话,nginx会检查重复创建,以及必要参数是否填写。
      2. NGX_HTTP_UPSTREAM_MAX_FAILS:可以在server中使用max_fails属性。
      3. NGX_HTTP_UPSTREAM_FAIL_TIMEOUT:可以在server中使用fail_timeout属性。
      4. NGX_HTTP_UPSTREAM_DOWN:可以在server中使用down属性。
      5. NGX_HTTP_UPSTREAM_WEIGHT:可以在server中使用weight属性。
      6. NGX_HTTP_UPSTREAM_BACKUP:可以在server中使用backup属性。

    联想到刚刚遇到的那个神奇的配置错误,可以得出一个结论:在负载均衡模块的指令处理函数中可以设置并修改upstream{}中”server”指令支持的属性。

    这是一个很重要的性质,因为不同的负载均衡模块对各种属性的支持情况都是不一样的,那么就需要在解析配置文件的时候检测出是否使用了不支持的负载均衡属性并给出错误提示,这对于提升系统维护性是很有意义的。(也就是说,当解析到upstream中的ip_hash指令时检测是否使用了不支持的属性配置)

    但是,这种机制也存在缺陷,正如前面的例子所示,没有机制能够追加检查在更新支持属性之前已经配置了不支持属性的”server”指令。(好比ip_hash之前已经配置的weight=5的那一条server指令,是不能被ip_hash的钩子函数检查的)

    • 设置init_upstream回调
      nginx初始化upstream时,会在ngx_http_upstream_init_main_conf函数中调用设置好的初始化负载均衡模块的回调函数。
      umcf->upstreams数组中的每个元素对应upstream{}中的信息。
      uscfp = umcf->upstreams.elts;
      
      for (i = 0; i < umcf->upstreams.nelts; i++) {
      
          init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
                                              ngx_http_upstream_init_round_robin;
      
          if (init(cf, uscfp[i]) != NGX_OK) {
              return NGX_CONF_ERROR;
          }
      }
      

初始化配置

init_upstream回调函数执行时需要初始化负载均衡模块的配置,还要设置一个新钩子,这个钩子函数会在nginx处理每个请求
时作为初始化函数调用。

先看ip_hash模块初始化配置的代码:

static ngx_int_t
ngx_http_upstream_init_ip_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
{
    if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
        return NGX_ERROR;
    }

    us->peer.init = ngx_http_upstream_init_ip_hash_peer;

    return NGX_OK;
}

这段代码中 ip_hash 模块首先调用另一个负载均衡模块Round Robin的初始化函数,然后再设置自己的处理请求阶段初始化钩子。

实际上几个负载均衡模块可以组成一条链表,每次都是从链首的模块开始进行处理。如果模块决定不处理,可以将处理权交给链表中的下一个模块。

这里,ip_hash模块指定Round Robin模块作为自己的后继负载均衡模块,所以在自己的初始化配置函数中也对Round Robin模块进行初始化。

初始化请求

nginx收到一个请求以后,如果发现需要访问upstream,就会执行对应的peer.init函数。这是在初始化配置时设置的回调函数。这个函数最重要的作用是构造一张表,当前请求可以使用的upstream服务器被依次添加到这张表中。之所以需要这张表,最重要的原因是如果upstream服务器出现异常,不能提供服务时,可以从这张表中取得其他服务器进行重试操作。此外,这张表也可以用于负载均衡的计算。之所以构造这张表的行为放在这里而不是在前面初始化配置的阶段,是因为upstream需要为每一个请求提供独立隔离的环境。

ngx_http_upstream_init_ip_hash_peer 函数中部分代码如下:

// 设置数据指针,这个指针就是指向前面提到的那张表。
r->upstream->peer.data = &iphp->rrp;	

// 是调用Round Robin模块的回调函数对该模块进行请求初始化。
// 前面已经提到,一个负载均衡模块可以调用其他负载均衡模块以提供功能的补充。
if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
    return NGX_ERROR;
}

/*设置一个新的回调函数get。该函数负责从表中取出某个服务器。
除了get回调函数,还有另一个r->upstream->peer.free的回调函数。
该函数在upstream请求完成后调用,负责做一些善后工作。
比如我们需要维护一个upstream服务器访问计数器,那么可以在get函数中对其加1,在free中对其减1
如果是SSL的话,nginx还提供两个回调函数peer.set_session和peer.save_session*/
r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;

peer.get和peer.free回调函数

这两个函数是负载均衡模块最底层的函数,负责实际获取一个连接和回收一个连接的预备操作。之所以说是预备操作,是因为在这两个函数中,并不实际进行建立连接或者释放连接的动作,而只是执行获取连接的地址或维护连接状态的操作。需要理解的清楚一点,在peer.get函数中获取连接的地址信息,并不代表这时连接一定没有被建立,相反的,通过get函数的返回值,nginx可以了解是否存在可用连接,连接是否已经建立。这些返回值总结如下:

返回值说明nginx后续动作
NGX_DONE得到了连接地址信息,并且连接已经建立直接使用连接,发送数据
NGX_OK得到了连接地址信息,但连接并未建立建立连接,如连接不能立即建立,设置事件, 暂停执行本请求,执行别的请求
NGX_BUSY所有连接均不可用返回502错误至客户端

可能的疑问

  1. 什么时候连接是已经建立的?
    使用后端keepalive连接的时候,连接在使用完以后并不关闭,而是存放在一个队列中,新的请求只需要从队列中取出连接,这些连接都是已经准备好的。
  2. 什么叫所有连接均不可用?
    初始化请求的过程中,建立了一张表,get函数负责每次从这张表中不重复的取出一个连接,当无法从表中取得一个新的连接时,即所有连接均不可用
  3. 对于一个请求,peer.get函数可能被调用多次么?
    当某次peer.get函数得到的连接地址连接不上,或者请求对应的服务器得到异常响应,nginx会执行ngx_http_upstream_next,然后可能再次调用peer.get函数尝试别的连接
  4. upstream整体流程如下
    在这里插入图片描述

小结

以上内容是负载均衡模块的基本组成。

负载均衡模块的配置区集中在upstream{}块中。

负载均衡模块的回调函数体系是以init_upstream为起点,经历init_peer,最终到达peer.get和peer.free。

其中init_peer负责建立每个请求使用的server列表,peer.get负责从server列表中选择某个server(一般是不重复选择),而peer.free负责server释放前的资源释放工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Nginx学习(9)—— 负载均衡模块 的相关文章

  • Microsoft Edge 不会在 Vagrant VM 中加载本地 nginx 网站

    我遇到了一个奇怪的问题 Microsoft Edge 无法加载托管在 vagrant 虚拟机内的本地 Craft CMS 网站 任何加载本地配置的主机名或 IP 的尝试都会返回 嗯 我们无法访问此页面 错误 我的主机文件中有一行 192 1
  • 如何在uWSGI中配置允许的GET参数字符数?

    我正在使用 nginx uWSGI 运行 Django 刚刚从本地开发转移到临时服务器后 我发现我们发出的特定 GET 请求有一个很长的查询字符串 尝试调试 似乎 uWSGI 不接受这个基于长度的查询字符串 我可以传递短字符串并且它可以工作
  • 使用 Flask 代理到另一个 Web 服务

    我想将对 Flask 应用程序发出的请求代理到计算机上本地运行的另一个 Web 服务 我宁愿使用 Flask 而不是更高级别的 nginx 实例 这样我们就可以重用应用程序中内置的现有身份验证系统 我们越能保持这种 单点登录 越好 是否有现
  • 使用 apt-get install nginx 后重新编译 nginx

    我最初是通过 apt get install 安装 nginx 的 它工作得很好 现在 我想安装一些第 3 方模块 并且必须重新编译 nginx 所以我尝试重新编译 它只是走过场 然后我意识到我的原始版本仍然是正在使用的版本 我是否需要先卸
  • Sqlalchemy 返回 SELECT 命令的不同结果(query.all)

    我有网络服务器 512 RAM FLASK SQLAlchemy SQLite gt uWSGI gt Nginx 问题 Sqlalchemy 返回 SELECT 命令 query all 的不同结果 Example 在数据库中添加了一些记
  • Meteor - 自动发起客户端登录

    我有一个 Meteor 应用程序 我使用 nginx 和内部 SSO 服务进行身份验证 我能够成功地完成此操作 并在服务器 Meteor onConnection 方法上的 nginx 设置 http 标头中检索用户详细信息 此时 我不确定
  • Docker-nginx-反向代理:使用 docker-compose 构建时在上游找不到主机

    我正在使用 NGINX 容器将某些请求重定向到另一个容器 运行 docker compose up d 时 我收到以下错误 2019 09 26 18 05 00 emerg 1 1 在 etc nginx nginx conf 10 中的
  • 如何让 nginx 和乘客在部署后自动重启

    我目前在虚拟专用服务器上部署了一个 Rails 应用程序 我使用 Capistrano Nginx 和乘客在服务器上运行我的 Rails 应用程序 由于某种原因 在完成 cap 部署 更新后 我永远无法在网站上显示更新的代码 部署进行得很好
  • nginx 不为 ssl 中的 Rails 资产提供服务

    我正在我的 nginx nginx 版本 nginx 1 4 1 Ubuntu rails Rails 3 2 16 和 unicorn unicorn v4 7 0 vps 中安装自签名 ssl 证书 没有 ssl 一切看起来都很好 但自
  • 无法以 root 身份运行 uwsgi,“bind(): 权限被拒绝”

    我尝试使用此文档配置 uWsgi Django Nginx http uwsgi docs readthedocs org en latest tutorials Django and nginx html http uwsgi docs
  • 如何将 CORS(跨源策略)添加到 NGINX 中的所有域?

    我创建了一个文件夹 用于提供静态文件 CSS 图像 字体和 JS 等 我最终会将文件夹 CNAME 到子域中 以便在 CDN 上使用 以便与我的 Magento 2 设置一起使用 我想允许所有域通过 CORS 跨源策略进行所有访问 并且我也
  • 为从 nginx 反向代理转发的请求添加唯一 id

    我们运行 nginx 作为反向代理 将请求转发到运行 Compojure 的 Clojure 应用程序 Compojure 是一个封装 Jetty 的库 为我们的应用程序提供服务 Web 请求的能力 目前 我们捕获 nginx 和 Cloj
  • 如何在 Docker 容器中运行 Nginx 而不停止?

    我在 Docker 容器上安装了 Nginx 并尝试像这样运行它 docker run i t p 80 80 mydockerimage usr sbin nginx 问题是 Nginx 的工作方式是 初始进程立即生成一个 Nginx 主
  • uWSGI重启时停机

    每次当我有代码更新时重新启动服务器时 我都会遇到 uwsgi 问题 当我使用 sudo restart account 重新启动 uwsgi 时 停止和启动实例之间存在一个小间隙 导致停机并停止所有当前请求 当我尝试 sudo reload
  • ./manage.py 使用 https 运行服务器

    manage py 运行服务器 0 0 0 0 8000 我使用上面的行作为我从 github 借用的代码的一部分 https github com ribeiroit boh puppet https github com ribeiro
  • Kong - 验证上游 ssl(ssl_proxy 打开)

    我已经成功为 API 安装了 kong 网关 该 API 通过上游负载平衡到多个目标 应用程序服务器 现在 我有一个我的应用程序服务器的自签名证书 kong 和目标之间的 ssl 握手应该失败 我推断 kong 不验证上游证书 经过一些研究
  • 如何设置带有子域和反向代理且不使用启用站点的 nginxconf?

    我读到没有必要使用sites enabled https stackoverflow com questions 41303885 nginx do i really need sites available and sites enabl
  • 如何将多个域路由到多个节点应用程序?

    我习惯了典型的 Lamp Web 托管环境 您只需单击 cpanel 中的几个按钮 您的域就会被分区并映射到 htdocs 中的文件夹 我经常使用 Node js 但做同样的事情似乎并不那么简单 如果我有多个节点应用程序 并且我想将doma
  • nginx - 记录 SSL 握手失败

    我正在运行启用了 SSL 的 nginx 服务器 我的协议 密码设置相当安全 我已经在 ssllabs com 上检查过它们 但是 因为这是一个由我无法控制的 http 客户端调用的 Web 服务 所以我担心兼容性 重点是 有没有办法在我的
  • NGinx 域名重定向

    假设我有一个名为 xyz co 的网站 我还有其他具有相同前缀的域名 例如 xyz com xyz it xyz co it 现在 nginx 与端口 80 的 nginx conf 中的 server name xyz co 配合得很好

随机推荐

  • LivePlayer H5直播/点播播放器安装与使用

    LivePlayer H5播放器 简介 H5直播 点播播放器 xff0c 使用简单 xff0c 功能强大 xff0c 免费使用 支持m3u8播放 支持HTTP FLV播放 支持RTMP播放 支持直播和点播播放 支持播放器快照截图 支持点播多
  • Echarts 修改折线的颜色和折线的点的大小方法

    在做SPC分析的时候或者一些专业的分析的时候有的客户会要求 点的大小 样式等 具体的设置方法如下 series type 39 line 39 showSymbol true symbol 39 circle 39 设定为实心点 symbo
  • 抽象工厂模式

    抽象工厂模式针对的是对产品族 xff0c 而不是产品等级结构 产品族 xff1a 同一厂商生产的产品 产品等级 xff1a 同一产品 xff0c 不同厂商的产品 比如水果类里面由苹果和香蕉 xff0c 水果就是产品族 xff0c 苹果香蕉就
  • 面向对象单例模式

    单例模式 xff1a 一个类只能创建一个对象 span class token keyword class span span class token class name A span span class token punctuati
  • 设计模式之代理模式

    概念 xff1a 为其他对象提供一种代理 xff0c 用来控制对象的访问 在某些情况下 xff0c 一个对象不适合或不能直接引用另一个对象 xff0c 而代理对象可以在客户端和目标对象之间起到中介作用 span class token co
  • ARM接口技术基础

    ARM介绍 嵌入式系统 xff1a 嵌入式系统 61 嵌入式硬件 43 嵌入式软件 硬件是软件的载体 xff0c 软件是硬件的灵魂 嵌入式软件 xff1a 1 裸机 xff1a APP 2 系统 xff1a OS 43 APP 嵌入式硬件
  • ARM指令之MOV指令汇编与机器码的对应关系

    指令条件码 条件码就是一种简单的测试ALU状态标志位的方法 mov指令机器码 比如 xff1a mov r1 3 立即数 xff1a 3 第一个操作数 xff1a 寄存器1 S xff1a 0 xff08 注意 xff1a mov指令后面加
  • 设计模式之外观模式

    什么是外观模式 外观模式就是将一个复杂的子类系统抽象到同一个接口进行管理 外界只需要通过此接口与子类系统进行交互 xff0c 不需要直接与复杂的子类系统进行交互 外观模式属于结构型模式 外观模式案例 1 实现KTV模式 xff1a 打开电视
  • 设计模式之适配器模式

    概念 将一个类的接口转换成客户希望的另外一个接口 使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 用vector容器中的for each 举例子 span class token keyword class span span c
  • Qt基础学习笔记

    Qt中的常用快捷键 注释 xff1a ctrl 43 运行 xff1a ctrl 43 r 编译 xff1a ctrl 43 b 帮助文档 xff1a F1 自动对齐 xff1a ctrl 43 i 同名之间 h文件与 cpp文件的切换 x
  • Nginx学习 (1) —— 初识Nginx(编译安装、启动停止、简单配置)

    文章目录 Nginx的发行版本Nginx的编译安装 xff08 ubuntu18 04 xff09 Nginx相关操作Nginx启动停止命令安装Nginx为系统服务 Nginx的目录结构与基本原理目录结构 xff1a 基本运行原理 xff1
  • Nginx学习 (2) —— 虚拟主机配置

    文章目录 虚拟主机原理域名解析与泛域名解析 xff08 实践 xff09 配置文件中ServerName的匹配规则技术架构多用户二级域名短网址 虚拟主机原理 为什么需要虚拟主机 xff1a 当一台主机充当服务器给用户提供资源的时候 xff0
  • 如任让Echarts默认显示全部的数据(x轴(时间轴)默认显示查询到的所有数据)

    Echarts绘制折线图 有时候会用到时间轴 但是有时候时间轴默认显示的是部分数据 而不是全部的数据 当客户要求默认显示全部的数据的时候 就可以使用下面的方法 把dataZoom属性的startValue设置为0即可 dataZoom st
  • Nginx学习(3)—— 反向代理、负载均衡、动静分离、URLRewrite、防盗链

    文章目录 网关 代理与反向代理Nginx的反向代理配置基于反向代理的负载均衡的配置负载均衡策略负载均衡权重相关配置 xff08 weight xff09 动静分离Nginx配置动静分离 URL rewrite伪静态配置负载均衡 43 URL
  • Nginx学习(4)—— 高可用配置(keepalived实现Nginx的高可用)

    文章目录 高可用场景及解决方案keepalived的安装 高可用场景及解决方案 一般高可用的服务端会都有备用服务 xff0c 当某一个服务节点挂掉的时候就会有备用机顶上 这往往需要反向代理 Nginx 来将连接切换到可用的服务机器上 如下图
  • Nginx学习(5)—— 基本结构(源码)

    文章目录 Nginx源码学习基本数据结构1 字符串结构 xff1a ngx str t2 类似资源管理的结构 xff1a ngx pool t3 Nginx数组结构 xff1a ngx array t4 哈希表结构 xff1a 1 ngx
  • Nginx学习(6)—— handler模块(自定义handler配置模块的编码编译)

    文章目录 Nginx请求的处理handler简介handler模块的基本结构模块配置结构模块配置指令先看一下 ngx command t 结构 一个模块配置的demo简单模块配置的案例演示 模块上下文结构模块的定义handler模块的基本结
  • Nginx学习(7)—— 过滤模块(filter)

    文章目录 过滤模块简介执行时间和内容执行顺序Nginx是怎么按照次序依次来执行各个过滤模块的呢这些过滤模块的简述 xff08 按执行顺序 xff09 模块编译过滤模块分析相关结构体 响应头过滤函数响应体过滤函数主要功能介绍发出子请求优化措施
  • Nginx学习(8)—— upstream模块

    文章目录 upstream模块简介upstream模块接口memcached模块分析小结 upstream模块简介 nginx模块一般被分成三大类 xff1a handler filter和upstream 前面的章节中 xff0c 读者已
  • Nginx学习(9)—— 负载均衡模块

    文章目录 Nginx负载均衡模块负载均衡配置指令钩子初始化配置初始化请求peer get和peer free回调函数 小结 Nginx负载均衡模块 负载均衡模块用于从 upstream 指令定义的后端主机列表中选取一台主机 nginx先使用