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

news2024/11/27 0:41:05

文章目录

  • 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释放前的资源释放工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/423785.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

应急响应 - Windows进程分析,Windows网络分析,tasklist,wmic process

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 进程网络排查一、Tasklist1、tasklist /v1、tasklist /svc2、tasklist /m二、wmic proces…

JAVAWeb02-CSS

1. CSS CSS 指的是层叠样式表 (Cascading Style Sheets) 1.1 概述 1.1.1 官方文档 地址: https://www.w3school.com.cn/css/index.asp 1.1.2 为什么需要 CSS 在没有 CSS 之前&#xff0c;我们想要修改 HTML 元素的样式需要为每个 HTML 元素单独定义样式属性&#xff0c;费心…

nodegui搭建/你好/打包

0、github连接问题 警告&#xff1a;如果你的网络有任何有任何有任何有任何有任何有任何有任何有任何有任何有任何连接 github 的问题&#xff0c;彻底放弃该框架 请转到其他框架 electron-egg教程、electron-egg官网&#xff0c;或其他electron项目 Tauri教程、Tauri官网 NW.…

Smartbi电子表格软件架构与差异化特色

选择和Excel结合Smartbi电子表格软件选择与Excel结合的原因在于&#xff0c;Excel一直被模仿&#xff0c;从未被超越。虽然市场上的报表软件很多&#xff0c;但存在太多的不完美。国外的产品功能复杂、难于学习&#xff08;控件方式&#xff09;&#xff0c;做不了中国式复杂格…

SpringBoot使用Redis实现分布式缓存

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Matlab群体智能优化算法之巨型睡莲优化算法(VAO)

Matlab群体智能优化算法之巨型睡莲优化算法(VAO) 摘要&#xff1a;介绍一种新型智能优化算法&#xff0c;巨型睡莲优化算法。其应用于24个基准测试函数&#xff0c;并与其他10个著名算法进行了比较。提出的算法在10个优化问题上进行了测试&#xff1a;最小生成树、枢纽位置分配…

技术复盘(4)--docker

技术复盘--docker资料地址环境初始docker安装dockerdocker常用命令-都需要先启动dockerdocker容器打包为镜像docker坑docker卸载docker数据卷dockerFile构建过程搭建私有仓库--非图形化界面搭建私有仓库--图形化界面docker理论知识资料地址 docker官网&#xff1a;https://www…

一种供水系统物联网监测系统

1.1供水系统 1.1.1监测范围选择依据 &#xff08;1&#xff09;管网老化区域管网 管网建设年代久远&#xff0c;通常管网发生破损问题较大&#xff0c;根据管网本身属性和历史发生事件的统计分析&#xff0c;结合数理统计&#xff0c;优先选择管网老化区域的管段所在区域进行…

基于imx8m plus开发板全体系开发教程4:Linux系统开发

前言&#xff1a; i.MX8M Plus 开发板是一款拥有 4 个 Cortex-A53 核心&#xff0c;运行频率 1.8GHz;1 个 Cortex-M7 核心&#xff0c;运行频率 800MHz;此外还集成了一个 2.3 TOPS 的 NPU&#xff0c;大大加速机器学习推理。 全文所使用的开发平台均为与NXP官方合作的FS-IMX8…

深入浅出Kafka

这个主题 武哥漫谈IT &#xff0c;作者骆俊武 讲得更好 一、什么是Kafka&#xff1f; 首先我们得去官网看看是怎么介绍Kafka的&#xff1a; https://kafka.apache.org/intro Apache Kafka is an open-source distributed event streaming platform. 翻译成中文就是&#xff1…

Git分布式版本控制软件

1.什么是git git是分布式版本控制软件。 软件&#xff1a;git是从别的地方下载下来安装到我们电脑上的软件。 版本控制&#xff1a;跟毕业论文一样&#xff0c;先写好版本1然后交给导师&#xff0c;导师说不行&#xff0c;然后再改为版本2&#xff0c;然后循环下去&#xff0…

