Annotation of embedaddon/nginx/src/http/ngx_http_upstream_round_robin.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Igor Sysoev
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: static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
14: ngx_http_upstream_rr_peer_data_t *rrp);
15:
16: #if (NGX_HTTP_SSL)
17:
18: static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
19: void *data);
20: static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
21: void *data);
22:
23: #endif
24:
25:
26: ngx_int_t
27: ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
28: ngx_http_upstream_srv_conf_t *us)
29: {
30: ngx_url_t u;
31: ngx_uint_t i, j, n, w;
32: ngx_http_upstream_server_t *server;
33: ngx_http_upstream_rr_peers_t *peers, *backup;
34:
35: us->peer.init = ngx_http_upstream_init_round_robin_peer;
36:
37: if (us->servers) {
38: server = us->servers->elts;
39:
40: n = 0;
41: w = 0;
42:
43: for (i = 0; i < us->servers->nelts; i++) {
44: if (server[i].backup) {
45: continue;
46: }
47:
48: n += server[i].naddrs;
49: w += server[i].naddrs * server[i].weight;
50: }
51:
52: if (n == 0) {
53: ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
54: "no servers in upstream \"%V\" in %s:%ui",
55: &us->host, us->file_name, us->line);
56: return NGX_ERROR;
57: }
58:
59: peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
60: + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
61: if (peers == NULL) {
62: return NGX_ERROR;
63: }
64:
65: peers->single = (n == 1);
66: peers->number = n;
67: peers->weighted = (w != n);
68: peers->total_weight = w;
69: peers->name = &us->host;
70:
71: n = 0;
72:
73: for (i = 0; i < us->servers->nelts; i++) {
74: for (j = 0; j < server[i].naddrs; j++) {
75: if (server[i].backup) {
76: continue;
77: }
78:
79: peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
80: peers->peer[n].socklen = server[i].addrs[j].socklen;
81: peers->peer[n].name = server[i].addrs[j].name;
82: peers->peer[n].max_fails = server[i].max_fails;
83: peers->peer[n].fail_timeout = server[i].fail_timeout;
84: peers->peer[n].down = server[i].down;
85: peers->peer[n].weight = server[i].weight;
86: peers->peer[n].effective_weight = server[i].weight;
87: peers->peer[n].current_weight = 0;
88: n++;
89: }
90: }
91:
92: us->peer.data = peers;
93:
94: /* backup servers */
95:
96: n = 0;
97: w = 0;
98:
99: for (i = 0; i < us->servers->nelts; i++) {
100: if (!server[i].backup) {
101: continue;
102: }
103:
104: n += server[i].naddrs;
105: w += server[i].naddrs * server[i].weight;
106: }
107:
108: if (n == 0) {
109: return NGX_OK;
110: }
111:
112: backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
113: + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
114: if (backup == NULL) {
115: return NGX_ERROR;
116: }
117:
118: peers->single = 0;
119: backup->single = 0;
120: backup->number = n;
121: backup->weighted = (w != n);
122: backup->total_weight = w;
123: backup->name = &us->host;
124:
125: n = 0;
126:
127: for (i = 0; i < us->servers->nelts; i++) {
128: for (j = 0; j < server[i].naddrs; j++) {
129: if (!server[i].backup) {
130: continue;
131: }
132:
133: backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
134: backup->peer[n].socklen = server[i].addrs[j].socklen;
135: backup->peer[n].name = server[i].addrs[j].name;
136: backup->peer[n].weight = server[i].weight;
137: backup->peer[n].effective_weight = server[i].weight;
138: backup->peer[n].current_weight = 0;
139: backup->peer[n].max_fails = server[i].max_fails;
140: backup->peer[n].fail_timeout = server[i].fail_timeout;
141: backup->peer[n].down = server[i].down;
142: n++;
143: }
144: }
145:
146: peers->next = backup;
147:
148: return NGX_OK;
149: }
150:
151:
152: /* an upstream implicitly defined by proxy_pass, etc. */
153:
154: if (us->port == 0) {
155: ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
156: "no port in upstream \"%V\" in %s:%ui",
157: &us->host, us->file_name, us->line);
158: return NGX_ERROR;
159: }
160:
161: ngx_memzero(&u, sizeof(ngx_url_t));
162:
163: u.host = us->host;
164: u.port = us->port;
165:
166: if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
167: if (u.err) {
168: ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
169: "%s in upstream \"%V\" in %s:%ui",
170: u.err, &us->host, us->file_name, us->line);
171: }
172:
173: return NGX_ERROR;
174: }
175:
176: n = u.naddrs;
177:
178: peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
179: + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
180: if (peers == NULL) {
181: return NGX_ERROR;
182: }
183:
184: peers->single = (n == 1);
185: peers->number = n;
186: peers->weighted = 0;
187: peers->total_weight = n;
188: peers->name = &us->host;
189:
190: for (i = 0; i < u.naddrs; i++) {
191: peers->peer[i].sockaddr = u.addrs[i].sockaddr;
192: peers->peer[i].socklen = u.addrs[i].socklen;
193: peers->peer[i].name = u.addrs[i].name;
194: peers->peer[i].weight = 1;
195: peers->peer[i].effective_weight = 1;
196: peers->peer[i].current_weight = 0;
197: peers->peer[i].max_fails = 1;
198: peers->peer[i].fail_timeout = 10;
199: }
200:
201: us->peer.data = peers;
202:
203: /* implicitly defined upstream has no backup servers */
204:
205: return NGX_OK;
206: }
207:
208:
209: ngx_int_t
210: ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
211: ngx_http_upstream_srv_conf_t *us)
212: {
213: ngx_uint_t n;
214: ngx_http_upstream_rr_peer_data_t *rrp;
215:
216: rrp = r->upstream->peer.data;
217:
218: if (rrp == NULL) {
219: rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
220: if (rrp == NULL) {
221: return NGX_ERROR;
222: }
223:
224: r->upstream->peer.data = rrp;
225: }
226:
227: rrp->peers = us->peer.data;
228: rrp->current = 0;
229:
230: n = rrp->peers->number;
231:
232: if (rrp->peers->next && rrp->peers->next->number > n) {
233: n = rrp->peers->next->number;
234: }
235:
236: if (n <= 8 * sizeof(uintptr_t)) {
237: rrp->tried = &rrp->data;
238: rrp->data = 0;
239:
240: } else {
241: n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
242:
243: rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
244: if (rrp->tried == NULL) {
245: return NGX_ERROR;
246: }
247: }
248:
249: r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
250: r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
251: r->upstream->peer.tries = rrp->peers->number;
252: #if (NGX_HTTP_SSL)
253: r->upstream->peer.set_session =
254: ngx_http_upstream_set_round_robin_peer_session;
255: r->upstream->peer.save_session =
256: ngx_http_upstream_save_round_robin_peer_session;
257: #endif
258:
259: return NGX_OK;
260: }
261:
262:
263: ngx_int_t
264: ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
265: ngx_http_upstream_resolved_t *ur)
266: {
267: u_char *p;
268: size_t len;
269: ngx_uint_t i, n;
270: struct sockaddr_in *sin;
271: ngx_http_upstream_rr_peers_t *peers;
272: ngx_http_upstream_rr_peer_data_t *rrp;
273:
274: rrp = r->upstream->peer.data;
275:
276: if (rrp == NULL) {
277: rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
278: if (rrp == NULL) {
279: return NGX_ERROR;
280: }
281:
282: r->upstream->peer.data = rrp;
283: }
284:
285: peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t)
286: + sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1));
287: if (peers == NULL) {
288: return NGX_ERROR;
289: }
290:
291: peers->single = (ur->naddrs == 1);
292: peers->number = ur->naddrs;
293: peers->name = &ur->host;
294:
295: if (ur->sockaddr) {
296: peers->peer[0].sockaddr = ur->sockaddr;
297: peers->peer[0].socklen = ur->socklen;
298: peers->peer[0].name = ur->host;
299: peers->peer[0].weight = 1;
300: peers->peer[0].effective_weight = 1;
301: peers->peer[0].current_weight = 0;
302: peers->peer[0].max_fails = 1;
303: peers->peer[0].fail_timeout = 10;
304:
305: } else {
306:
307: for (i = 0; i < ur->naddrs; i++) {
308:
309: len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
310:
311: p = ngx_pnalloc(r->pool, len);
312: if (p == NULL) {
313: return NGX_ERROR;
314: }
315:
316: len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
317: len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
318:
319: sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
320: if (sin == NULL) {
321: return NGX_ERROR;
322: }
323:
324: sin->sin_family = AF_INET;
325: sin->sin_port = htons(ur->port);
326: sin->sin_addr.s_addr = ur->addrs[i];
327:
328: peers->peer[i].sockaddr = (struct sockaddr *) sin;
329: peers->peer[i].socklen = sizeof(struct sockaddr_in);
330: peers->peer[i].name.len = len;
331: peers->peer[i].name.data = p;
332: peers->peer[i].weight = 1;
333: peers->peer[i].effective_weight = 1;
334: peers->peer[i].current_weight = 0;
335: peers->peer[i].max_fails = 1;
336: peers->peer[i].fail_timeout = 10;
337: }
338: }
339:
340: rrp->peers = peers;
341: rrp->current = 0;
342:
343: if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
344: rrp->tried = &rrp->data;
345: rrp->data = 0;
346:
347: } else {
348: n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
349: / (8 * sizeof(uintptr_t));
350:
351: rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
352: if (rrp->tried == NULL) {
353: return NGX_ERROR;
354: }
355: }
356:
357: r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
358: r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
359: r->upstream->peer.tries = rrp->peers->number;
360: #if (NGX_HTTP_SSL)
361: r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
362: r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
363: #endif
364:
365: return NGX_OK;
366: }
367:
368:
369: ngx_int_t
370: ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
371: {
372: ngx_http_upstream_rr_peer_data_t *rrp = data;
373:
374: ngx_int_t rc;
375: ngx_uint_t i, n;
376: ngx_http_upstream_rr_peer_t *peer;
377: ngx_http_upstream_rr_peers_t *peers;
378:
379: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
380: "get rr peer, try: %ui", pc->tries);
381:
382: /* ngx_lock_mutex(rrp->peers->mutex); */
383:
384: pc->cached = 0;
385: pc->connection = NULL;
386:
387: if (rrp->peers->single) {
388: peer = &rrp->peers->peer[0];
389:
390: if (peer->down) {
391: goto failed;
392: }
393:
394: } else {
395:
396: /* there are several peers */
397:
398: peer = ngx_http_upstream_get_peer(rrp);
399:
400: if (peer == NULL) {
401: goto failed;
402: }
403:
404: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
405: "get rr peer, current: %ui %i",
406: rrp->current, peer->current_weight);
407: }
408:
409: pc->sockaddr = peer->sockaddr;
410: pc->socklen = peer->socklen;
411: pc->name = &peer->name;
412:
413: /* ngx_unlock_mutex(rrp->peers->mutex); */
414:
415: if (pc->tries == 1 && rrp->peers->next) {
416: pc->tries += rrp->peers->next->number;
417: }
418:
419: return NGX_OK;
420:
421: failed:
422:
423: peers = rrp->peers;
424:
425: if (peers->next) {
426:
427: /* ngx_unlock_mutex(peers->mutex); */
428:
429: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
430:
431: rrp->peers = peers->next;
432: pc->tries = rrp->peers->number;
433:
434: n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
435: / (8 * sizeof(uintptr_t));
436:
437: for (i = 0; i < n; i++) {
438: rrp->tried[i] = 0;
439: }
440:
441: rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
442:
443: if (rc != NGX_BUSY) {
444: return rc;
445: }
446:
447: /* ngx_lock_mutex(peers->mutex); */
448: }
449:
450: /* all peers failed, mark them as live for quick recovery */
451:
452: for (i = 0; i < peers->number; i++) {
453: peers->peer[i].fails = 0;
454: }
455:
456: /* ngx_unlock_mutex(peers->mutex); */
457:
458: pc->name = peers->name;
459:
460: return NGX_BUSY;
461: }
462:
463:
464: static ngx_http_upstream_rr_peer_t *
465: ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
466: {
467: time_t now;
468: uintptr_t m;
469: ngx_int_t total;
470: ngx_uint_t i, n;
471: ngx_http_upstream_rr_peer_t *peer, *best;
472:
473: now = ngx_time();
474:
475: best = NULL;
476: total = 0;
477:
478: for (i = 0; i < rrp->peers->number; i++) {
479:
480: n = i / (8 * sizeof(uintptr_t));
481: m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
482:
483: if (rrp->tried[n] & m) {
484: continue;
485: }
486:
487: peer = &rrp->peers->peer[i];
488:
489: if (peer->down) {
490: continue;
491: }
492:
493: if (peer->max_fails
494: && peer->fails >= peer->max_fails
495: && now - peer->checked <= peer->fail_timeout)
496: {
497: continue;
498: }
499:
500: peer->current_weight += peer->effective_weight;
501: total += peer->effective_weight;
502:
503: if (peer->effective_weight < peer->weight) {
504: peer->effective_weight++;
505: }
506:
507: if (best == NULL || peer->current_weight > best->current_weight) {
508: best = peer;
509: }
510: }
511:
512: if (best == NULL) {
513: return NULL;
514: }
515:
516: i = best - &rrp->peers->peer[0];
517:
518: rrp->current = i;
519:
520: n = i / (8 * sizeof(uintptr_t));
521: m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
522:
523: rrp->tried[n] |= m;
524:
525: best->current_weight -= total;
526:
527: if (now - best->checked > best->fail_timeout) {
528: best->checked = now;
529: }
530:
531: return best;
532: }
533:
534:
535: void
536: ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
537: ngx_uint_t state)
538: {
539: ngx_http_upstream_rr_peer_data_t *rrp = data;
540:
541: time_t now;
542: ngx_http_upstream_rr_peer_t *peer;
543:
544: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
545: "free rr peer %ui %ui", pc->tries, state);
546:
547: /* TODO: NGX_PEER_KEEPALIVE */
548:
549: if (rrp->peers->single) {
550: pc->tries = 0;
551: return;
552: }
553:
554: peer = &rrp->peers->peer[rrp->current];
555:
556: if (state & NGX_PEER_FAILED) {
557: now = ngx_time();
558:
559: /* ngx_lock_mutex(rrp->peers->mutex); */
560:
561: peer->fails++;
562: peer->accessed = now;
563: peer->checked = now;
564:
565: if (peer->max_fails) {
566: peer->effective_weight -= peer->weight / peer->max_fails;
567: }
568:
569: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
570: "free rr peer failed: %ui %i",
571: rrp->current, peer->effective_weight);
572:
573: if (peer->effective_weight < 0) {
574: peer->effective_weight = 0;
575: }
576:
577: /* ngx_unlock_mutex(rrp->peers->mutex); */
578:
579: } else {
580:
581: /* mark peer live if check passed */
582:
583: if (peer->accessed < peer->checked) {
584: peer->fails = 0;
585: }
586: }
587:
588: if (pc->tries) {
589: pc->tries--;
590: }
591:
592: /* ngx_unlock_mutex(rrp->peers->mutex); */
593: }
594:
595:
596: #if (NGX_HTTP_SSL)
597:
598: ngx_int_t
599: ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
600: void *data)
601: {
602: ngx_http_upstream_rr_peer_data_t *rrp = data;
603:
604: ngx_int_t rc;
605: ngx_ssl_session_t *ssl_session;
606: ngx_http_upstream_rr_peer_t *peer;
607:
608: peer = &rrp->peers->peer[rrp->current];
609:
610: /* TODO: threads only mutex */
611: /* ngx_lock_mutex(rrp->peers->mutex); */
612:
613: ssl_session = peer->ssl_session;
614:
615: rc = ngx_ssl_set_session(pc->connection, ssl_session);
616:
617: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
618: "set session: %p:%d",
619: ssl_session, ssl_session ? ssl_session->references : 0);
620:
621: /* ngx_unlock_mutex(rrp->peers->mutex); */
622:
623: return rc;
624: }
625:
626:
627: void
628: ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
629: void *data)
630: {
631: ngx_http_upstream_rr_peer_data_t *rrp = data;
632:
633: ngx_ssl_session_t *old_ssl_session, *ssl_session;
634: ngx_http_upstream_rr_peer_t *peer;
635:
636: ssl_session = ngx_ssl_get_session(pc->connection);
637:
638: if (ssl_session == NULL) {
639: return;
640: }
641:
642: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
643: "save session: %p:%d", ssl_session, ssl_session->references);
644:
645: peer = &rrp->peers->peer[rrp->current];
646:
647: /* TODO: threads only mutex */
648: /* ngx_lock_mutex(rrp->peers->mutex); */
649:
650: old_ssl_session = peer->ssl_session;
651: peer->ssl_session = ssl_session;
652:
653: /* ngx_unlock_mutex(rrp->peers->mutex); */
654:
655: if (old_ssl_session) {
656:
657: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
658: "old session: %p:%d",
659: old_ssl_session, old_ssl_session->references);
660:
661: /* TODO: may block */
662:
663: ngx_ssl_free_session(old_ssl_session);
664: }
665: }
666:
667:
668: static ngx_int_t
669: ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
670: {
671: return NGX_OK;
672: }
673:
674:
675: static void
676: ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
677: {
678: return;
679: }
680:
681: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>