Mercurial > hg > ngx_http_upstream_keepalive
comparison ngx_http_upstream_keepalive_module.c @ 1:ca955a7f651b
Keepalive: common cache for all backends.
Known limitations:
Connections cached to the upstream pool as a whole, not to individual
backend servers, and therefore load distribution may be less than ideal
(especially under light load).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 22 Oct 2008 03:52:29 +0400 |
parents | 725ee11164f3 |
children | 8545bbda9e4b |
comparison
equal
deleted
inserted
replaced
0:725ee11164f3 | 1:ca955a7f651b |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright (C) Igor Sysoev | 3 * Copyright (C) Maxim Dounin |
4 */ | 4 */ |
5 | 5 |
6 | 6 |
7 #include <ngx_config.h> | 7 #include <ngx_config.h> |
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_http.h> | 9 #include <ngx_http.h> |
10 | 10 |
11 | 11 |
12 typedef struct { | 12 typedef struct { |
13 ngx_int_t cached; | 13 ngx_uint_t max_cached; |
14 ngx_uint_t last_cached; | |
15 | |
16 ngx_connection_t **cached; | |
14 | 17 |
15 ngx_http_upstream_init_pt original_init_upstream; | 18 ngx_http_upstream_init_pt original_init_upstream; |
16 ngx_http_upstream_init_peer_pt original_init_peer; | 19 ngx_http_upstream_init_peer_pt original_init_peer; |
17 | 20 |
18 } ngx_http_upstream_keepalive_srv_conf_t; | 21 } ngx_http_upstream_keepalive_srv_conf_t; |
19 | 22 |
20 typedef struct { | 23 typedef struct { |
24 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
25 | |
21 void *data; | 26 void *data; |
22 | 27 |
23 ngx_event_get_peer_pt original_get_peer; | 28 ngx_event_get_peer_pt original_get_peer; |
24 ngx_event_free_peer_pt original_free_peer; | 29 ngx_event_free_peer_pt original_free_peer; |
25 | 30 |
30 ngx_http_upstream_srv_conf_t *us); | 35 ngx_http_upstream_srv_conf_t *us); |
31 static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, | 36 static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, |
32 void *data); | 37 void *data); |
33 static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, | 38 static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, |
34 void *data, ngx_uint_t state); | 39 void *data, ngx_uint_t state); |
40 | |
41 static void ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev); | |
42 static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev); | |
43 | |
35 | 44 |
36 static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf); | 45 static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf); |
37 static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, | 46 static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, |
38 void *conf); | 47 void *conf); |
39 | 48 |
100 | 109 |
101 kcf->original_init_peer = us->peer.init; | 110 kcf->original_init_peer = us->peer.init; |
102 | 111 |
103 us->peer.init = ngx_http_upstream_init_keepalive_peer; | 112 us->peer.init = ngx_http_upstream_init_keepalive_peer; |
104 | 113 |
114 kcf->cached = ngx_pcalloc(cf->pool, | |
115 sizeof(ngx_connection_t *) * kcf->max_cached); | |
116 if (kcf->cached == NULL) { | |
117 return NGX_ERROR; | |
118 } | |
119 | |
120 | |
105 return NGX_OK; | 121 return NGX_OK; |
106 } | 122 } |
107 | 123 |
108 | 124 |
109 static ngx_int_t | 125 static ngx_int_t |
126 | 142 |
127 if (kcf->original_init_peer(r, us) != NGX_OK) { | 143 if (kcf->original_init_peer(r, us) != NGX_OK) { |
128 return NGX_ERROR; | 144 return NGX_ERROR; |
129 } | 145 } |
130 | 146 |
147 kp->conf = kcf; | |
131 kp->data = r->upstream->peer.data; | 148 kp->data = r->upstream->peer.data; |
132 kp->original_get_peer = r->upstream->peer.get; | 149 kp->original_get_peer = r->upstream->peer.get; |
133 kp->original_free_peer = r->upstream->peer.free; | 150 kp->original_free_peer = r->upstream->peer.free; |
134 | 151 |
135 r->upstream->peer.data = kp; | 152 r->upstream->peer.data = kp; |
143 static ngx_int_t | 160 static ngx_int_t |
144 ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) | 161 ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) |
145 { | 162 { |
146 ngx_http_upstream_keepalive_peer_data_t *kp = data; | 163 ngx_http_upstream_keepalive_peer_data_t *kp = data; |
147 | 164 |
165 ngx_connection_t *c; | |
166 | |
148 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, | 167 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, |
149 "get keepalive peer"); | 168 "get keepalive peer"); |
169 | |
170 /* XXX single pool of cached connections */ | |
171 | |
172 if (kp->conf->last_cached) { | |
173 | |
174 c = kp->conf->cached[--kp->conf->last_cached]; | |
175 | |
176 c->idle = 0; | |
177 c->log = pc->log; | |
178 c->read->log = pc->log; | |
179 c->write->log = pc->log; | |
180 | |
181 pc->connection = c; | |
182 pc->cached = 1; | |
183 | |
184 return NGX_DONE; | |
185 } | |
150 | 186 |
151 return kp->original_get_peer(pc, kp->data); | 187 return kp->original_get_peer(pc, kp->data); |
152 } | 188 } |
153 | 189 |
154 | 190 |
156 ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, | 192 ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, |
157 ngx_uint_t state) | 193 ngx_uint_t state) |
158 { | 194 { |
159 ngx_http_upstream_keepalive_peer_data_t *kp = data; | 195 ngx_http_upstream_keepalive_peer_data_t *kp = data; |
160 | 196 |
197 ngx_connection_t *c; | |
198 | |
161 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, | 199 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, |
162 "free keepalive peer"); | 200 "free keepalive peer"); |
163 | 201 |
202 if (!(state & NGX_PEER_FAILED) | |
203 && pc->connection != NULL | |
204 && kp->conf->last_cached < kp->conf->max_cached) | |
205 { | |
206 c = pc->connection; | |
207 | |
208 kp->conf->cached[kp->conf->last_cached++] = c; | |
209 pc->connection = NULL; | |
210 | |
211 if (c->read->timer_set) { | |
212 ngx_del_timer(c->read); | |
213 } | |
214 if (c->write->timer_set) { | |
215 ngx_del_timer(c->write); | |
216 } | |
217 | |
218 c->write->handler = ngx_http_upstream_keepalive_dummy_handler; | |
219 c->read->handler = ngx_http_upstream_keepalive_close_handler; | |
220 | |
221 c->data = kp->conf; | |
222 c->idle = 1; | |
223 c->log = ngx_cycle->log; | |
224 c->read->log = ngx_cycle->log; | |
225 c->write->log = ngx_cycle->log; | |
226 } | |
227 | |
164 return kp->original_free_peer(pc, kp->data, state); | 228 return kp->original_free_peer(pc, kp->data, state); |
229 } | |
230 | |
231 | |
232 static void | |
233 ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev) | |
234 { | |
235 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, | |
236 "keepalive dummy handler"); | |
237 } | |
238 | |
239 | |
240 static void | |
241 ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev) | |
242 { | |
243 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
244 | |
245 ngx_uint_t i; | |
246 ngx_connection_t *c; | |
247 | |
248 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, | |
249 "keepalive close handler"); | |
250 | |
251 c = ev->data; | |
252 conf = c->data; | |
253 | |
254 for (i = 0; i < conf->last_cached; i++) { | |
255 if (conf->cached[i] == c) { | |
256 | |
257 conf->cached[i] = conf->cached[--conf->last_cached]; | |
258 | |
259 ngx_close_connection(c); | |
260 return; | |
261 } | |
262 } | |
263 | |
264 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
265 "keepalive close handler: unknown connection %p", c); | |
266 ngx_close_connection(c); | |
165 } | 267 } |
166 | 268 |
167 | 269 |
168 static void * | 270 static void * |
169 ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) | 271 ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) |
177 } | 279 } |
178 | 280 |
179 /* | 281 /* |
180 * set by ngx_pcalloc(): | 282 * set by ngx_pcalloc(): |
181 * | 283 * |
182 * conf->cached = 0; | 284 * conf->last_cached = 0; |
183 * conf->original_init_upstream = NULL; | 285 * conf->original_init_upstream = NULL; |
184 * conf->original_init_peer = NULL; | 286 * conf->original_init_peer = NULL; |
185 */ | 287 */ |
186 | 288 |
289 conf->max_cached = 1; | |
290 | |
187 return conf; | 291 return conf; |
188 } | 292 } |
189 | 293 |
190 | 294 |
191 static char * | 295 static char * |
192 ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 296 ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
193 { | 297 { |
194 ngx_http_upstream_srv_conf_t *uscf; | 298 ngx_http_upstream_srv_conf_t *uscf; |
195 ngx_http_upstream_keepalive_srv_conf_t *kcf; | 299 ngx_http_upstream_keepalive_srv_conf_t *kcf; |
300 | |
301 ngx_int_t n; | |
302 ngx_str_t *value; | |
303 ngx_uint_t i; | |
196 | 304 |
197 uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); | 305 uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); |
198 | 306 |
199 kcf = ngx_http_conf_upstream_srv_conf(uscf, | 307 kcf = ngx_http_conf_upstream_srv_conf(uscf, |
200 ngx_http_upstream_keepalive_module); | 308 ngx_http_upstream_keepalive_module); |
203 ? uscf->peer.init_upstream | 311 ? uscf->peer.init_upstream |
204 : ngx_http_upstream_init_round_robin; | 312 : ngx_http_upstream_init_round_robin; |
205 | 313 |
206 uscf->peer.init_upstream = ngx_http_upstream_init_keepalive; | 314 uscf->peer.init_upstream = ngx_http_upstream_init_keepalive; |
207 | 315 |
316 /* read options */ | |
317 | |
318 value = cf->args->elts; | |
319 | |
320 for (i = 1; i < cf->args->nelts; i++) { | |
321 | |
322 if (ngx_strncmp(value[i].data, "cached=", 7) == 0) { | |
323 n = ngx_atoi(&value[i].data[7], value[i].len - 7); | |
324 | |
325 if (n == NGX_ERROR) { | |
326 goto invalid; | |
327 } | |
328 | |
329 kcf->max_cached = n; | |
330 | |
331 continue; | |
332 } | |
333 | |
334 goto invalid; | |
335 } | |
336 | |
208 return NGX_CONF_OK; | 337 return NGX_CONF_OK; |
209 } | 338 |
339 invalid: | |
340 | |
341 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
342 "invalid parameter \"%V\"", &value[i]); | |
343 | |
344 return NGX_CONF_ERROR; | |
345 } |