Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Maxim Dounin
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
0014     ngx_http_upstream_srv_conf_t *us);
0015 static ngx_int_t ngx_http_upstream_get_least_conn_peer(
0016     ngx_peer_connection_t *pc, void *data);
0017 static char *ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd,
0018     void *conf);
0019 
0020 
0021 static ngx_command_t  ngx_http_upstream_least_conn_commands[] = {
0022 
0023     { ngx_string("least_conn"),
0024       NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
0025       ngx_http_upstream_least_conn,
0026       0,
0027       0,
0028       NULL },
0029 
0030       ngx_null_command
0031 };
0032 
0033 
0034 static ngx_http_module_t  ngx_http_upstream_least_conn_module_ctx = {
0035     NULL,                                  /* preconfiguration */
0036     NULL,                                  /* postconfiguration */
0037 
0038     NULL,                                  /* create main configuration */
0039     NULL,                                  /* init main configuration */
0040 
0041     NULL,                                  /* create server configuration */
0042     NULL,                                  /* merge server configuration */
0043 
0044     NULL,                                  /* create location configuration */
0045     NULL                                   /* merge location configuration */
0046 };
0047 
0048 
0049 ngx_module_t  ngx_http_upstream_least_conn_module = {
0050     NGX_MODULE_V1,
0051     &ngx_http_upstream_least_conn_module_ctx, /* module context */
0052     ngx_http_upstream_least_conn_commands, /* module directives */
0053     NGX_HTTP_MODULE,                       /* module type */
0054     NULL,                                  /* init master */
0055     NULL,                                  /* init module */
0056     NULL,                                  /* init process */
0057     NULL,                                  /* init thread */
0058     NULL,                                  /* exit thread */
0059     NULL,                                  /* exit process */
0060     NULL,                                  /* exit master */
0061     NGX_MODULE_V1_PADDING
0062 };
0063 
0064 
0065 static ngx_int_t
0066 ngx_http_upstream_init_least_conn(ngx_conf_t *cf,
0067     ngx_http_upstream_srv_conf_t *us)
0068 {
0069     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
0070                    "init least conn");
0071 
0072     if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
0073         return NGX_ERROR;
0074     }
0075 
0076     us->peer.init = ngx_http_upstream_init_least_conn_peer;
0077 
0078     return NGX_OK;
0079 }
0080 
0081 
0082 static ngx_int_t
0083 ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
0084     ngx_http_upstream_srv_conf_t *us)
0085 {
0086     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0087                    "init least conn peer");
0088 
0089     if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
0090         return NGX_ERROR;
0091     }
0092 
0093     r->upstream->peer.get = ngx_http_upstream_get_least_conn_peer;
0094 
0095     return NGX_OK;
0096 }
0097 
0098 
0099 static ngx_int_t
0100 ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
0101 {
0102     ngx_http_upstream_rr_peer_data_t  *rrp = data;
0103 
0104     time_t                         now;
0105     uintptr_t                      m;
0106     ngx_int_t                      rc, total;
0107     ngx_uint_t                     i, n, p, many;
0108     ngx_http_upstream_rr_peer_t   *peer, *best;
0109     ngx_http_upstream_rr_peers_t  *peers;
0110 
0111     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0112                    "get least conn peer, try: %ui", pc->tries);
0113 
0114     if (rrp->peers->single) {
0115         return ngx_http_upstream_get_round_robin_peer(pc, rrp);
0116     }
0117 
0118     pc->cached = 0;
0119     pc->connection = NULL;
0120 
0121     now = ngx_time();
0122 
0123     peers = rrp->peers;
0124 
0125     ngx_http_upstream_rr_peers_wlock(peers);
0126 
0127     best = NULL;
0128     total = 0;
0129 
0130 #if (NGX_SUPPRESS_WARN)
0131     many = 0;
0132     p = 0;
0133 #endif
0134 
0135     for (peer = peers->peer, i = 0;
0136          peer;
0137          peer = peer->next, i++)
0138     {
0139         n = i / (8 * sizeof(uintptr_t));
0140         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0141 
0142         if (rrp->tried[n] & m) {
0143             continue;
0144         }
0145 
0146         if (peer->down) {
0147             continue;
0148         }
0149 
0150         if (peer->max_fails
0151             && peer->fails >= peer->max_fails
0152             && now - peer->checked <= peer->fail_timeout)
0153         {
0154             continue;
0155         }
0156 
0157         if (peer->max_conns && peer->conns >= peer->max_conns) {
0158             continue;
0159         }
0160 
0161         /*
0162          * select peer with least number of connections; if there are
0163          * multiple peers with the same number of connections, select
0164          * based on round-robin
0165          */
0166 
0167         if (best == NULL
0168             || peer->conns * best->weight < best->conns * peer->weight)
0169         {
0170             best = peer;
0171             many = 0;
0172             p = i;
0173 
0174         } else if (peer->conns * best->weight == best->conns * peer->weight) {
0175             many = 1;
0176         }
0177     }
0178 
0179     if (best == NULL) {
0180         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0181                        "get least conn peer, no peer found");
0182 
0183         goto failed;
0184     }
0185 
0186     if (many) {
0187         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0188                        "get least conn peer, many");
0189 
0190         for (peer = best, i = p;
0191              peer;
0192              peer = peer->next, i++)
0193         {
0194             n = i / (8 * sizeof(uintptr_t));
0195             m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0196 
0197             if (rrp->tried[n] & m) {
0198                 continue;
0199             }
0200 
0201             if (peer->down) {
0202                 continue;
0203             }
0204 
0205             if (peer->conns * best->weight != best->conns * peer->weight) {
0206                 continue;
0207             }
0208 
0209             if (peer->max_fails
0210                 && peer->fails >= peer->max_fails
0211                 && now - peer->checked <= peer->fail_timeout)
0212             {
0213                 continue;
0214             }
0215 
0216             if (peer->max_conns && peer->conns >= peer->max_conns) {
0217                 continue;
0218             }
0219 
0220             peer->current_weight += peer->effective_weight;
0221             total += peer->effective_weight;
0222 
0223             if (peer->effective_weight < peer->weight) {
0224                 peer->effective_weight++;
0225             }
0226 
0227             if (peer->current_weight > best->current_weight) {
0228                 best = peer;
0229                 p = i;
0230             }
0231         }
0232     }
0233 
0234     best->current_weight -= total;
0235 
0236     if (now - best->checked > best->fail_timeout) {
0237         best->checked = now;
0238     }
0239 
0240     pc->sockaddr = best->sockaddr;
0241     pc->socklen = best->socklen;
0242     pc->name = &best->name;
0243 
0244     best->conns++;
0245 
0246     rrp->current = best;
0247 
0248     n = p / (8 * sizeof(uintptr_t));
0249     m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
0250 
0251     rrp->tried[n] |= m;
0252 
0253     ngx_http_upstream_rr_peers_unlock(peers);
0254 
0255     return NGX_OK;
0256 
0257 failed:
0258 
0259     if (peers->next) {
0260         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0261                        "get least conn peer, backup servers");
0262 
0263         rrp->peers = peers->next;
0264 
0265         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
0266                 / (8 * sizeof(uintptr_t));
0267 
0268         for (i = 0; i < n; i++) {
0269             rrp->tried[i] = 0;
0270         }
0271 
0272         ngx_http_upstream_rr_peers_unlock(peers);
0273 
0274         rc = ngx_http_upstream_get_least_conn_peer(pc, rrp);
0275 
0276         if (rc != NGX_BUSY) {
0277             return rc;
0278         }
0279 
0280         ngx_http_upstream_rr_peers_wlock(peers);
0281     }
0282 
0283     ngx_http_upstream_rr_peers_unlock(peers);
0284 
0285     pc->name = peers->name;
0286 
0287     return NGX_BUSY;
0288 }
0289 
0290 
0291 static char *
0292 ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0293 {
0294     ngx_http_upstream_srv_conf_t  *uscf;
0295 
0296     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
0297 
0298     if (uscf->peer.init_upstream) {
0299         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
0300                            "load balancing method redefined");
0301     }
0302 
0303     uscf->peer.init_upstream = ngx_http_upstream_init_least_conn;
0304 
0305     uscf->flags = NGX_HTTP_UPSTREAM_CREATE
0306                   |NGX_HTTP_UPSTREAM_WEIGHT
0307                   |NGX_HTTP_UPSTREAM_MAX_CONNS
0308                   |NGX_HTTP_UPSTREAM_MAX_FAILS
0309                   |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
0310                   |NGX_HTTP_UPSTREAM_DOWN
0311                   |NGX_HTTP_UPSTREAM_BACKUP;
0312 
0313     return NGX_CONF_OK;
0314 }