3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
13 static ngx_http_upstream_rr_peer_t
*ngx_http_upstream_get_peer(
14 ngx_http_upstream_rr_peer_data_t
*rrp
);
18 static ngx_int_t
ngx_http_upstream_empty_set_session(ngx_peer_connection_t
*pc
,
20 static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t
*pc
,
27 ngx_http_upstream_init_round_robin(ngx_conf_t
*cf
,
28 ngx_http_upstream_srv_conf_t
*us
)
31 ngx_uint_t i
, j
, n
, w
;
32 ngx_http_upstream_server_t
*server
;
33 ngx_http_upstream_rr_peers_t
*peers
, *backup
;
35 us
->peer
.init
= ngx_http_upstream_init_round_robin_peer
;
38 server
= us
->servers
->elts
;
43 for (i
= 0; i
< us
->servers
->nelts
; i
++) {
44 if (server
[i
].backup
) {
48 n
+= server
[i
].naddrs
;
49 w
+= server
[i
].naddrs
* server
[i
].weight
;
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
);
59 peers
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_upstream_rr_peers_t
)
60 + sizeof(ngx_http_upstream_rr_peer_t
) * (n
- 1));
65 peers
->single
= (n
== 1);
67 peers
->weighted
= (w
!= n
);
68 peers
->total_weight
= w
;
69 peers
->name
= &us
->host
;
73 for (i
= 0; i
< us
->servers
->nelts
; i
++) {
74 for (j
= 0; j
< server
[i
].naddrs
; j
++) {
75 if (server
[i
].backup
) {
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;
92 us
->peer
.data
= peers
;
99 for (i
= 0; i
< us
->servers
->nelts
; i
++) {
100 if (!server
[i
].backup
) {
104 n
+= server
[i
].naddrs
;
105 w
+= server
[i
].naddrs
* server
[i
].weight
;
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
) {
121 backup
->weighted
= (w
!= n
);
122 backup
->total_weight
= w
;
123 backup
->name
= &us
->host
;
127 for (i
= 0; i
< us
->servers
->nelts
; i
++) {
128 for (j
= 0; j
< server
[i
].naddrs
; j
++) {
129 if (!server
[i
].backup
) {
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
;
146 peers
->next
= backup
;
152 /* an upstream implicitly defined by proxy_pass, etc. */
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
);
161 ngx_memzero(&u
, sizeof(ngx_url_t
));
166 if (ngx_inet_resolve_host(cf
->pool
, &u
) != NGX_OK
) {
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
);
178 peers
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_upstream_rr_peers_t
)
179 + sizeof(ngx_http_upstream_rr_peer_t
) * (n
- 1));
184 peers
->single
= (n
== 1);
187 peers
->total_weight
= n
;
188 peers
->name
= &us
->host
;
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;
201 us
->peer
.data
= peers
;
203 /* implicitly defined upstream has no backup servers */
210 ngx_http_upstream_init_round_robin_peer(ngx_http_request_t
*r
,
211 ngx_http_upstream_srv_conf_t
*us
)
214 ngx_http_upstream_rr_peer_data_t
*rrp
;
216 rrp
= r
->upstream
->peer
.data
;
219 rrp
= ngx_palloc(r
->pool
, sizeof(ngx_http_upstream_rr_peer_data_t
));
224 r
->upstream
->peer
.data
= rrp
;
227 rrp
->peers
= us
->peer
.data
;
230 n
= rrp
->peers
->number
;
232 if (rrp
->peers
->next
&& rrp
->peers
->next
->number
> n
) {
233 n
= rrp
->peers
->next
->number
;
236 if (n
<= 8 * sizeof(uintptr_t)) {
237 rrp
->tried
= &rrp
->data
;
241 n
= (n
+ (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
243 rrp
->tried
= ngx_pcalloc(r
->pool
, n
* sizeof(uintptr_t));
244 if (rrp
->tried
== NULL
) {
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
;
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
;
264 ngx_http_upstream_create_round_robin_peer(ngx_http_request_t
*r
,
265 ngx_http_upstream_resolved_t
*ur
)
270 struct sockaddr_in
*sin
;
271 ngx_http_upstream_rr_peers_t
*peers
;
272 ngx_http_upstream_rr_peer_data_t
*rrp
;
274 rrp
= r
->upstream
->peer
.data
;
277 rrp
= ngx_palloc(r
->pool
, sizeof(ngx_http_upstream_rr_peer_data_t
));
282 r
->upstream
->peer
.data
= rrp
;
285 peers
= ngx_pcalloc(r
->pool
, sizeof(ngx_http_upstream_rr_peers_t
)
286 + sizeof(ngx_http_upstream_rr_peer_t
) * (ur
->naddrs
- 1));
291 peers
->single
= (ur
->naddrs
== 1);
292 peers
->number
= ur
->naddrs
;
293 peers
->name
= &ur
->host
;
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;
307 for (i
= 0; i
< ur
->naddrs
; i
++) {
309 len
= NGX_INET_ADDRSTRLEN
+ sizeof(":65536") - 1;
311 p
= ngx_pnalloc(r
->pool
, len
);
316 len
= ngx_inet_ntop(AF_INET
, &ur
->addrs
[i
], p
, NGX_INET_ADDRSTRLEN
);
317 len
= ngx_sprintf(&p
[len
], ":%d", ur
->port
) - p
;
319 sin
= ngx_pcalloc(r
->pool
, sizeof(struct sockaddr_in
));
324 sin
->sin_family
= AF_INET
;
325 sin
->sin_port
= htons(ur
->port
);
326 sin
->sin_addr
.s_addr
= ur
->addrs
[i
];
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;
343 if (rrp
->peers
->number
<= 8 * sizeof(uintptr_t)) {
344 rrp
->tried
= &rrp
->data
;
348 n
= (rrp
->peers
->number
+ (8 * sizeof(uintptr_t) - 1))
349 / (8 * sizeof(uintptr_t));
351 rrp
->tried
= ngx_pcalloc(r
->pool
, n
* sizeof(uintptr_t));
352 if (rrp
->tried
== NULL
) {
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
;
361 r
->upstream
->peer
.set_session
= ngx_http_upstream_empty_set_session
;
362 r
->upstream
->peer
.save_session
= ngx_http_upstream_empty_save_session
;
370 ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t
*pc
, void *data
)
372 ngx_http_upstream_rr_peer_data_t
*rrp
= data
;
376 ngx_http_upstream_rr_peer_t
*peer
;
377 ngx_http_upstream_rr_peers_t
*peers
;
379 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
380 "get rr peer, try: %ui", pc
->tries
);
382 /* ngx_lock_mutex(rrp->peers->mutex); */
385 pc
->connection
= NULL
;
387 if (rrp
->peers
->single
) {
388 peer
= &rrp
->peers
->peer
[0];
396 /* there are several peers */
398 peer
= ngx_http_upstream_get_peer(rrp
);
404 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
405 "get rr peer, current: %ui %i",
406 rrp
->current
, peer
->current_weight
);
409 pc
->sockaddr
= peer
->sockaddr
;
410 pc
->socklen
= peer
->socklen
;
411 pc
->name
= &peer
->name
;
413 /* ngx_unlock_mutex(rrp->peers->mutex); */
415 if (pc
->tries
== 1 && rrp
->peers
->next
) {
416 pc
->tries
+= rrp
->peers
->next
->number
;
427 /* ngx_unlock_mutex(peers->mutex); */
429 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0, "backup servers");
431 rrp
->peers
= peers
->next
;
432 pc
->tries
= rrp
->peers
->number
;
434 n
= (rrp
->peers
->number
+ (8 * sizeof(uintptr_t) - 1))
435 / (8 * sizeof(uintptr_t));
437 for (i
= 0; i
< n
; i
++) {
441 rc
= ngx_http_upstream_get_round_robin_peer(pc
, rrp
);
443 if (rc
!= NGX_BUSY
) {
447 /* ngx_lock_mutex(peers->mutex); */
450 /* all peers failed, mark them as live for quick recovery */
452 for (i
= 0; i
< peers
->number
; i
++) {
453 peers
->peer
[i
].fails
= 0;
456 /* ngx_unlock_mutex(peers->mutex); */
458 pc
->name
= peers
->name
;
464 static ngx_http_upstream_rr_peer_t
*
465 ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t
*rrp
)
471 ngx_http_upstream_rr_peer_t
*peer
, *best
;
478 for (i
= 0; i
< rrp
->peers
->number
; i
++) {
480 n
= i
/ (8 * sizeof(uintptr_t));
481 m
= (uintptr_t) 1 << i
% (8 * sizeof(uintptr_t));
483 if (rrp
->tried
[n
] & m
) {
487 peer
= &rrp
->peers
->peer
[i
];
494 && peer
->fails
>= peer
->max_fails
495 && now
- peer
->checked
<= peer
->fail_timeout
)
500 peer
->current_weight
+= peer
->effective_weight
;
501 total
+= peer
->effective_weight
;
503 if (peer
->effective_weight
< peer
->weight
) {
504 peer
->effective_weight
++;
507 if (best
== NULL
|| peer
->current_weight
> best
->current_weight
) {
516 i
= best
- &rrp
->peers
->peer
[0];
520 n
= i
/ (8 * sizeof(uintptr_t));
521 m
= (uintptr_t) 1 << i
% (8 * sizeof(uintptr_t));
525 best
->current_weight
-= total
;
533 ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t
*pc
, void *data
,
536 ngx_http_upstream_rr_peer_data_t
*rrp
= data
;
539 ngx_http_upstream_rr_peer_t
*peer
;
541 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
542 "free rr peer %ui %ui", pc
->tries
, state
);
544 /* TODO: NGX_PEER_KEEPALIVE */
546 if (rrp
->peers
->single
) {
551 peer
= &rrp
->peers
->peer
[rrp
->current
];
553 if (state
& NGX_PEER_FAILED
) {
556 /* ngx_lock_mutex(rrp->peers->mutex); */
559 peer
->accessed
= now
;
562 if (peer
->max_fails
) {
563 peer
->effective_weight
-= peer
->weight
/ peer
->max_fails
;
566 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
567 "free rr peer failed: %ui %i",
568 rrp
->current
, peer
->effective_weight
);
570 if (peer
->effective_weight
< 0) {
571 peer
->effective_weight
= 0;
574 /* ngx_unlock_mutex(rrp->peers->mutex); */
578 /* mark peer live if check passed */
580 if (peer
->accessed
< peer
->checked
) {
589 /* ngx_unlock_mutex(rrp->peers->mutex); */
596 ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t
*pc
,
599 ngx_http_upstream_rr_peer_data_t
*rrp
= data
;
602 ngx_ssl_session_t
*ssl_session
;
603 ngx_http_upstream_rr_peer_t
*peer
;
605 peer
= &rrp
->peers
->peer
[rrp
->current
];
607 /* TODO: threads only mutex */
608 /* ngx_lock_mutex(rrp->peers->mutex); */
610 ssl_session
= peer
->ssl_session
;
612 rc
= ngx_ssl_set_session(pc
->connection
, ssl_session
);
614 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
615 "set session: %p:%d",
616 ssl_session
, ssl_session
? ssl_session
->references
: 0);
618 /* ngx_unlock_mutex(rrp->peers->mutex); */
625 ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t
*pc
,
628 ngx_http_upstream_rr_peer_data_t
*rrp
= data
;
630 ngx_ssl_session_t
*old_ssl_session
, *ssl_session
;
631 ngx_http_upstream_rr_peer_t
*peer
;
633 ssl_session
= ngx_ssl_get_session(pc
->connection
);
635 if (ssl_session
== NULL
) {
639 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
640 "save session: %p:%d", ssl_session
, ssl_session
->references
);
642 peer
= &rrp
->peers
->peer
[rrp
->current
];
644 /* TODO: threads only mutex */
645 /* ngx_lock_mutex(rrp->peers->mutex); */
647 old_ssl_session
= peer
->ssl_session
;
648 peer
->ssl_session
= ssl_session
;
650 /* ngx_unlock_mutex(rrp->peers->mutex); */
652 if (old_ssl_session
) {
654 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
655 "old session: %p:%d",
656 old_ssl_session
, old_ssl_session
->references
);
658 /* TODO: may block */
660 ngx_ssl_free_session(old_ssl_session
);
666 ngx_http_upstream_empty_set_session(ngx_peer_connection_t
*pc
, void *data
)
673 ngx_http_upstream_empty_save_session(ngx_peer_connection_t
*pc
, void *data
)