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)