Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_upstream_least_conn_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Maxim Dounin
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 typedef struct {
16 
17 
18 typedef struct {
19  /* the round robin data must be first */
21 
23 
27 
28 
29 static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
31 static ngx_int_t ngx_http_upstream_get_least_conn_peer(
32  ngx_peer_connection_t *pc, void *data);
33 static void ngx_http_upstream_free_least_conn_peer(ngx_peer_connection_t *pc,
34  void *data, ngx_uint_t state);
35 static void *ngx_http_upstream_least_conn_create_conf(ngx_conf_t *cf);
36 static char *ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd,
37  void *conf);
38 
39 
40 static ngx_command_t ngx_http_upstream_least_conn_commands[] = {
41 
42  { ngx_string("least_conn"),
44  ngx_http_upstream_least_conn,
45  0,
46  0,
47  NULL },
48 
50 };
51 
52 
53 static ngx_http_module_t ngx_http_upstream_least_conn_module_ctx = {
54  NULL, /* preconfiguration */
55  NULL, /* postconfiguration */
56 
57  NULL, /* create main configuration */
58  NULL, /* init main configuration */
59 
60  ngx_http_upstream_least_conn_create_conf, /* create server configuration */
61  NULL, /* merge server configuration */
62 
63  NULL, /* create location configuration */
64  NULL /* merge location configuration */
65 };
66 
67 
70  &ngx_http_upstream_least_conn_module_ctx, /* module context */
71  ngx_http_upstream_least_conn_commands, /* module directives */
72  NGX_HTTP_MODULE, /* module type */
73  NULL, /* init master */
74  NULL, /* init module */
75  NULL, /* init process */
76  NULL, /* init thread */
77  NULL, /* exit thread */
78  NULL, /* exit process */
79  NULL, /* exit master */
81 };
82 
83 
84 static ngx_int_t
85 ngx_http_upstream_init_least_conn(ngx_conf_t *cf,
87 {
88  ngx_uint_t n;
91 
93  "init least conn");
94 
96  return NGX_ERROR;
97  }
98 
99  peers = us->peer.data;
100 
101  n = peers->number;
102 
103  if (peers->next) {
104  n += peers->next->number;
105  }
106 
108  ngx_http_upstream_least_conn_module);
109 
110  lcf->conns = ngx_pcalloc(cf->pool, sizeof(ngx_uint_t) * n);
111  if (lcf->conns == NULL) {
112  return NGX_ERROR;
113  }
114 
115  us->peer.init = ngx_http_upstream_init_least_conn_peer;
116 
117  return NGX_OK;
118 }
119 
120 
121 static ngx_int_t
122 ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
124 {
127 
129  "init least conn peer");
130 
132  ngx_http_upstream_least_conn_module);
133 
135  if (lcp == NULL) {
136  return NGX_ERROR;
137  }
138 
139  lcp->conns = lcf->conns;
140 
141  r->upstream->peer.data = &lcp->rrp;
142 
144  return NGX_ERROR;
145  }
146 
147  r->upstream->peer.get = ngx_http_upstream_get_least_conn_peer;
148  r->upstream->peer.free = ngx_http_upstream_free_least_conn_peer;
149 
152 
153  return NGX_OK;
154 }
155 
156 
157 static ngx_int_t
158 ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
159 {
161 
162  time_t now;
163  uintptr_t m;
164  ngx_int_t rc, total;
165  ngx_uint_t i, n, p, many;
166  ngx_http_upstream_rr_peer_t *peer, *best;
168 
170  "get least conn peer, try: %ui", pc->tries);
171 
172  if (lcp->rrp.peers->single) {
173  return lcp->get_rr_peer(pc, &lcp->rrp);
174  }
175 
176  pc->cached = 0;
177  pc->connection = NULL;
178 
179  now = ngx_time();
180 
181  peers = lcp->rrp.peers;
182 
183  best = NULL;
184  total = 0;
185 
186 #if (NGX_SUPPRESS_WARN)
187  many = 0;
188  p = 0;
189 #endif
190 
191  for (i = 0; i < peers->number; i++) {
192 
193  n = i / (8 * sizeof(uintptr_t));
194  m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
195 
196  if (lcp->rrp.tried[n] & m) {
197  continue;
198  }
199 
200  peer = &peers->peer[i];
201 
202  if (peer->down) {
203  continue;
204  }
205 
206  if (peer->max_fails
207  && peer->fails >= peer->max_fails
208  && now - peer->checked <= peer->fail_timeout)
209  {
210  continue;
211  }
212 
213  /*
214  * select peer with least number of connections; if there are
215  * multiple peers with the same number of connections, select
216  * based on round-robin
217  */
218 
219  if (best == NULL
220  || lcp->conns[i] * best->weight < lcp->conns[p] * peer->weight)
221  {
222  best = peer;
223  many = 0;
224  p = i;
225 
226  } else if (lcp->conns[i] * best->weight
227  == lcp->conns[p] * peer->weight)
228  {
229  many = 1;
230  }
231  }
232 
233  if (best == NULL) {
235  "get least conn peer, no peer found");
236 
237  goto failed;
238  }
239 
240  if (many) {
242  "get least conn peer, many");
243 
244  for (i = p; i < peers->number; i++) {
245 
246  n = i / (8 * sizeof(uintptr_t));
247  m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
248 
249  if (lcp->rrp.tried[n] & m) {
250  continue;
251  }
252 
253  peer = &peers->peer[i];
254 
255  if (peer->down) {
256  continue;
257  }
258 
259  if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) {
260  continue;
261  }
262 
263  if (peer->max_fails
264  && peer->fails >= peer->max_fails
265  && now - peer->checked <= peer->fail_timeout)
266  {
267  continue;
268  }
269 
270  peer->current_weight += peer->effective_weight;
271  total += peer->effective_weight;
272 
273  if (peer->effective_weight < peer->weight) {
274  peer->effective_weight++;
275  }
276 
277  if (peer->current_weight > best->current_weight) {
278  best = peer;
279  p = i;
280  }
281  }
282  }
283 
284  best->current_weight -= total;
285 
286  if (now - best->checked > best->fail_timeout) {
287  best->checked = now;
288  }
289 
290  pc->sockaddr = best->sockaddr;
291  pc->socklen = best->socklen;
292  pc->name = &best->name;
293 
294  lcp->rrp.current = p;
295 
296  n = p / (8 * sizeof(uintptr_t));
297  m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
298 
299  lcp->rrp.tried[n] |= m;
300  lcp->conns[p]++;
301 
302  if (pc->tries == 1 && peers->next) {
303  pc->tries += peers->next->number;
304  }
305 
306  return NGX_OK;
307 
308 failed:
309 
310  if (peers->next) {
312  "get least conn peer, backup servers");
313 
314  lcp->conns += peers->number;
315 
316  lcp->rrp.peers = peers->next;
317  pc->tries = lcp->rrp.peers->number;
318 
319  n = (lcp->rrp.peers->number + (8 * sizeof(uintptr_t) - 1))
320  / (8 * sizeof(uintptr_t));
321 
322  for (i = 0; i < n; i++) {
323  lcp->rrp.tried[i] = 0;
324  }
325 
326  rc = ngx_http_upstream_get_least_conn_peer(pc, lcp);
327 
328  if (rc != NGX_BUSY) {
329  return rc;
330  }
331  }
332 
333  /* all peers failed, mark them as live for quick recovery */
334 
335  for (i = 0; i < peers->number; i++) {
336  peers->peer[i].fails = 0;
337  }
338 
339  pc->name = peers->name;
340 
341  return NGX_BUSY;
342 }
343 
344 
345 static void
346 ngx_http_upstream_free_least_conn_peer(ngx_peer_connection_t *pc,
347  void *data, ngx_uint_t state)
348 {
350 
352  "free least conn peer %ui %ui", pc->tries, state);
353 
354  if (lcp->rrp.peers->single) {
355  lcp->free_rr_peer(pc, &lcp->rrp, state);
356  return;
357  }
358 
359  lcp->conns[lcp->rrp.current]--;
360 
361  lcp->free_rr_peer(pc, &lcp->rrp, state);
362 }
363 
364 
365 static void *
366 ngx_http_upstream_least_conn_create_conf(ngx_conf_t *cf)
367 {
369 
370  conf = ngx_pcalloc(cf->pool,
372  if (conf == NULL) {
373  return NULL;
374  }
375 
376  /*
377  * set by ngx_pcalloc():
378  *
379  * conf->conns = NULL;
380  */
381 
382  return conf;
383 }
384 
385 
386 static char *
387 ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
388 {
390 
392 
393  if (uscf->peer.init_upstream) {
395  "load balancing method redefined");
396  }
397 
398  uscf->peer.init_upstream = ngx_http_upstream_init_least_conn;
399 
406 
407  return NGX_CONF_OK;
408 }