Annotation of embedaddon/nginx/src/http/modules/ngx_http_upstream_least_conn_module.c, revision 1.1.1.1
1.1 misho 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 {
14: ngx_uint_t *conns;
15: } ngx_http_upstream_least_conn_conf_t;
16:
17:
18: typedef struct {
19: /* the round robin data must be first */
20: ngx_http_upstream_rr_peer_data_t rrp;
21:
22: ngx_uint_t *conns;
23:
24: ngx_event_get_peer_pt get_rr_peer;
25: ngx_event_free_peer_pt free_rr_peer;
26: } ngx_http_upstream_lc_peer_data_t;
27:
28:
29: static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
30: ngx_http_upstream_srv_conf_t *us);
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"),
43: NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
44: ngx_http_upstream_least_conn,
45: 0,
46: 0,
47: NULL },
48:
49: ngx_null_command
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:
68: ngx_module_t ngx_http_upstream_least_conn_module = {
69: NGX_MODULE_V1,
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 */
80: NGX_MODULE_V1_PADDING
81: };
82:
83:
84: static ngx_int_t
85: ngx_http_upstream_init_least_conn(ngx_conf_t *cf,
86: ngx_http_upstream_srv_conf_t *us)
87: {
88: ngx_uint_t n;
89: ngx_http_upstream_rr_peers_t *peers;
90: ngx_http_upstream_least_conn_conf_t *lcf;
91:
92: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
93: "init least conn");
94:
95: if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
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:
107: lcf = ngx_http_conf_upstream_srv_conf(us,
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,
123: ngx_http_upstream_srv_conf_t *us)
124: {
125: ngx_http_upstream_lc_peer_data_t *lcp;
126: ngx_http_upstream_least_conn_conf_t *lcf;
127:
128: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
129: "init least conn peer");
130:
131: lcf = ngx_http_conf_upstream_srv_conf(us,
132: ngx_http_upstream_least_conn_module);
133:
134: lcp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_lc_peer_data_t));
135: if (lcp == NULL) {
136: return NGX_ERROR;
137: }
138:
139: lcp->conns = lcf->conns;
140:
141: r->upstream->peer.data = &lcp->rrp;
142:
143: if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
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:
150: lcp->get_rr_peer = ngx_http_upstream_get_round_robin_peer;
151: lcp->free_rr_peer = ngx_http_upstream_free_round_robin_peer;
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: {
160: ngx_http_upstream_lc_peer_data_t *lcp = data;
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;
167: ngx_http_upstream_rr_peers_t *peers;
168:
169: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
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) {
234: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
235: "get least conn peer, no peer found");
236:
237: goto failed;
238: }
239:
240: if (many) {
241: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
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) {
311: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
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: {
349: ngx_http_upstream_lc_peer_data_t *lcp = data;
350:
351: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
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: {
368: ngx_http_upstream_least_conn_conf_t *conf;
369:
370: conf = ngx_pcalloc(cf->pool,
371: sizeof(ngx_http_upstream_least_conn_conf_t));
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: {
389: ngx_http_upstream_srv_conf_t *uscf;
390:
391: uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
392:
393: if (uscf->peer.init_upstream) {
394: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
395: "load balancing method redefined");
396: }
397:
398: uscf->peer.init_upstream = ngx_http_upstream_init_least_conn;
399:
400: uscf->flags = NGX_HTTP_UPSTREAM_CREATE
401: |NGX_HTTP_UPSTREAM_WEIGHT
402: |NGX_HTTP_UPSTREAM_MAX_FAILS
403: |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
404: |NGX_HTTP_UPSTREAM_DOWN
405: |NGX_HTTP_UPSTREAM_BACKUP;
406:
407: return NGX_CONF_OK;
408: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>