src/http/modules/ngx_http_upstream_least_conn_module.c - nginx-1.31.3 nginx/ @ 42f8df65b

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Maxim Dounin
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
  9.     ngx_http_upstream_srv_conf_t *us);
  10. static ngx_int_t ngx_http_upstream_get_least_conn_peer(
  11.     ngx_peer_connection_t *pc, void *data);
  12. static char *ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd,
  13.     void *conf);


  14. static ngx_command_t  ngx_http_upstream_least_conn_commands[] = {

  15.     { ngx_string("least_conn"),
  16.       NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
  17.       ngx_http_upstream_least_conn,
  18.       0,
  19.       0,
  20.       NULL },

  21.       ngx_null_command
  22. };


  23. static ngx_http_module_t  ngx_http_upstream_least_conn_module_ctx = {
  24.     NULL,                                  /* preconfiguration */
  25.     NULL,                                  /* postconfiguration */

  26.     NULL,                                  /* create main configuration */
  27.     NULL,                                  /* init main configuration */

  28.     NULL,                                  /* create server configuration */
  29.     NULL,                                  /* merge server configuration */

  30.     NULL,                                  /* create location configuration */
  31.     NULL                                   /* merge location configuration */
  32. };


  33. ngx_module_t  ngx_http_upstream_least_conn_module = {
  34.     NGX_MODULE_V1,
  35.     &ngx_http_upstream_least_conn_module_ctx, /* module context */
  36.     ngx_http_upstream_least_conn_commands, /* module directives */
  37.     NGX_HTTP_MODULE,                       /* module type */
  38.     NULL,                                  /* init master */
  39.     NULL,                                  /* init module */
  40.     NULL,                                  /* init process */
  41.     NULL,                                  /* init thread */
  42.     NULL,                                  /* exit thread */
  43.     NULL,                                  /* exit process */
  44.     NULL,                                  /* exit master */
  45.     NGX_MODULE_V1_PADDING
  46. };


  47. static ngx_int_t
  48. ngx_http_upstream_init_least_conn(ngx_conf_t *cf,
  49.     ngx_http_upstream_srv_conf_t *us)
  50. {
  51.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
  52.                    "init least conn");

  53.     if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
  54.         return NGX_ERROR;
  55.     }

  56.     us->peer.init = ngx_http_upstream_init_least_conn_peer;

  57.     return NGX_OK;
  58. }


  59. static ngx_int_t
  60. ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
  61.     ngx_http_upstream_srv_conf_t *us)
  62. {
  63.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  64.                    "init least conn peer");

  65.     if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
  66.         return NGX_ERROR;
  67.     }

  68.     r->upstream->peer.get = ngx_http_upstream_get_least_conn_peer;

  69.     return NGX_OK;
  70. }


  71. static ngx_int_t
  72. ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
  73. {
  74.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  75.     time_t                         now;
  76.     uintptr_t                      m;
  77.     ngx_int_t                      rc, total;
  78.     ngx_uint_t                     i, n, p, many;
  79.     ngx_http_upstream_rr_peer_t   *peer, *best;
  80.     ngx_http_upstream_rr_peers_t  *peers;

  81.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  82.                    "get least conn peer, try: %ui", pc->tries);

  83.     if (rrp->peers->single) {
  84.         return ngx_http_upstream_get_round_robin_peer(pc, rrp);
  85.     }

  86.     pc->cached = 0;
  87.     pc->connection = NULL;

  88.     now = ngx_time();

  89.     peers = rrp->peers;

  90.     ngx_http_upstream_rr_peers_wlock(peers);

  91. #if (NGX_HTTP_UPSTREAM_ZONE)
  92.     if (peers->config && rrp->config != *peers->config) {
  93.         goto busy;
  94.     }
  95. #endif

  96.     best = NULL;
  97.     total = 0;

  98. #if (NGX_SUPPRESS_WARN)
  99.     many = 0;
  100.     p = 0;
  101. #endif

  102. #if (NGX_HTTP_UPSTREAM_SID)
  103.     best = ngx_http_upstream_get_rr_peer_by_sid(rrp, pc->hint, &p, 0);

  104.     if (best) {
  105.         goto best_chosen;
  106.     }
  107. #endif

  108.     for (peer = peers->peer, i = 0;
  109.          peer;
  110.          peer = peer->next, i++)
  111.     {
  112.         n = i / (8 * sizeof(uintptr_t));
  113.         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  114.         if (rrp->tried[n] & m) {
  115.             continue;
  116.         }

  117.         if (peer->down) {
  118.             continue;
  119.         }

  120.         if (peer->max_fails
  121.             && peer->fails >= peer->max_fails
  122.             && now - peer->checked <= peer->fail_timeout)
  123.         {
  124.             continue;
  125.         }

  126.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  127.             continue;
  128.         }

  129.         /*
  130.          * select peer with least number of connections; if there are
  131.          * multiple peers with the same number of connections, select
  132.          * based on round-robin
  133.          */

  134.         if (best == NULL
  135.             || peer->conns * best->weight < best->conns * peer->weight)
  136.         {
  137.             best = peer;
  138.             many = 0;
  139.             p = i;

  140.         } else if (peer->conns * best->weight == best->conns * peer->weight) {
  141.             many = 1;
  142.         }
  143.     }

  144.     if (best == NULL) {
  145.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  146.                        "get least conn peer, no peer found");

  147.         goto failed;
  148.     }

  149.     if (many) {
  150.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  151.                        "get least conn peer, many");

  152.         for (peer = best, i = p;
  153.              peer;
  154.              peer = peer->next, i++)
  155.         {
  156.             n = i / (8 * sizeof(uintptr_t));
  157.             m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  158.             if (rrp->tried[n] & m) {
  159.                 continue;
  160.             }

  161.             if (peer->down) {
  162.                 continue;
  163.             }

  164.             if (peer->conns * best->weight != best->conns * peer->weight) {
  165.                 continue;
  166.             }

  167.             if (peer->max_fails
  168.                 && peer->fails >= peer->max_fails
  169.                 && now - peer->checked <= peer->fail_timeout)
  170.             {
  171.                 continue;
  172.             }

  173.             if (peer->max_conns && peer->conns >= peer->max_conns) {
  174.                 continue;
  175.             }

  176.             peer->current_weight += peer->effective_weight;
  177.             total += peer->effective_weight;

  178.             if (peer->effective_weight < peer->weight) {
  179.                 peer->effective_weight++;
  180.             }

  181.             if (peer->current_weight > best->current_weight) {
  182.                 best = peer;
  183.                 p = i;
  184.             }
  185.         }
  186.     }

  187.     best->current_weight -= total;

  188. #if (NGX_HTTP_UPSTREAM_SID)
  189. best_chosen:
  190. #endif

  191.     if (now - best->checked > best->fail_timeout) {
  192.         best->checked = now;
  193.     }

  194.     pc->sockaddr = best->sockaddr;
  195.     pc->socklen = best->socklen;
  196.     pc->name = &best->name;

  197. #if (NGX_HTTP_UPSTREAM_SID)
  198.     pc->sid = &best->sid;
  199. #endif

  200.     best->conns++;

  201.     rrp->current = best;
  202.     ngx_http_upstream_rr_peer_ref(peers, best);

  203.     n = p / (8 * sizeof(uintptr_t));
  204.     m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));

  205.     rrp->tried[n] |= m;

  206.     ngx_http_upstream_rr_peers_unlock(peers);

  207.     return NGX_OK;

  208. failed:

  209.     if (peers->next) {
  210.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  211.                        "get least conn peer, backup servers");

  212.         rrp->peers = peers->next;

  213.         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
  214.                 / (8 * sizeof(uintptr_t));

  215.         for (i = 0; i < n; i++) {
  216.             rrp->tried[i] = 0;
  217.         }

  218.         ngx_http_upstream_rr_peers_unlock(peers);

  219.         rc = ngx_http_upstream_get_least_conn_peer(pc, rrp);

  220.         if (rc != NGX_BUSY) {
  221.             return rc;
  222.         }

  223.         ngx_http_upstream_rr_peers_wlock(peers);
  224.     }

  225. #if (NGX_HTTP_UPSTREAM_ZONE)
  226. busy:
  227. #endif

  228.     ngx_http_upstream_rr_peers_unlock(peers);

  229.     pc->name = peers->name;

  230.     return NGX_BUSY;
  231. }


  232. static char *
  233. ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  234. {
  235.     ngx_http_upstream_srv_conf_t  *uscf;

  236.     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);

  237.     if (uscf->peer.init_upstream) {
  238.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  239.                            "load balancing method redefined");
  240.     }

  241.     uscf->peer.init_upstream = ngx_http_upstream_init_least_conn;

  242.     uscf->flags = NGX_HTTP_UPSTREAM_CREATE
  243.                   |NGX_HTTP_UPSTREAM_MODIFY
  244.                   |NGX_HTTP_UPSTREAM_WEIGHT
  245.                   |NGX_HTTP_UPSTREAM_MAX_CONNS
  246.                   |NGX_HTTP_UPSTREAM_MAX_FAILS
  247.                   |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
  248.                   |NGX_HTTP_UPSTREAM_DOWN
  249.                   |NGX_HTTP_UPSTREAM_BACKUP;

  250.     return NGX_CONF_OK;
  251. }