在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
负载均衡模块负载均衡模块用于从 配置要了解负载均衡模块的开发方法,首先需要了解负载均衡模块的使用方法。因为负载均衡模块与之前书中提到的模块差别比较大,所以我们从配置入手比较容易理解。 在配置文件中,我们如果需要使用 ip hash 的负载均衡算法。我们需要写一个类似下面的配置:
从配置我们可以看出负载均衡模块的使用场景:
神奇的事情出现了:
可见 ip_hash 指令的确能影响到配置的解析。 指令配置决定指令系统,现在就来看 ip_hash 的指令定义:
没有特别的东西,除了指令属性是 NGX_HTTP_UPS_CONF。这个属性表示该指令的适用范围是 upstream{}。 钩子以从前面的章节得到的经验,大家应该知道这里就是模块的切入点了。负载均衡模块的钩子代码都是有规律的,这里通过 ip_hash 模块来分析这个规律。
这段代码中有两点值得我们注意。一个是 uscf->flags 的设置,另一个是设置 init_upstream 回调。 设置 uscf->flags
聪明的读者如果联想到刚刚遇到的那个神奇的配置错误,可以得出一个结论:在负载均衡模块的指令处理函数中可以设置并修改 upstream{} 中 设置 init_upstream 回调Nginx 初始化 upstream 时,会在 ngx_http_upstream_init_main_conf 函数中调用设置的回调函数初始化负载均衡模块。这里不太好理解的是 uscf 的具体位置。通过下面的示意图,说明 upstream 负载均衡模块的配置的内存布局。 从图上可以看出,MAIN_CONF 中 ngx_upstream_module 模块的配置项中有一个指针数组 upstreams,数组中的每个元素对应就是配置文件中每一个 upstream{}的信息。更具体的将会在后面的原理篇讨论。 初始化配置init_upstream 回调函数执行时需要初始化负载均衡模块的配置,还要设置一个新钩子,这个钩子函数会在 Nginx 处理每个请求时作为初始化函数调用,关于这个新钩子函数的功能,后面会有详细的描述。这里,我们先分析 IP hash 模块初始化配置的代码:
这段代码非常简单:IP hash 模块首先调用另一个负载均衡模块 Round Robin 的初始化函数,然后再设置自己的处理请求阶段初始化钩子。实际上几个负载均衡模块可以组成一条链表,每次都是从链首的模块开始进行处理。如果模块决定不处理,可以将处理权交给链表中的下一个模块。这里,IP hash 模块指定 Round Robin 模块作为自己的后继负载均衡模块,所以在自己的初始化配置函数中也对 Round Robin 模块进行初始化。 初始化请求Nginx 收到一个请求以后,如果发现需要访问 upstream,就会执行对应的 peer.init 函数。这是在初始化配置时设置的回调函数。这个函数最重要的作用是构造一张表,当前请求可以使用的 upstream 服务器被依次添加到这张表中。之所以需要这张表,最重要的原因是如果 upstream 服务器出现异常,不能提供服务时,可以从这张表中取得其他服务器进行重试操作。此外,这张表也可以用于负载均衡的计算。之所以构造这张表的行为放在这里而不是在前面初始化配置的阶段,是因为upstream需要为每一个请求提供独立隔离的环境。 为了讨论 peer.init 的核心,我们还是看 IP hash 模块的实现:
第一行是设置数据指针,这个指针就是指向前面提到的那张表; 第二行是调用 Round Robin 模块的回调函数对该模块进行请求初始化。面前已经提到,一个负载均衡模块可以调用其他负载均衡模块以提供功能的补充。 第三行是设置一个新的回调函数get。该函数负责从表中取出某个服务器。除了 get 回调函数,还有另一个 peer.get 和 peer.free 回调函数这两个函数是负载均衡模块最底层的函数,负责实际获取一个连接和回收一个连接的预备操作。之所以说是预备操作,是因为在这两个函数中,并不实际进行建立连接或者释放连接的动作,而只是执行获取连接的地址或维护连接状态的操作。需要理解的清楚一点,在 peer.get 函数中获取连接的地址信息,并不代表这时连接一定没有被建立,相反的,通过 get 函数的返回值,Nginx 可以了解是否存在可用连接,连接是否已经建立。这些返回值总结如下:
各位读者看到上面这张表,可能会有几个问题浮现出来: Q: 什么时候连接是已经建立的? A: 使用后端 keepalive 连接的时候,连接在使用完以后并不关闭,而是存放在一个队列中,新的请求只需要从队列中取出连接,这些连接都是已经准备好的。 Q: 什么叫所有连接均不可用? A: 初始化请求的过程中,建立了一张表,get 函数负责每次从这张表中不重复的取出一个连接,当无法从表中取得一个新的连接时,即所有连接均不可用。 Q: 对于一个请求,peer.get 函数可能被调用多次么? A: 正式如此。当某次 peer.get 函数得到的连接地址连接不上,或者请求对应的服务器得到异常响应,Nginx 会执行 ngx_http_upstream_next,然后可能再次调用 peer.get 函数尝试别的连接。upstream 整体流程如下: 本节回顾这一节介绍了负载均衡模块的基本组成。负载均衡模块的配置区集中在 upstream{}块中。负载均衡模块的回调函数体系是以 init_upstream 为起点,经历 init_peer,最终到达 peer.get 和 peer.free。其中 init_peer 负责建立每个请求使用的 server 列表,peer.get 负责从 server 列表中选择某个 server(一般是不重复选择),而 peer.free 负责 server 释放前的资源释放工作。最后,这一节通过一张图将 upstream 模块和负载均衡模块在请求处理过程中的相互关系展现出来。 |
请发表评论