NGX负载均衡策略

负载均衡策略


nginx的负载均衡策略可以划分为两大类:内置策略和扩展策略。内置策略包含加权轮询和ip hash,在默认情况下这两种策略会编译进nginx内核,只需在nginx配置中指明参数即可。扩展策略有很多,如fair、通用hash、consistent hash等,默认不编译进nginx内核,是第三方模块。

nginx 的 upstream目前支持 4 种方式的分配 :

1)轮询(默认) 

      每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 

2)weight 

      指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 

2)ip_hash 

      每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。  

3)fair(第三方) 

      按后端服务器的响应时间来分配请求,响应时间短的优先分配。  

4)url_hash(第三方)


Nginx默认采用round_robin加权算法。如果要选择其他的负载均衡算法,必须在upstream的配置上下文中通过配置指令ip_hash明确指定(该配置项最好放在其他server指令等的前面,以便检查server的配置选项是否合理)。比如采用Ip_hash的upstream配置如下所示:

  1. upstream load_balance{  
  2.     ip_hash;  
  3.     server localhost:8001;  
  4.     server localhost:8002;  
  5. }  

Load-blance模块中4个关键回调函数:
表1

回调指针

函数功能

round_robin模块

IP_hash模块

uscf->peer.init_upstream

解析配置文件过程中调用,根据upstream里各个server配置项做初始准备工作,另外的核心工作是设置回调指针us->peer.init。配置文件解析完后不再被调用

ngx_http_upstream_init_round_robin

设置:us->peer.init = ngx_http_upstream_init_round_robin_peer;

ngx_http_upstream_init_ip_hash

设置:us->peer.init = ngx_http_upstream_init_ip_hash_peer;

us->peer.init

在每一次Nginx准备转发客户端请求到后端服务器前都会调用该函数。该函数为本次转发选择合适的后端服务器做初始准备工作,另外的核心工作是设置回调指针r->upstream->peer.getr->upstream->peer.free

ngx_http_upstream_init_round_robin_peer

设置:r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;

r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;

ngx_http_upstream_init_ip_hash_peer

设置:r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;

r->upstream->peer.free为空

r->upstream->peer.get

在每一次Nginx准备转发客户端请求到后端服务器前都会调用该函数。该函数实现具体的位本次转发选择合适的后端服务器的算法逻辑,即完成选择获取合适后端服务器的功能

ngx_http_upstream_get_round_robin_peer

加权选择当前权值最高的后端服务器

ngx_http_upstream_get_ip_hash_peer

根据IP哈希值选择后端服务器

r->upstream->peer.free

在每一次Nginx完成与后端服务器之间的交互后都会调用该函数。

ngx_http_upstream_free_round_robin_peer

更新相关数值,比如rrp->current



当整个http配置块被Nginx解析完毕之后,会调用各个http模块对应的初始函数。对于模块ngx_http_upstream_module而言,对应的main配置初始函数是ngx_http_upstream_init_main_conf(),在这个函数中有这样一段代码:
  1. for (i = 0; i < umcf->upstreams.nelts; i++) {  
  2.   
  3.         init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:  
  4.                                             ngx_http_upstream_init_round_robin;  
  5.   
  6.         if (init(cf, uscfp[i]) != NGX_OK) {  
  7.             return NGX_CONF_ERROR;  
  8.         }  
  9. }  

默认采用加权轮询策略的原因就是在于上述代码中的init赋值一行。如果用户没有做任何策略选择,那么执行的策略初始函数为ngx_http_upstream_init_round_robin,也就是加权轮询策略。否则的话执行的是uscfp[i]->peer.init_upstream指针函数,如果有配置执行ip_hash ,那么就是ngx_http_upstream_init_ip_hash()。

加权轮询策略

全局准备工作


需要注意的是,配置文件中出现的参数只能和某些策略配合使用,所以如果发现某参数没有生效,则应该检查这一点。在配置解析的过程中,这些选项设置都被转换为Nginx内对于的变量值,对应的结构体ngx_http_upstream_server_t如下(ngx_http_upstream.h):
  1. typedef struct {  
  2.     ngx_addr_t                      *addrs;//指向存储IP地址的数组的指针,host信息(对应的是 ngx_url_t->addrs )  
  3.     ngx_uint_t                       naddrs;//与第一个参数配合使用,数组元素个数(对应的是 ngx_url_t->naddrs )  
  4.     ngx_uint_t                       weight;  
  5.     ngx_uint_t                       max_fails;  
  6.     time_t                           fail_timeout;  
  7.   
  8.     unsigned                         down:1;  
  9.     unsigned                         backup:1;  
  10. } ngx_http_upstream_server_t;  
这个阶段的函数是ngx_http_upstream_init_round_robin(),其主要完成的工作详见表1.

首先是设置了一个回调指针,这个函数用来针对每个请求选择后端服务器之前做一些初始化工作:
  1. us->peer.init = ngx_http_upstream_init_round_robin_peer;  