Su+ELK实现网络监测(2)——ELK安装与配置

ELK安装配置文档一、环境准备基础配置二、Jdk1.8环境部署1、安装jdk2、编辑环境变量三、ElasticSearch部署1、安装2、修改文件所有者3、修改配置文件4、启动四、elasticsearch-head部署&#xff08;可不安装&#xff0c;跳过&#xff09;1、nodejs安装2、head插件安装3、修改he…

智慧工厂可视化合集,推动行业数字化转型

图扑软件基于 HTML5&#xff08;Canvas/WebGL/WebVR&#xff09;标准的 Web 技术&#xff0c;满足了工业物联网跨平台云端化部署实施的需求&#xff0c;以低代码的形式自由构建三维数字孪生、大屏可视化、工业组态等等。从 SDK 组件库&#xff0c;到 2D 和 3D 编辑&#xff0c;…

软化水处理知识总结

软化水除了广泛应用在饮用、浴室、厨房、洗衣等生活用水&#xff0c;和酒店、学校、写字楼、公寓、餐饮等商业用水的处理&#xff0c;还可用于锅炉、交换器、蒸发冷凝器、空调、直燃机等系统的补给水的软化。 那什么是软化水&#xff0c;和除盐水、纯水有什么区别&#xff1f;…

大学物理第四单元:刚体

1.刚体的定轴转动 思考&#xff1a;改变转动状态的因素 答&#xff1a;改变刚体运动状态的的因素有力的大小及力臂有关&#xff0c;力与力臂的乘积为力矩。 力臂&#xff1a;力到转轴的距离 简而言之&#xff0c;改变刚体运动状态的因素是力矩&#xff0c;与力和力臂有关。 …

谷粒学院项目笔记第一部分

1.环境搭建&#xff0c;准备工作 &#xff08;1&#xff09;创建数据库 &#xff08;2&#xff09;创建项目完整结构 &#xff08;3&#xff09;父工程springboot,子工程maven &#xff08;4&#xff09;父工程pom设置版本&#xff0c;添加pom #版本 <version>2.2.1.R…

11个AI写作软件工具!知名4A广告公司蓝标宣布停止文案外包!

AI的这场熊熊大火&#xff0c;终于还是烧到了广告界&#xff01; 2023年4月12日&#xff0c;是一个再普通不过的日子&#xff0c;但这一天会被很多人记住。不是因为席卷整个华北区的漫天黄沙&#xff0c;而是因为一封代表着AI势不可挡的决心和象征着一个行业巨变拉开序幕的邮件…

学会 制作极简搜索浏览器 —— 并将 ChatGPT 接入浏览器

前期回顾 Vue3 Ts Vite pnpm 项目中集成 —— eslint 、prettier、stylelint、husky、commitizen_0.活在风浪里的博客-CSDN博客搭建VIte Ts Vue3项目并集成eslint 、prettier、stylelint、huskyhttps://blog.csdn.net/m0_57904695/article/details/129950163?spm1001.2…

采用D-K迭代设计不确定对象的鲁棒控制器(μ-controllers)

采用D-K迭代设计不确定对象的鲁棒控制器&#xff0c;将H∞综合(K步)与μ分析(D步)相结合&#xff0c;优化闭环鲁棒性能。 Step 1&#xff1a;利用H∞综合方法找到使标称系统闭环增益最小的控制器。 Step 2&#xff1a;进行鲁棒性分析&#xff0c;以估计闭环系统的鲁棒H∞性能。…

手把手kubernetes本地化部署(含疑难杂症排查解析)

文章目录一、什么是Kubernetes&#xff1f;二、Kubernetes的基本概念PodDeploymentServiceNamespaceConfigMapSecret三、Kuberntes单机本地部署3.1、安装minikube命令行工具3.2、安装docker3.3、启动minikube3.4、使用Dashboard3.5、异常问题解决3.5.1、提示Docker失败3.5.2、d…