Mercurial > hg > nginx
comparison src/stream/ngx_stream_upstream_least_conn_module.c @ 6115:61d7ae76647d
Stream: port from NGINX+.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Mon, 20 Apr 2015 13:05:11 +0300 |
parents | |
children | 68c106e6fa0a |
comparison
equal
deleted
inserted
replaced
6114:4a640716f4e2 | 6115:61d7ae76647d |
---|---|
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_stream.h> | |
11 | |
12 | |
13 static ngx_int_t ngx_stream_upstream_init_least_conn_peer( | |
14 ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us); | |
15 static ngx_int_t ngx_stream_upstream_get_least_conn_peer( | |
16 ngx_peer_connection_t *pc, void *data); | |
17 static char *ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, | |
18 void *conf); | |
19 | |
20 | |
21 static ngx_command_t ngx_stream_upstream_least_conn_commands[] = { | |
22 | |
23 { ngx_string("least_conn"), | |
24 NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS, | |
25 ngx_stream_upstream_least_conn, | |
26 0, | |
27 0, | |
28 NULL }, | |
29 | |
30 ngx_null_command | |
31 }; | |
32 | |
33 | |
34 static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = { | |
35 NULL, /* create main configuration */ | |
36 NULL, /* init main configuration */ | |
37 | |
38 NULL, /* create server configuration */ | |
39 NULL, /* merge server configuration */ | |
40 }; | |
41 | |
42 | |
43 ngx_module_t ngx_stream_upstream_least_conn_module = { | |
44 NGX_MODULE_V1, | |
45 &ngx_stream_upstream_least_conn_module_ctx, /* module context */ | |
46 ngx_stream_upstream_least_conn_commands, /* module directives */ | |
47 NGX_STREAM_MODULE, /* module type */ | |
48 NULL, /* init master */ | |
49 NULL, /* init module */ | |
50 NULL, /* init process */ | |
51 NULL, /* init thread */ | |
52 NULL, /* exit thread */ | |
53 NULL, /* exit process */ | |
54 NULL, /* exit master */ | |
55 NGX_MODULE_V1_PADDING | |
56 }; | |
57 | |
58 | |
59 static ngx_int_t | |
60 ngx_stream_upstream_init_least_conn(ngx_conf_t *cf, | |
61 ngx_stream_upstream_srv_conf_t *us) | |
62 { | |
63 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0, | |
64 "init least conn"); | |
65 | |
66 if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) { | |
67 return NGX_ERROR; | |
68 } | |
69 | |
70 us->peer.init = ngx_stream_upstream_init_least_conn_peer; | |
71 | |
72 return NGX_OK; | |
73 } | |
74 | |
75 | |
76 static ngx_int_t | |
77 ngx_stream_upstream_init_least_conn_peer(ngx_stream_session_t *s, | |
78 ngx_stream_upstream_srv_conf_t *us) | |
79 { | |
80 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, | |
81 "init least conn peer"); | |
82 | |
83 if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) { | |
84 return NGX_ERROR; | |
85 } | |
86 | |
87 s->upstream->peer.get = ngx_stream_upstream_get_least_conn_peer; | |
88 | |
89 return NGX_OK; | |
90 } | |
91 | |
92 | |
93 static ngx_int_t | |
94 ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) | |
95 { | |
96 ngx_stream_upstream_rr_peer_data_t *rrp = data; | |
97 | |
98 time_t now; | |
99 uintptr_t m; | |
100 ngx_int_t rc, total; | |
101 ngx_uint_t i, n, p, many; | |
102 ngx_stream_upstream_rr_peer_t *peer, *best; | |
103 ngx_stream_upstream_rr_peers_t *peers; | |
104 | |
105 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
106 "get least conn peer, try: %ui", pc->tries); | |
107 | |
108 if (rrp->peers->single) { | |
109 return ngx_stream_upstream_get_round_robin_peer(pc, rrp); | |
110 } | |
111 | |
112 pc->connection = NULL; | |
113 | |
114 now = ngx_time(); | |
115 | |
116 peers = rrp->peers; | |
117 | |
118 ngx_stream_upstream_rr_peers_wlock(peers); | |
119 | |
120 best = NULL; | |
121 total = 0; | |
122 | |
123 #if (NGX_SUPPRESS_WARN) | |
124 many = 0; | |
125 p = 0; | |
126 #endif | |
127 | |
128 for (peer = peers->peer, i = 0; | |
129 peer; | |
130 peer = peer->next, i++) | |
131 { | |
132 | |
133 n = i / (8 * sizeof(uintptr_t)); | |
134 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | |
135 | |
136 if (rrp->tried[n] & m) { | |
137 continue; | |
138 } | |
139 | |
140 if (peer->down) { | |
141 continue; | |
142 } | |
143 | |
144 if (peer->max_fails | |
145 && peer->fails >= peer->max_fails | |
146 && now - peer->checked <= peer->fail_timeout) | |
147 { | |
148 continue; | |
149 } | |
150 | |
151 /* | |
152 * select peer with least number of connections; if there are | |
153 * multiple peers with the same number of connections, select | |
154 * based on round-robin | |
155 */ | |
156 | |
157 if (best == NULL | |
158 || peer->conns * best->weight < best->conns * peer->weight) | |
159 { | |
160 best = peer; | |
161 many = 0; | |
162 p = i; | |
163 | |
164 } else if (peer->conns * best->weight == best->conns * peer->weight) { | |
165 many = 1; | |
166 } | |
167 } | |
168 | |
169 if (best == NULL) { | |
170 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
171 "get least conn peer, no peer found"); | |
172 | |
173 goto failed; | |
174 } | |
175 | |
176 if (many) { | |
177 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
178 "get least conn peer, many"); | |
179 | |
180 for (peer = best, i = p; | |
181 peer; | |
182 peer = peer->next, i++) | |
183 { | |
184 n = i / (8 * sizeof(uintptr_t)); | |
185 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | |
186 | |
187 if (rrp->tried[n] & m) { | |
188 continue; | |
189 } | |
190 | |
191 if (peer->down) { | |
192 continue; | |
193 } | |
194 | |
195 if (peer->conns * best->weight != best->conns * peer->weight) { | |
196 continue; | |
197 } | |
198 | |
199 if (peer->max_fails | |
200 && peer->fails >= peer->max_fails | |
201 && now - peer->checked <= peer->fail_timeout) | |
202 { | |
203 continue; | |
204 } | |
205 | |
206 peer->current_weight += peer->effective_weight; | |
207 total += peer->effective_weight; | |
208 | |
209 if (peer->effective_weight < peer->weight) { | |
210 peer->effective_weight++; | |
211 } | |
212 | |
213 if (peer->current_weight > best->current_weight) { | |
214 best = peer; | |
215 p = i; | |
216 } | |
217 } | |
218 } | |
219 | |
220 best->current_weight -= total; | |
221 | |
222 if (now - best->checked > best->fail_timeout) { | |
223 best->checked = now; | |
224 } | |
225 | |
226 pc->sockaddr = best->sockaddr; | |
227 pc->socklen = best->socklen; | |
228 pc->name = &best->name; | |
229 | |
230 best->conns++; | |
231 | |
232 rrp->current = best; | |
233 | |
234 n = p / (8 * sizeof(uintptr_t)); | |
235 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); | |
236 | |
237 rrp->tried[n] |= m; | |
238 | |
239 ngx_stream_upstream_rr_peers_unlock(peers); | |
240 | |
241 return NGX_OK; | |
242 | |
243 failed: | |
244 | |
245 if (peers->next) { | |
246 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
247 "get least conn peer, backup servers"); | |
248 | |
249 rrp->peers = peers->next; | |
250 | |
251 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) | |
252 / (8 * sizeof(uintptr_t)); | |
253 | |
254 for (i = 0; i < n; i++) { | |
255 rrp->tried[i] = 0; | |
256 } | |
257 | |
258 ngx_stream_upstream_rr_peers_unlock(peers); | |
259 | |
260 rc = ngx_stream_upstream_get_least_conn_peer(pc, rrp); | |
261 | |
262 if (rc != NGX_BUSY) { | |
263 return rc; | |
264 } | |
265 | |
266 ngx_stream_upstream_rr_peers_wlock(peers); | |
267 } | |
268 | |
269 /* all peers failed, mark them as live for quick recovery */ | |
270 | |
271 for (peer = peers->peer; peer; peer = peer->next) { | |
272 peer->fails = 0; | |
273 } | |
274 | |
275 ngx_stream_upstream_rr_peers_unlock(peers); | |
276 | |
277 pc->name = peers->name; | |
278 | |
279 return NGX_BUSY; | |
280 } | |
281 | |
282 | |
283 static char * | |
284 ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
285 { | |
286 ngx_stream_upstream_srv_conf_t *uscf; | |
287 | |
288 uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module); | |
289 | |
290 if (uscf->peer.init_upstream) { | |
291 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
292 "load balancing method redefined"); | |
293 } | |
294 | |
295 uscf->peer.init_upstream = ngx_stream_upstream_init_least_conn; | |
296 | |
297 uscf->flags = NGX_STREAM_UPSTREAM_CREATE | |
298 |NGX_STREAM_UPSTREAM_WEIGHT | |
299 |NGX_STREAM_UPSTREAM_MAX_FAILS | |
300 |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT | |
301 |NGX_STREAM_UPSTREAM_DOWN | |
302 |NGX_STREAM_UPSTREAM_BACKUP; | |
303 | |
304 return NGX_CONF_OK; | |
305 } |