src/http/modules/ngx_http_upstream_least_conn_module.c - nginx source code

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.     for (peer = peers->peer, i = 0;
  103.          peer;
  104.          peer = peer->next, i++)
  105.     {
  106.         n = i / (8 * sizeof(uintptr_t));
  107.         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  108.         if (rrp->tried[n] & m) {
  109.             continue;
  110.         }

  111.         if (peer->down) {
  112.             continue;
  113.         }

  114.         if (peer->max_fails
  115.             && peer->fails >= peer->max_fails
  116.             && now - peer->checked <= peer->fail_timeout)
  117.         {
  118.             continue;
  119.         }

  120.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  121.             continue;
  122.         }

  123.         /*
  124.          * select peer with least number of connections; if there are
  125.          * multiple peers with the same number of connections, select
  126.          * based on round-robin
  127.          */

  128.         if (best == NULL
  129.             || peer->conns * best->weight < best->conns * peer->weight)
  130.         {
  131.             best = peer;
  132.             many = 0;
  133.             p = i;

  134.         } else if (peer->conns * best->weight == best->conns * peer->weight) {
  135.             many = 1;
  136.         }
  137.     }

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

  141.         goto failed;
  142.     }

  143.     if (many) {
  144.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  145.                        "get least conn peer, many");

  146.         for (peer = best, i = p;
  147.              peer;
  148.              peer = peer->next, i++)
  149.         {
  150.             n = i / (8 * sizeof(uintptr_t));
  151.             m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  152.             if (rrp->tried[n] & m) {
  153.                 continue;
  154.             }

  155.             if (peer->down) {
  156.                 continue;
  157.             }

  158.             if (peer->conns * best->weight != best->conns * peer->weight) {
  159.                 continue;
  160.             }

  161.             if (peer->max_fails
  162.                 && peer->fails >= peer->max_fails
  163.                 && now - peer->checked <= peer->fail_timeout)
  164.             {
  165.                 continue;
  166.             }

  167.             if (peer->max_conns && peer->conns >= peer->max_conns) {
  168.                 continue;
  169.             }

  170.             peer->current_weight += peer->effective_weight;
  171.             total += peer->effective_weight;

  172.             if (peer->effective_weight < peer->weight) {
  173.                 peer->effective_weight++;
  174.             }

  175.             if (peer->current_weight > best->current_weight) {
  176.                 best = peer;
  177.                 p = i;
  178.             }
  179.         }
  180.     }

  181.     best->current_weight -= total;

  182.     if (now - best->checked > best->fail_timeout) {
  183.         best->checked = now;
  184.     }

  185.     pc->sockaddr = best->sockaddr;
  186.     pc->socklen = best->socklen;
  187.     pc->name = &best->name;

  188.     best->conns++;

  189.     rrp->current = best;
  190.     ngx_http_upstream_rr_peer_ref(peers, best);

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

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

  194.     ngx_http_upstream_rr_peers_unlock(peers);

  195.     return NGX_OK;

  196. failed:

  197.     if (peers->next) {
  198.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  199.                        "get least conn peer, backup servers");

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

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

  203.         for (i = 0; i < n; i++) {
  204.             rrp->tried[i] = 0;
  205.         }

  206.         ngx_http_upstream_rr_peers_unlock(peers);

  207.         rc = ngx_http_upstream_get_least_conn_peer(pc, rrp);

  208.         if (rc != NGX_BUSY) {
  209.             return rc;
  210.         }

  211.         ngx_http_upstream_rr_peers_wlock(peers);
  212.     }

  213. #if (NGX_HTTP_UPSTREAM_ZONE)
  214. busy:
  215. #endif

  216.     ngx_http_upstream_rr_peers_unlock(peers);

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

  218.     return NGX_BUSY;
  219. }


  220. static char *
  221. ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  222. {
  223.     ngx_http_upstream_srv_conf_t  *uscf;

  224.     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);

  225.     if (uscf->peer.init_upstream) {
  226.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  227.                            "load balancing method redefined");
  228.     }

  229.     uscf->peer.init_upstream = ngx_http_upstream_init_least_conn;

  230.     uscf->flags = NGX_HTTP_UPSTREAM_CREATE
  231.                   |NGX_HTTP_UPSTREAM_MODIFY
  232.                   |NGX_HTTP_UPSTREAM_WEIGHT
  233.                   |NGX_HTTP_UPSTREAM_MAX_CONNS
  234.                   |NGX_HTTP_UPSTREAM_MAX_FAILS
  235.                   |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
  236.                   |NGX_HTTP_UPSTREAM_DOWN
  237.                   |NGX_HTTP_UPSTREAM_BACKUP;

  238.     return NGX_CONF_OK;
  239. }