Mercurial > hg > nginx
comparison src/http/modules/ngx_http_upstream_least_conn_module.c @ 6099:6ff0ebd6fbf4
Upstream: track the number of active connections to upstreams.
This also simplifies the implementation of the least_conn module.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Fri, 10 Apr 2015 13:16:23 +0300 |
parents | 575175ebf4b4 |
children | c44459611d91 |
comparison
equal
deleted
inserted
replaced
6098:ac34eff7e147 | 6099:6ff0ebd6fbf4 |
---|---|
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_http.h> | 10 #include <ngx_http.h> |
11 | 11 |
12 | 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, | 13 static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, |
30 ngx_http_upstream_srv_conf_t *us); | 14 ngx_http_upstream_srv_conf_t *us); |
31 static ngx_int_t ngx_http_upstream_get_least_conn_peer( | 15 static ngx_int_t ngx_http_upstream_get_least_conn_peer( |
32 ngx_peer_connection_t *pc, void *data); | 16 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, | 17 static char *ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, |
37 void *conf); | 18 void *conf); |
38 | 19 |
39 | 20 |
40 static ngx_command_t ngx_http_upstream_least_conn_commands[] = { | 21 static ngx_command_t ngx_http_upstream_least_conn_commands[] = { |
55 NULL, /* postconfiguration */ | 36 NULL, /* postconfiguration */ |
56 | 37 |
57 NULL, /* create main configuration */ | 38 NULL, /* create main configuration */ |
58 NULL, /* init main configuration */ | 39 NULL, /* init main configuration */ |
59 | 40 |
60 ngx_http_upstream_least_conn_create_conf, /* create server configuration */ | 41 NULL, /* create server configuration */ |
61 NULL, /* merge server configuration */ | 42 NULL, /* merge server configuration */ |
62 | 43 |
63 NULL, /* create location configuration */ | 44 NULL, /* create location configuration */ |
64 NULL /* merge location configuration */ | 45 NULL /* merge location configuration */ |
65 }; | 46 }; |
83 | 64 |
84 static ngx_int_t | 65 static ngx_int_t |
85 ngx_http_upstream_init_least_conn(ngx_conf_t *cf, | 66 ngx_http_upstream_init_least_conn(ngx_conf_t *cf, |
86 ngx_http_upstream_srv_conf_t *us) | 67 ngx_http_upstream_srv_conf_t *us) |
87 { | 68 { |
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, | 69 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, |
93 "init least conn"); | 70 "init least conn"); |
94 | 71 |
95 if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { | 72 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; | 73 return NGX_ERROR; |
113 } | 74 } |
114 | 75 |
115 us->peer.init = ngx_http_upstream_init_least_conn_peer; | 76 us->peer.init = ngx_http_upstream_init_least_conn_peer; |
116 | 77 |
120 | 81 |
121 static ngx_int_t | 82 static ngx_int_t |
122 ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, | 83 ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, |
123 ngx_http_upstream_srv_conf_t *us) | 84 ngx_http_upstream_srv_conf_t *us) |
124 { | 85 { |
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, | 86 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
129 "init least conn peer"); | 87 "init least conn peer"); |
130 | 88 |
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) { | 89 if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { |
144 return NGX_ERROR; | 90 return NGX_ERROR; |
145 } | 91 } |
146 | 92 |
147 r->upstream->peer.get = ngx_http_upstream_get_least_conn_peer; | 93 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 | 94 |
153 return NGX_OK; | 95 return NGX_OK; |
154 } | 96 } |
155 | 97 |
156 | 98 |
157 static ngx_int_t | 99 static ngx_int_t |
158 ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) | 100 ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) |
159 { | 101 { |
160 ngx_http_upstream_lc_peer_data_t *lcp = data; | 102 ngx_http_upstream_rr_peer_data_t *rrp = data; |
161 | 103 |
162 time_t now; | 104 time_t now; |
163 uintptr_t m; | 105 uintptr_t m; |
164 ngx_int_t rc, total; | 106 ngx_int_t rc, total; |
165 ngx_uint_t i, n, p, many; | 107 ngx_uint_t i, n, p, many; |
167 ngx_http_upstream_rr_peers_t *peers; | 109 ngx_http_upstream_rr_peers_t *peers; |
168 | 110 |
169 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, | 111 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, |
170 "get least conn peer, try: %ui", pc->tries); | 112 "get least conn peer, try: %ui", pc->tries); |
171 | 113 |
172 if (lcp->rrp.peers->single) { | 114 if (rrp->peers->single) { |
173 return lcp->get_rr_peer(pc, &lcp->rrp); | 115 return ngx_http_upstream_get_round_robin_peer(pc, rrp); |
174 } | 116 } |
175 | 117 |
176 pc->cached = 0; | 118 pc->cached = 0; |
177 pc->connection = NULL; | 119 pc->connection = NULL; |
178 | 120 |
179 now = ngx_time(); | 121 now = ngx_time(); |
180 | 122 |
181 peers = lcp->rrp.peers; | 123 peers = rrp->peers; |
182 | 124 |
183 best = NULL; | 125 best = NULL; |
184 total = 0; | 126 total = 0; |
185 | 127 |
186 #if (NGX_SUPPRESS_WARN) | 128 #if (NGX_SUPPRESS_WARN) |
191 for (i = 0; i < peers->number; i++) { | 133 for (i = 0; i < peers->number; i++) { |
192 | 134 |
193 n = i / (8 * sizeof(uintptr_t)); | 135 n = i / (8 * sizeof(uintptr_t)); |
194 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | 136 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); |
195 | 137 |
196 if (lcp->rrp.tried[n] & m) { | 138 if (rrp->tried[n] & m) { |
197 continue; | 139 continue; |
198 } | 140 } |
199 | 141 |
200 peer = &peers->peer[i]; | 142 peer = &peers->peer[i]; |
201 | 143 |
215 * multiple peers with the same number of connections, select | 157 * multiple peers with the same number of connections, select |
216 * based on round-robin | 158 * based on round-robin |
217 */ | 159 */ |
218 | 160 |
219 if (best == NULL | 161 if (best == NULL |
220 || lcp->conns[i] * best->weight < lcp->conns[p] * peer->weight) | 162 || peer->conns * best->weight < best->conns * peer->weight) |
221 { | 163 { |
222 best = peer; | 164 best = peer; |
223 many = 0; | 165 many = 0; |
224 p = i; | 166 p = i; |
225 | 167 |
226 } else if (lcp->conns[i] * best->weight | 168 } else if (peer->conns * best->weight == best->conns * peer->weight) { |
227 == lcp->conns[p] * peer->weight) | |
228 { | |
229 many = 1; | 169 many = 1; |
230 } | 170 } |
231 } | 171 } |
232 | 172 |
233 if (best == NULL) { | 173 if (best == NULL) { |
244 for (i = p; i < peers->number; i++) { | 184 for (i = p; i < peers->number; i++) { |
245 | 185 |
246 n = i / (8 * sizeof(uintptr_t)); | 186 n = i / (8 * sizeof(uintptr_t)); |
247 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | 187 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); |
248 | 188 |
249 if (lcp->rrp.tried[n] & m) { | 189 if (rrp->tried[n] & m) { |
250 continue; | 190 continue; |
251 } | 191 } |
252 | 192 |
253 peer = &peers->peer[i]; | 193 peer = &peers->peer[i]; |
254 | 194 |
255 if (peer->down) { | 195 if (peer->down) { |
256 continue; | 196 continue; |
257 } | 197 } |
258 | 198 |
259 if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) { | 199 if (peer->conns * best->weight != best->conns * peer->weight) { |
260 continue; | 200 continue; |
261 } | 201 } |
262 | 202 |
263 if (peer->max_fails | 203 if (peer->max_fails |
264 && peer->fails >= peer->max_fails | 204 && peer->fails >= peer->max_fails |
289 | 229 |
290 pc->sockaddr = best->sockaddr; | 230 pc->sockaddr = best->sockaddr; |
291 pc->socklen = best->socklen; | 231 pc->socklen = best->socklen; |
292 pc->name = &best->name; | 232 pc->name = &best->name; |
293 | 233 |
294 lcp->rrp.current = p; | 234 best->conns++; |
235 | |
236 rrp->current = p; | |
295 | 237 |
296 n = p / (8 * sizeof(uintptr_t)); | 238 n = p / (8 * sizeof(uintptr_t)); |
297 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); | 239 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); |
298 | 240 |
299 lcp->rrp.tried[n] |= m; | 241 rrp->tried[n] |= m; |
300 lcp->conns[p]++; | |
301 | 242 |
302 return NGX_OK; | 243 return NGX_OK; |
303 | 244 |
304 failed: | 245 failed: |
305 | 246 |
306 if (peers->next) { | 247 if (peers->next) { |
307 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, | 248 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, |
308 "get least conn peer, backup servers"); | 249 "get least conn peer, backup servers"); |
309 | 250 |
310 lcp->conns += peers->number; | 251 rrp->peers = peers->next; |
311 | 252 |
312 lcp->rrp.peers = peers->next; | 253 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) |
313 | |
314 n = (lcp->rrp.peers->number + (8 * sizeof(uintptr_t) - 1)) | |
315 / (8 * sizeof(uintptr_t)); | 254 / (8 * sizeof(uintptr_t)); |
316 | 255 |
317 for (i = 0; i < n; i++) { | 256 for (i = 0; i < n; i++) { |
318 lcp->rrp.tried[i] = 0; | 257 rrp->tried[i] = 0; |
319 } | 258 } |
320 | 259 |
321 rc = ngx_http_upstream_get_least_conn_peer(pc, lcp); | 260 rc = ngx_http_upstream_get_least_conn_peer(pc, rrp); |
322 | 261 |
323 if (rc != NGX_BUSY) { | 262 if (rc != NGX_BUSY) { |
324 return rc; | 263 return rc; |
325 } | 264 } |
326 } | 265 } |
332 } | 271 } |
333 | 272 |
334 pc->name = peers->name; | 273 pc->name = peers->name; |
335 | 274 |
336 return NGX_BUSY; | 275 return NGX_BUSY; |
337 } | |
338 | |
339 | |
340 static void | |
341 ngx_http_upstream_free_least_conn_peer(ngx_peer_connection_t *pc, | |
342 void *data, ngx_uint_t state) | |
343 { | |
344 ngx_http_upstream_lc_peer_data_t *lcp = data; | |
345 | |
346 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
347 "free least conn peer %ui %ui", pc->tries, state); | |
348 | |
349 if (lcp->rrp.peers->single) { | |
350 lcp->free_rr_peer(pc, &lcp->rrp, state); | |
351 return; | |
352 } | |
353 | |
354 lcp->conns[lcp->rrp.current]--; | |
355 | |
356 lcp->free_rr_peer(pc, &lcp->rrp, state); | |
357 } | |
358 | |
359 | |
360 static void * | |
361 ngx_http_upstream_least_conn_create_conf(ngx_conf_t *cf) | |
362 { | |
363 ngx_http_upstream_least_conn_conf_t *conf; | |
364 | |
365 conf = ngx_pcalloc(cf->pool, | |
366 sizeof(ngx_http_upstream_least_conn_conf_t)); | |
367 if (conf == NULL) { | |
368 return NULL; | |
369 } | |
370 | |
371 /* | |
372 * set by ngx_pcalloc(): | |
373 * | |
374 * conf->conns = NULL; | |
375 */ | |
376 | |
377 return conf; | |
378 } | 276 } |
379 | 277 |
380 | 278 |
381 static char * | 279 static char * |
382 ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 280 ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |