Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

0001 
0002 /*
0003  * Copyright (C) Nginx, Inc.
0004  */
0005 
0006 
0007 #include <ngx_config.h>
0008 #include <ngx_core.h>
0009 #include <ngx_stream.h>
0010 
0011 
0012 typedef struct {
0013     ngx_stream_upstream_rr_peer_t          *peer;
0014     ngx_uint_t                              range;
0015 } ngx_stream_upstream_random_range_t;
0016 
0017 
0018 typedef struct {
0019     ngx_uint_t                              two;
0020     ngx_stream_upstream_random_range_t     *ranges;
0021 } ngx_stream_upstream_random_srv_conf_t;
0022 
0023 
0024 typedef struct {
0025     /* the round robin data must be first */
0026     ngx_stream_upstream_rr_peer_data_t      rrp;
0027 
0028     ngx_stream_upstream_random_srv_conf_t  *conf;
0029     u_char                                  tries;
0030 } ngx_stream_upstream_random_peer_data_t;
0031 
0032 
0033 static ngx_int_t ngx_stream_upstream_init_random(ngx_conf_t *cf,
0034     ngx_stream_upstream_srv_conf_t *us);
0035 static ngx_int_t ngx_stream_upstream_update_random(ngx_pool_t *pool,
0036     ngx_stream_upstream_srv_conf_t *us);
0037 
0038 static ngx_int_t ngx_stream_upstream_init_random_peer(ngx_stream_session_t *s,
0039     ngx_stream_upstream_srv_conf_t *us);
0040 static ngx_int_t ngx_stream_upstream_get_random_peer(ngx_peer_connection_t *pc,
0041     void *data);
0042 static ngx_int_t ngx_stream_upstream_get_random2_peer(ngx_peer_connection_t *pc,
0043     void *data);
0044 static ngx_uint_t ngx_stream_upstream_peek_random_peer(
0045     ngx_stream_upstream_rr_peers_t *peers,
0046     ngx_stream_upstream_random_peer_data_t *rp);
0047 static void *ngx_stream_upstream_random_create_conf(ngx_conf_t *cf);
0048 static char *ngx_stream_upstream_random(ngx_conf_t *cf, ngx_command_t *cmd,
0049     void *conf);
0050 
0051 
0052 static ngx_command_t  ngx_stream_upstream_random_commands[] = {
0053 
0054     { ngx_string("random"),
0055       NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE12,
0056       ngx_stream_upstream_random,
0057       NGX_STREAM_SRV_CONF_OFFSET,
0058       0,
0059       NULL },
0060 
0061       ngx_null_command
0062 };
0063 
0064 
0065 static ngx_stream_module_t  ngx_stream_upstream_random_module_ctx = {
0066     NULL,                                    /* preconfiguration */
0067     NULL,                                    /* postconfiguration */
0068 
0069     NULL,                                    /* create main configuration */
0070     NULL,                                    /* init main configuration */
0071 
0072     ngx_stream_upstream_random_create_conf,  /* create server configuration */
0073     NULL                                     /* merge server configuration */
0074 };
0075 
0076 
0077 ngx_module_t  ngx_stream_upstream_random_module = {
0078     NGX_MODULE_V1,
0079     &ngx_stream_upstream_random_module_ctx,  /* module context */
0080     ngx_stream_upstream_random_commands,     /* module directives */
0081     NGX_STREAM_MODULE,                       /* module type */
0082     NULL,                                    /* init master */
0083     NULL,                                    /* init module */
0084     NULL,                                    /* init process */
0085     NULL,                                    /* init thread */
0086     NULL,                                    /* exit thread */
0087     NULL,                                    /* exit process */
0088     NULL,                                    /* exit master */
0089     NGX_MODULE_V1_PADDING
0090 };
0091 
0092 
0093 static ngx_int_t
0094 ngx_stream_upstream_init_random(ngx_conf_t *cf,
0095     ngx_stream_upstream_srv_conf_t *us)
0096 {
0097     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0, "init random");
0098 
0099     if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) {
0100         return NGX_ERROR;
0101     }
0102 
0103     us->peer.init = ngx_stream_upstream_init_random_peer;
0104 
0105 #if (NGX_STREAM_UPSTREAM_ZONE)
0106     if (us->shm_zone) {
0107         return NGX_OK;
0108     }
0109 #endif
0110 
0111     return ngx_stream_upstream_update_random(cf->pool, us);
0112 }
0113 
0114 
0115 static ngx_int_t
0116 ngx_stream_upstream_update_random(ngx_pool_t *pool,
0117     ngx_stream_upstream_srv_conf_t *us)
0118 {
0119     size_t                                  size;
0120     ngx_uint_t                              i, total_weight;
0121     ngx_stream_upstream_rr_peer_t          *peer;
0122     ngx_stream_upstream_rr_peers_t         *peers;
0123     ngx_stream_upstream_random_range_t     *ranges;
0124     ngx_stream_upstream_random_srv_conf_t  *rcf;
0125 
0126     rcf = ngx_stream_conf_upstream_srv_conf(us,
0127                                             ngx_stream_upstream_random_module);
0128     peers = us->peer.data;
0129 
0130     size = peers->number * sizeof(ngx_stream_upstream_random_range_t);
0131 
0132     ranges = pool ? ngx_palloc(pool, size) : ngx_alloc(size, ngx_cycle->log);
0133     if (ranges == NULL) {
0134         return NGX_ERROR;
0135     }
0136 
0137     total_weight = 0;
0138 
0139     for (peer = peers->peer, i = 0; peer; peer = peer->next, i++) {
0140         ranges[i].peer = peer;
0141         ranges[i].range = total_weight;
0142         total_weight += peer->weight;
0143     }
0144 
0145     rcf->ranges = ranges;
0146 
0147     return NGX_OK;
0148 }
0149 
0150 
0151 static ngx_int_t
0152 ngx_stream_upstream_init_random_peer(ngx_stream_session_t *s,
0153     ngx_stream_upstream_srv_conf_t *us)
0154 {
0155     ngx_stream_upstream_random_srv_conf_t   *rcf;
0156     ngx_stream_upstream_random_peer_data_t  *rp;
0157 
0158     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0159                    "init random peer");
0160 
0161     rcf = ngx_stream_conf_upstream_srv_conf(us,
0162                                             ngx_stream_upstream_random_module);
0163 
0164     rp = ngx_palloc(s->connection->pool,
0165                     sizeof(ngx_stream_upstream_random_peer_data_t));
0166     if (rp == NULL) {
0167         return NGX_ERROR;
0168     }
0169 
0170     s->upstream->peer.data = &rp->rrp;
0171 
0172     if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) {
0173         return NGX_ERROR;
0174     }
0175 
0176     if (rcf->two) {
0177         s->upstream->peer.get = ngx_stream_upstream_get_random2_peer;
0178 
0179     } else {
0180         s->upstream->peer.get = ngx_stream_upstream_get_random_peer;
0181     }
0182 
0183     rp->conf = rcf;
0184     rp->tries = 0;
0185 
0186     ngx_stream_upstream_rr_peers_rlock(rp->rrp.peers);
0187 
0188 #if (NGX_STREAM_UPSTREAM_ZONE)
0189     if (rp->rrp.peers->shpool && rcf->ranges == NULL) {
0190         if (ngx_stream_upstream_update_random(NULL, us) != NGX_OK) {
0191             ngx_stream_upstream_rr_peers_unlock(rp->rrp.peers);
0192             return NGX_ERROR;
0193         }
0194     }
0195 #endif
0196 
0197     ngx_stream_upstream_rr_peers_unlock(rp->rrp.peers);
0198 
0199     return NGX_OK;
0200 }
0201 
0202 
0203 static ngx_int_t
0204 ngx_stream_upstream_get_random_peer(ngx_peer_connection_t *pc, void *data)
0205 {
0206     ngx_stream_upstream_random_peer_data_t  *rp = data;
0207 
0208     time_t                               now;
0209     uintptr_t                            m;
0210     ngx_uint_t                           i, n;
0211     ngx_stream_upstream_rr_peer_t       *peer;
0212     ngx_stream_upstream_rr_peers_t      *peers;
0213     ngx_stream_upstream_rr_peer_data_t  *rrp;
0214 
0215     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0216                    "get random peer, try: %ui", pc->tries);
0217 
0218     rrp = &rp->rrp;
0219     peers = rrp->peers;
0220 
0221     ngx_stream_upstream_rr_peers_rlock(peers);
0222 
0223     if (rp->tries > 20 || peers->single) {
0224         ngx_stream_upstream_rr_peers_unlock(peers);
0225         return ngx_stream_upstream_get_round_robin_peer(pc, rrp);
0226     }
0227 
0228     pc->cached = 0;
0229     pc->connection = NULL;
0230 
0231     now = ngx_time();
0232 
0233     for ( ;; ) {
0234 
0235         i = ngx_stream_upstream_peek_random_peer(peers, rp);
0236 
0237         peer = rp->conf->ranges[i].peer;
0238 
0239         n = i / (8 * sizeof(uintptr_t));
0240         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0241 
0242         if (rrp->tried[n] & m) {
0243             goto next;
0244         }
0245 
0246         ngx_stream_upstream_rr_peer_lock(peers, peer);
0247 
0248         if (peer->down) {
0249             ngx_stream_upstream_rr_peer_unlock(peers, peer);
0250             goto next;
0251         }
0252 
0253         if (peer->max_fails
0254             && peer->fails >= peer->max_fails
0255             && now - peer->checked <= peer->fail_timeout)
0256         {
0257             ngx_stream_upstream_rr_peer_unlock(peers, peer);
0258             goto next;
0259         }
0260 
0261         if (peer->max_conns && peer->conns >= peer->max_conns) {
0262             ngx_stream_upstream_rr_peer_unlock(peers, peer);
0263             goto next;
0264         }
0265 
0266         break;
0267 
0268     next:
0269 
0270         if (++rp->tries > 20) {
0271             ngx_stream_upstream_rr_peers_unlock(peers);
0272             return ngx_stream_upstream_get_round_robin_peer(pc, rrp);
0273         }
0274     }
0275 
0276     rrp->current = peer;
0277 
0278     if (now - peer->checked > peer->fail_timeout) {
0279         peer->checked = now;
0280     }
0281 
0282     pc->sockaddr = peer->sockaddr;
0283     pc->socklen = peer->socklen;
0284     pc->name = &peer->name;
0285 
0286     peer->conns++;
0287 
0288     ngx_stream_upstream_rr_peer_unlock(peers, peer);
0289     ngx_stream_upstream_rr_peers_unlock(peers);
0290 
0291     rrp->tried[n] |= m;
0292 
0293     return NGX_OK;
0294 }
0295 
0296 
0297 static ngx_int_t
0298 ngx_stream_upstream_get_random2_peer(ngx_peer_connection_t *pc, void *data)
0299 {
0300     ngx_stream_upstream_random_peer_data_t  *rp = data;
0301 
0302     time_t                               now;
0303     uintptr_t                            m;
0304     ngx_uint_t                           i, n, p;
0305     ngx_stream_upstream_rr_peer_t       *peer, *prev;
0306     ngx_stream_upstream_rr_peers_t      *peers;
0307     ngx_stream_upstream_rr_peer_data_t  *rrp;
0308 
0309     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0310                    "get random2 peer, try: %ui", pc->tries);
0311 
0312     rrp = &rp->rrp;
0313     peers = rrp->peers;
0314 
0315     ngx_stream_upstream_rr_peers_wlock(peers);
0316 
0317     if (rp->tries > 20 || peers->single) {
0318         ngx_stream_upstream_rr_peers_unlock(peers);
0319         return ngx_stream_upstream_get_round_robin_peer(pc, rrp);
0320     }
0321 
0322     pc->cached = 0;
0323     pc->connection = NULL;
0324 
0325     now = ngx_time();
0326 
0327     prev = NULL;
0328 
0329 #if (NGX_SUPPRESS_WARN)
0330     p = 0;
0331 #endif
0332 
0333     for ( ;; ) {
0334 
0335         i = ngx_stream_upstream_peek_random_peer(peers, rp);
0336 
0337         peer = rp->conf->ranges[i].peer;
0338 
0339         if (peer == prev) {
0340             goto next;
0341         }
0342 
0343         n = i / (8 * sizeof(uintptr_t));
0344         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0345 
0346         if (rrp->tried[n] & m) {
0347             goto next;
0348         }
0349 
0350         if (peer->down) {
0351             goto next;
0352         }
0353 
0354         if (peer->max_fails
0355             && peer->fails >= peer->max_fails
0356             && now - peer->checked <= peer->fail_timeout)
0357         {
0358             goto next;
0359         }
0360 
0361         if (peer->max_conns && peer->conns >= peer->max_conns) {
0362             goto next;
0363         }
0364 
0365         if (prev) {
0366             if (peer->conns * prev->weight > prev->conns * peer->weight) {
0367                 peer = prev;
0368                 n = p / (8 * sizeof(uintptr_t));
0369                 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
0370             }
0371 
0372             break;
0373         }
0374 
0375         prev = peer;
0376         p = i;
0377 
0378     next:
0379 
0380         if (++rp->tries > 20) {
0381             ngx_stream_upstream_rr_peers_unlock(peers);
0382             return ngx_stream_upstream_get_round_robin_peer(pc, rrp);
0383         }
0384     }
0385 
0386     rrp->current = peer;
0387 
0388     if (now - peer->checked > peer->fail_timeout) {
0389         peer->checked = now;
0390     }
0391 
0392     pc->sockaddr = peer->sockaddr;
0393     pc->socklen = peer->socklen;
0394     pc->name = &peer->name;
0395 
0396     peer->conns++;
0397 
0398     ngx_stream_upstream_rr_peers_unlock(peers);
0399 
0400     rrp->tried[n] |= m;
0401 
0402     return NGX_OK;
0403 }
0404 
0405 
0406 static ngx_uint_t
0407 ngx_stream_upstream_peek_random_peer(ngx_stream_upstream_rr_peers_t *peers,
0408     ngx_stream_upstream_random_peer_data_t *rp)
0409 {
0410     ngx_uint_t  i, j, k, x;
0411 
0412     x = ngx_random() % peers->total_weight;
0413 
0414     i = 0;
0415     j = peers->number;
0416 
0417     while (j - i > 1) {
0418         k = (i + j) / 2;
0419 
0420         if (x < rp->conf->ranges[k].range) {
0421             j = k;
0422 
0423         } else {
0424             i = k;
0425         }
0426     }
0427 
0428     return i;
0429 }
0430 
0431 
0432 static void *
0433 ngx_stream_upstream_random_create_conf(ngx_conf_t *cf)
0434 {
0435     ngx_stream_upstream_random_srv_conf_t  *conf;
0436 
0437     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_random_srv_conf_t));
0438     if (conf == NULL) {
0439         return NULL;
0440     }
0441 
0442     /*
0443      * set by ngx_pcalloc():
0444      *
0445      *     conf->two = 0;
0446      */
0447 
0448     return conf;
0449 }
0450 
0451 
0452 static char *
0453 ngx_stream_upstream_random(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0454 {
0455     ngx_stream_upstream_random_srv_conf_t  *rcf = conf;
0456 
0457     ngx_str_t                       *value;
0458     ngx_stream_upstream_srv_conf_t  *uscf;
0459 
0460     uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module);
0461 
0462     if (uscf->peer.init_upstream) {
0463         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
0464                            "load balancing method redefined");
0465     }
0466 
0467     uscf->peer.init_upstream = ngx_stream_upstream_init_random;
0468 
0469     uscf->flags = NGX_STREAM_UPSTREAM_CREATE
0470                   |NGX_STREAM_UPSTREAM_WEIGHT
0471                   |NGX_STREAM_UPSTREAM_MAX_CONNS
0472                   |NGX_STREAM_UPSTREAM_MAX_FAILS
0473                   |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT
0474                   |NGX_STREAM_UPSTREAM_DOWN;
0475 
0476     if (cf->args->nelts == 1) {
0477         return NGX_CONF_OK;
0478     }
0479 
0480     value = cf->args->elts;
0481 
0482     if (ngx_strcmp(value[1].data, "two") == 0) {
0483         rcf->two = 1;
0484 
0485     } else {
0486         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0487                            "invalid parameter \"%V\"", &value[1]);
0488         return NGX_CONF_ERROR;
0489     }
0490 
0491     if (cf->args->nelts == 2) {
0492         return NGX_CONF_OK;
0493     }
0494 
0495     if (ngx_strcmp(value[2].data, "least_conn") != 0) {
0496         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0497                            "invalid parameter \"%V\"", &value[2]);
0498         return NGX_CONF_ERROR;
0499     }
0500 
0501     return NGX_CONF_OK;
0502 }