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 }