us类型是ngx_http_upstream_srv_conf_t:
  1. typedef struct ngx_http_upstream_srv_conf_s  ngx_http_upstream_srv_conf_t;  
  2.   
  3. struct ngx_http_upstream_srv_conf_s {  
  4.     ngx_http_upstream_peer_t         peer;  
  5.     void                           **srv_conf;//在 ngx_http_upstream()函数中被设置,指向的是本层的srv_conf  
  6.   
  7.     ngx_array_t                     *servers;  /*array of ngx_http_upstream_server_t */  
  8.   
  9.     ngx_uint_t                       flags;//调用函数时ngx_http_upstream_add() 指定的标记  
  10.     ngx_str_t                        host;//在函数 ngx_http_upstream_add() 中设置(e.g. upstream backend中的backend)  
  11.     u_char                          *file_name;//"/usr/local/nginx/conf/nginx.conf"  
  12.     ngx_uint_t                       line;//proxy在配置文件中的行号  
  13.     in_port_t                        port;//使用的端口号(ngx_http_upstream_add()函数中添加, 指向ngx_url_t-->port,通常在函数ngx_parse_inet_url()中解析)  
  14.     in_port_t                        default_port;//默认使用的端口号(ngx_http_upstream_add()函数中添加, 指向ngx_url_t-->default_port)  
  15.     ngx_uint_t                       no_port;  /* unsigned no_port:1 */  
  16. };  

而ngx_http_upstream_peer_t :
  1. typedef struct {  
  2.     //使用负载均衡的类型,默认采用 ngx_http_upstream_init_round_robin()  
  3.     ngx_http_upstream_init_pt        init_upstream;  
  4.     //使用的负载均衡类型的初始化函数  
  5.     ngx_http_upstream_init_peer_pt   init;  
  6.     //us->peer.data = peers; 指向的是 ngx_http_upstream_rr_peers_t(函数 ngx_http_upstream_init_round_robin()中设置)  
  7.     void                            *data;  
  8. } ngx_http_upstream_peer_t;  

ngx_http_upstream_init_peer_pt  是函数指针类型:
  1. typedef ngx_int_t (*ngx_http_upstream_init_peer_pt)(ngx_http_request_t *r,  
  2.     ngx_http_upstream_srv_conf_t *us);  
服务器类型ngx_http_upstream_server_t见前面的解释。

如果upstream中服务器为空,那么默认使用proxy_pass。将利用函数ngx_inet_resolve_host依据us参数中的host和port进行解析。将结果保存在一个ngx_url_t类型的变量中:
  1. typedef struct {  
  2.     ngx_str_t                 url;                  //保存IP地址+端口信息(e.g. 192.168.124.129:8011 或 money.163.com)  
  3.     ngx_str_t                 host;                 //保存IP地址信息  
  4.     ngx_str_t                 port_text;                //保存port字符串  
  5.     ngx_str_t                 uri;                  //uri部分,在函数ngx_parse_inet_url()中设置  
  6.   
  7.     in_port_t                 port;                 //端口,e.g. listen指令中指定的端口(listen 192.168.124.129:8011)  
  8.     in_port_t                 default_port;             //默认端口(当no_port字段为真时,将默认端口赋值给port字段, 默认端口通常是80)  
  9.     int                       family;                   //address family, AF_xxx  
  10.   
  11.     unsigned                  listen:1;             //是否为指监听类的设置  
  12.     unsigned                  uri_part:1;  
  13.     unsigned                  no_resolve:1;             //根据情况决定是否解析域名(将域名解析到IP地址)  
  14.     unsigned                  one_addr:1;               //等于1时,仅有一个IP地址  
  15.   
  16.     unsigned                  no_port:1;                //标识url中没有显示指定端口(为1时没有指定)  
  17.     unsigned                  wildcard:1;               //标识是否使用通配符(e.g. listen *:8000;)  
  18.   
  19.     socklen_t                 socklen;              //sizeof(struct sockaddr_in)  
  20.     u_char                    sockaddr[NGX_SOCKADDRLEN];        //sockaddr_in结构指向它  
  21.   
  22.     ngx_addr_t               *addrs;                //数组大小是naddrs字段;每个元素对应域名的IP地址信息(struct sockaddr_in),在函数中赋值(ngx_inet_resolve_host())  
  23.     ngx_uint_t                naddrs;               //url对应的IP地址个数,IP格式的地址将默认为1  
  24.   
  25.     char                     *err;                  //错误信息字符串  
  26. } ngx_url_t;  

此函数会创建后端服务器列表,并且将非后备服务器与后备服务器分开进行各自单独的链表。每一个后端服务器用一个结构体ngx_http_upstream_rr_peer_t与之对应(ngx_http_upstream_round_robin.h):
  1. typedef struct {  
  2.     struct sockaddr                *sockaddr;//后端服务器地址  
  3.     socklen_t                       socklen;//后端服务器地址长度  
  4.     ngx_str_t                       name;//后端名称  
  5.   
  6.     ngx_int_t                       current_weight;//当前权重,nginx会在运行过程中调整此权重  
  7.     ngx_int_t                       effective_weight;  
  8.     ngx_int_t                       weight;//配置的权重  
  9.   
  10.     ngx_uint_t                      fails;//已尝试失败次数  
  11.     time_t                          accessed;//检测失败时间,用于计算超时  
  12.     time_t                          checked;  
  13.   
  14.     ngx_uint_t                      max_fails;//最大失败次数  
  15.     time_t                          fail_timeout;//多长时间内出现max_fails次失败便认为后端down掉了  
  16.   
  17.     ngx_uint_t                      down;          /* unsigned  down:1; *///指定某后端是否挂了  
  18.   
  19. #if (NGX_HTTP_SSL)  
  20.     ngx_ssl_session_t              *ssl_session;   /* local to a process */  
  21. #endif  
  22. } ngx_http_upstream_rr_peer_t;  

列表最前面需要带有一些head信息,用结构体ngx_http_upstream_rr_peers_t与之对应:
  1. typedef struct ngx_http_upstream_rr_peers_s  ngx_http_upstream_rr_peers_t;  
  2.   
  3. struct ngx_http_upstream_rr_peers_s {  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值