src/stream/ngx_stream_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_stream.h>


  8. static ngx_int_t ngx_stream_upstream_init_least_conn_peer(
  9.     ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us);
  10. static ngx_int_t ngx_stream_upstream_get_least_conn_peer(
  11.     ngx_peer_connection_t *pc, void *data);
  12. static char *ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd,
  13.     void *conf);


  14. static ngx_command_t  ngx_stream_upstream_least_conn_commands[] = {

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

  21.       ngx_null_command
  22. };


  23. static ngx_stream_module_t  ngx_stream_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. };


  31. ngx_module_t  ngx_stream_upstream_least_conn_module = {
  32.     NGX_MODULE_V1,
  33.     &ngx_stream_upstream_least_conn_module_ctx, /* module context */
  34.     ngx_stream_upstream_least_conn_commands, /* module directives */
  35.     NGX_STREAM_MODULE,                       /* module type */
  36.     NULL,                                    /* init master */
  37.     NULL,                                    /* init module */
  38.     NULL,                                    /* init process */
  39.     NULL,                                    /* init thread */
  40.     NULL,                                    /* exit thread */
  41.     NULL,                                    /* exit process */
  42.     NULL,                                    /* exit master */
  43.     NGX_MODULE_V1_PADDING
  44. };


  45. static ngx_int_t
  46. ngx_stream_upstream_init_least_conn(ngx_conf_t *cf,
  47.     ngx_stream_upstream_srv_conf_t *us)
  48. {
  49.     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0,
  50.                    "init least conn");

  51.     if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) {
  52.         return NGX_ERROR;
  53.     }

  54.     us->peer.init = ngx_stream_upstream_init_least_conn_peer;

  55.     return NGX_OK;
  56. }


  57. static ngx_int_t
  58. ngx_stream_upstream_init_least_conn_peer(ngx_stream_session_t *s,
  59.     ngx_stream_upstream_srv_conf_t *us)
  60. {
  61.     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
  62.                    "init least conn peer");

  63.     if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) {
  64.         return NGX_ERROR;
  65.     }

  66.     s->upstream->peer.get = ngx_stream_upstream_get_least_conn_peer;

  67.     return NGX_OK;
  68. }


  69. static ngx_int_t
  70. ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
  71. {
  72.     ngx_stream_upstream_rr_peer_data_t *rrp = data;

  73.     time_t                           now;
  74.     uintptr_t                        m;
  75.     ngx_int_t                        rc, total;
  76.     ngx_uint_t                       i, n, p, many;
  77.     ngx_stream_upstream_rr_peer_t   *peer, *best;
  78.     ngx_stream_upstream_rr_peers_t  *peers;

  79.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  80.                    "get least conn peer, try: %ui", pc->tries);

  81.     if (rrp->peers->single) {
  82.         return ngx_stream_upstream_get_round_robin_peer(pc, rrp);
  83.     }

  84.     pc->connection = NULL;

  85.     now = ngx_time();

  86.     peers = rrp->peers;

  87.     ngx_stream_upstream_rr_peers_wlock(peers);

  88. #if (NGX_STREAM_UPSTREAM_ZONE)
  89.     if (peers->config && rrp->config != *peers->config) {
  90.         goto busy;
  91.     }
  92. #endif

  93.     best = NULL;
  94.     total = 0;

  95. #if (NGX_SUPPRESS_WARN)
  96.     many = 0;
  97.     p = 0;
  98. #endif

  99.     for (peer = peers->peer, i = 0;
  100.          peer;
  101.          peer = peer->next, i++)
  102.     {
  103.         n = i / (8 * sizeof(uintptr_t));
  104.         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  105.         if (rrp->tried[n] & m) {
  106.             continue;
  107.         }

  108.         if (peer->down) {
  109.             continue;
  110.         }

  111.         if (peer->max_fails
  112.             && peer->fails >= peer->max_fails
  113.             && now - peer->checked <= peer->fail_timeout)
  114.         {
  115.             continue;
  116.         }

  117.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  118.             continue;
  119.         }

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

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

  131.         } else if (peer->conns * best->weight == best->conns * peer->weight) {
  132.             many = 1;
  133.         }
  134.     }

  135.     if (best == NULL) {
  136.         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  137.                        "get least conn peer, no peer found");

  138.         goto failed;
  139.     }

  140.     if (many) {
  141.         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  142.                        "get least conn peer, many");

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

  149.             if (rrp->tried[n] & m) {
  150.                 continue;
  151.             }

  152.             if (peer->down) {
  153.                 continue;
  154.             }

  155.             if (peer->conns * best->weight != best->conns * peer->weight) {
  156.                 continue;
  157.             }

  158.             if (peer->max_fails
  159.                 && peer->fails >= peer->max_fails
  160.                 && now - peer->checked <= peer->fail_timeout)
  161.             {
  162.                 continue;
  163.             }

  164.             if (peer->max_conns && peer->conns >= peer->max_conns) {
  165.                 continue;
  166.             }

  167.             peer->current_weight += peer->effective_weight;
  168.             total += peer->effective_weight;

  169.             if (peer->effective_weight < peer->weight) {
  170.                 peer->effective_weight++;
  171.             }

  172.             if (peer->current_weight > best->current_weight) {
  173.                 best = peer;
  174.                 p = i;
  175.             }
  176.         }
  177.     }

  178.     best->current_weight -= total;

  179.     if (now - best->checked > best->fail_timeout) {
  180.         best->checked = now;
  181.     }

  182.     pc->sockaddr = best->sockaddr;
  183.     pc->socklen = best->socklen;
  184.     pc->name = &best->name;

  185.     best->conns++;

  186.     rrp->current = best;
  187.     ngx_stream_upstream_rr_peer_ref(peers, best);

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

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

  191.     ngx_stream_upstream_rr_peers_unlock(peers);

  192.     return NGX_OK;

  193. failed:

  194.     if (peers->next) {
  195.         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  196.                        "get least conn peer, backup servers");

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

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

  200.         for (i = 0; i < n; i++) {
  201.             rrp->tried[i] = 0;
  202.         }

  203.         ngx_stream_upstream_rr_peers_unlock(peers);

  204.         rc = ngx_stream_upstream_get_least_conn_peer(pc, rrp);

  205.         if (rc != NGX_BUSY) {
  206.             return rc;
  207.         }

  208.         ngx_stream_upstream_rr_peers_wlock(peers);
  209.     }

  210. #if (NGX_STREAM_UPSTREAM_ZONE)
  211. busy:
  212. #endif

  213.     ngx_stream_upstream_rr_peers_unlock(peers);

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

  215.     return NGX_BUSY;
  216. }


  217. static char *
  218. ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  219. {
  220.     ngx_stream_upstream_srv_conf_t  *uscf;

  221.     uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module);

  222.     if (uscf->peer.init_upstream) {
  223.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  224.                            "load balancing method redefined");
  225.     }

  226.     uscf->peer.init_upstream = ngx_stream_upstream_init_least_conn;

  227.     uscf->flags = NGX_STREAM_UPSTREAM_CREATE
  228.                   |NGX_STREAM_UPSTREAM_MODIFY
  229.                   |NGX_STREAM_UPSTREAM_WEIGHT
  230.                   |NGX_STREAM_UPSTREAM_MAX_CONNS
  231.                   |NGX_STREAM_UPSTREAM_MAX_FAILS
  232.                   |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT
  233.                   |NGX_STREAM_UPSTREAM_DOWN
  234.                   |NGX_STREAM_UPSTREAM_BACKUP;

  235.     return NGX_CONF_OK;
  236. }