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_stream.h>
0011 
0012 
0013 static ngx_int_t ngx_stream_upstream_init_least_conn_peer(
0014     ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us);
0015 static ngx_int_t ngx_stream_upstream_get_least_conn_peer(
0016     ngx_peer_connection_t *pc, void *data);
0017 static char *ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd,
0018     void *conf);
0019 
0020 
0021 static ngx_command_t  ngx_stream_upstream_least_conn_commands[] = {
0022 
0023     { ngx_string("least_conn"),
0024       NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS,
0025       ngx_stream_upstream_least_conn,
0026       0,
0027       0,
0028       NULL },
0029 
0030       ngx_null_command
0031 };
0032 
0033 
0034 static ngx_stream_module_t  ngx_stream_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 
0045 
0046 ngx_module_t  ngx_stream_upstream_least_conn_module = {
0047     NGX_MODULE_V1,
0048     &ngx_stream_upstream_least_conn_module_ctx, /* module context */
0049     ngx_stream_upstream_least_conn_commands, /* module directives */
0050     NGX_STREAM_MODULE,                       /* module type */
0051     NULL,                                    /* init master */
0052     NULL,                                    /* init module */
0053     NULL,                                    /* init process */
0054     NULL,                                    /* init thread */
0055     NULL,                                    /* exit thread */
0056     NULL,                                    /* exit process */
0057     NULL,                                    /* exit master */
0058     NGX_MODULE_V1_PADDING
0059 };
0060 
0061 
0062 static ngx_int_t
0063 ngx_stream_upstream_init_least_conn(ngx_conf_t *cf,
0064     ngx_stream_upstream_srv_conf_t *us)
0065 {
0066     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0,
0067                    "init least conn");
0068 
0069     if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) {
0070         return NGX_ERROR;
0071     }
0072 
0073     us->peer.init = ngx_stream_upstream_init_least_conn_peer;
0074 
0075     return NGX_OK;
0076 }
0077 
0078 
0079 static ngx_int_t
0080 ngx_stream_upstream_init_least_conn_peer(ngx_stream_session_t *s,
0081     ngx_stream_upstream_srv_conf_t *us)
0082 {
0083     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0084                    "init least conn peer");
0085 
0086     if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) {
0087         return NGX_ERROR;
0088     }
0089 
0090     s->upstream->peer.get = ngx_stream_upstream_get_least_conn_peer;
0091 
0092     return NGX_OK;
0093 }
0094 
0095 
0096 static ngx_int_t
0097 ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
0098 {
0099     ngx_stream_upstream_rr_peer_data_t *rrp = data;
0100 
0101     time_t                           now;
0102     uintptr_t                        m;
0103     ngx_int_t                        rc, total;
0104     ngx_uint_t                       i, n, p, many;
0105     ngx_stream_upstream_rr_peer_t   *peer, *best;
0106     ngx_stream_upstream_rr_peers_t  *peers;
0107 
0108     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0109                    "get least conn peer, try: %ui", pc->tries);
0110 
0111     if (rrp->peers->single) {
0112         return ngx_stream_upstream_get_round_robin_peer(pc, rrp);
0113     }
0114 
0115     pc->connection = NULL;
0116 
0117     now = ngx_time();
0118 
0119     peers = rrp->peers;
0120 
0121     ngx_stream_upstream_rr_peers_wlock(peers);
0122 
0123     best = NULL;
0124     total = 0;
0125 
0126 #if (NGX_SUPPRESS_WARN)
0127     many = 0;
0128     p = 0;
0129 #endif
0130 
0131     for (peer = peers->peer, i = 0;
0132          peer;
0133          peer = peer->next, i++)
0134     {
0135         n = i / (8 * sizeof(uintptr_t));
0136         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0137 
0138         if (rrp->tried[n] & m) {
0139             continue;
0140         }
0141 
0142         if (peer->down) {
0143             continue;
0144         }
0145 
0146         if (peer->max_fails
0147             && peer->fails >= peer->max_fails
0148             && now - peer->checked <= peer->fail_timeout)
0149         {
0150             continue;
0151         }
0152 
0153         if (peer->max_conns && peer->conns >= peer->max_conns) {
0154             continue;
0155         }
0156 
0157         /*
0158          * select peer with least number of connections; if there are
0159          * multiple peers with the same number of connections, select
0160          * based on round-robin
0161          */
0162 
0163         if (best == NULL
0164             || peer->conns * best->weight < best->conns * peer->weight)
0165         {
0166             best = peer;
0167             many = 0;
0168             p = i;
0169 
0170         } else if (peer->conns * best->weight == best->conns * peer->weight) {
0171             many = 1;
0172         }
0173     }
0174 
0175     if (best == NULL) {
0176         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0177                        "get least conn peer, no peer found");
0178 
0179         goto failed;
0180     }
0181 
0182     if (many) {
0183         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0184                        "get least conn peer, many");
0185 
0186         for (peer = best, i = p;
0187              peer;
0188              peer = peer->next, i++)
0189         {
0190             n = i / (8 * sizeof(uintptr_t));
0191             m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0192 
0193             if (rrp->tried[n] & m) {
0194                 continue;
0195             }
0196 
0197             if (peer->down) {
0198                 continue;
0199             }
0200 
0201             if (peer->conns * best->weight != best->conns * peer->weight) {
0202                 continue;
0203             }
0204 
0205             if (peer->max_fails
0206                 && peer->fails >= peer->max_fails
0207                 && now - peer->checked <= peer->fail_timeout)
0208             {
0209                 continue;
0210             }
0211 
0212             if (peer->max_conns && peer->conns >= peer->max_conns) {
0213                 continue;
0214             }
0215 
0216             peer->current_weight += peer->effective_weight;
0217             total += peer->effective_weight;
0218 
0219             if (peer->effective_weight < peer->weight) {
0220                 peer->effective_weight++;
0221             }
0222 
0223             if (peer->current_weight > best->current_weight) {
0224                 best = peer;
0225                 p = i;
0226             }
0227         }
0228     }
0229 
0230     best->current_weight -= total;
0231 
0232     if (now - best->checked > best->fail_timeout) {
0233         best->checked = now;
0234     }
0235 
0236     pc->sockaddr = best->sockaddr;
0237     pc->socklen = best->socklen;
0238     pc->name = &best->name;
0239 
0240     best->conns++;
0241 
0242     rrp->current = best;
0243 
0244     n = p / (8 * sizeof(uintptr_t));
0245     m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
0246 
0247     rrp->tried[n] |= m;
0248 
0249     ngx_stream_upstream_rr_peers_unlock(peers);
0250 
0251     return NGX_OK;
0252 
0253 failed:
0254 
0255     if (peers->next) {
0256         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0257                        "get least conn peer, backup servers");
0258 
0259         rrp->peers = peers->next;
0260 
0261         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
0262                 / (8 * sizeof(uintptr_t));
0263 
0264         for (i = 0; i < n; i++) {
0265             rrp->tried[i] = 0;
0266         }
0267 
0268         ngx_stream_upstream_rr_peers_unlock(peers);
0269 
0270         rc = ngx_stream_upstream_get_least_conn_peer(pc, rrp);
0271 
0272         if (rc != NGX_BUSY) {
0273             return rc;
0274         }
0275 
0276         ngx_stream_upstream_rr_peers_wlock(peers);
0277     }
0278 
0279     ngx_stream_upstream_rr_peers_unlock(peers);
0280 
0281     pc->name = peers->name;
0282 
0283     return NGX_BUSY;
0284 }
0285 
0286 
0287 static char *
0288 ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0289 {
0290     ngx_stream_upstream_srv_conf_t  *uscf;
0291 
0292     uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module);
0293 
0294     if (uscf->peer.init_upstream) {
0295         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
0296                            "load balancing method redefined");
0297     }
0298 
0299     uscf->peer.init_upstream = ngx_stream_upstream_init_least_conn;
0300 
0301     uscf->flags = NGX_STREAM_UPSTREAM_CREATE
0302                   |NGX_STREAM_UPSTREAM_WEIGHT
0303                   |NGX_STREAM_UPSTREAM_MAX_CONNS
0304                   |NGX_STREAM_UPSTREAM_MAX_FAILS
0305                   |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT
0306                   |NGX_STREAM_UPSTREAM_DOWN
0307                   |NGX_STREAM_UPSTREAM_BACKUP;
0308 
0309     return NGX_CONF_OK;
0310 }