diff --git a/auto/modules b/auto/modules index a78e785..30e1645 100644 --- a/auto/modules +++ b/auto/modules @@ -376,6 +376,7 @@ if [ $HTTP_UPSTREAM_LEAST_CONN = YES ]; then fi if [ $HTTP_UPSTREAM_KEEPALIVE = YES ]; then + have=NGX_HTTP_UPSTREAM_KEEPALIVE . auto/have HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_KEEPALIVE_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_KEEPALIVE_SRCS" fi diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 5e62caa..9fee00b 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -513,6 +513,22 @@ static ngx_command_t ngx_http_proxy_commands[] = { #endif +#if (NGX_HTTP_UPSTREAM_KEEPALIVE) + { ngx_string("proxy_upstream_default_keepalive"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.default_keepalive), + NULL }, + + { ngx_string("proxy_upstream_default_keepalive_max_connections"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.default_keepalive_max_connections), + NULL }, +#endif + ngx_null_command }; @@ -2385,6 +2401,11 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->redirects = NULL; */ +#if (NGX_HTTP_UPSTREAM_KEEPALIVE) + conf->upstream.default_keepalive = NGX_CONF_UNSET; + conf->upstream.default_keepalive_max_connections = NGX_CONF_UNSET_SIZE; +#endif + conf->upstream.store = NGX_CONF_UNSET; conf->upstream.store_access = NGX_CONF_UNSET_UINT; conf->upstream.buffering = NGX_CONF_UNSET; @@ -2467,6 +2488,20 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) } } +#if (NGX_HTTP_UPSTREAM_KEEPALIVE) + ngx_conf_merge_uint_value(conf->upstream.default_keepalive, + prev->upstream.default_keepalive, 0); + + ngx_conf_merge_size_value(conf->upstream.default_keepalive_max_connections, + prev->upstream.default_keepalive_max_connections, 10); + + if (conf->upstream.default_keepalive) { + if (ngx_http_upstream_default_keepalive_init(cf, &(conf->upstream)) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + } +#endif + ngx_conf_merge_uint_value(conf->upstream.store_access, prev->upstream.store_access, 0600); diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index eed1174..3723668 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -36,6 +36,8 @@ typedef struct { ngx_event_set_peer_session_pt original_set_session; ngx_event_save_peer_session_pt original_save_session; #endif + + ngx_str_t host; } ngx_http_upstream_keepalive_peer_data_t; @@ -49,6 +51,9 @@ typedef struct { socklen_t socklen; u_char sockaddr[NGX_SOCKADDRLEN]; + char host[NGX_MAXHOSTNAMELEN]; + uint16_t host_len; + } ngx_http_upstream_keepalive_cache_t; @@ -184,6 +189,8 @@ ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r, return NGX_ERROR; } + kp->host = us->host; + kp->conf = kcf; kp->upstream = r->upstream; kp->data = r->upstream->peer.data; @@ -238,8 +245,9 @@ ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) c = item->connection; if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr, - item->socklen, pc->socklen) - == 0) + item->socklen, pc->socklen) == 0 && + ngx_memn2cmp((u_char *) &item->host, (u_char *) kp->host.data, + item->host_len, kp->host.len) == 0) { ngx_queue_remove(q); ngx_queue_insert_head(&kp->conf->free, q); @@ -345,6 +353,8 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, item->socklen = pc->socklen; ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen); + item->host_len = kp->host.len; + ngx_memcpy(&item->host, kp->host.data, ngx_min(kp->host.len, NGX_MAXHOSTNAMELEN)); if (c->read->ready) { ngx_http_upstream_keepalive_close_handler(c->read); @@ -537,3 +547,77 @@ invalid: return NGX_CONF_ERROR; } + +char * +ngx_http_upstream_default_keepalive_init(ngx_conf_t *cf, + ngx_http_upstream_conf_t *umcf) +{ + ngx_uint_t i; + ngx_http_upstream_keepalive_cache_t *cached; + ngx_http_upstream_keepalive_srv_conf_t *kcf; + + kcf = ngx_pcalloc(cf->pool, + sizeof(ngx_http_upstream_keepalive_srv_conf_t)); + if (kcf == NULL) { + return NGX_CONF_ERROR; + } + + kcf->max_cached = umcf->default_keepalive_max_connections; + + cached = ngx_pcalloc(cf->pool, + sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached); + if (cached == NULL) { + return NGX_CONF_ERROR; + } + + ngx_queue_init(&kcf->cache); + ngx_queue_init(&kcf->free); + + for (i = 0; i < kcf->max_cached; i += 1) { + ngx_queue_insert_head(&kcf->free, &cached[i].queue); + cached[i].conf = kcf; + } + + umcf->default_keepalive_cache = kcf; + + return NGX_CONF_OK; +} + +ngx_int_t +ngx_http_upstream_default_keepalive_adapt_peer(ngx_http_request_t *r, + ngx_http_upstream_resolved_t *ur) +{ + ngx_http_upstream_keepalive_peer_data_t *kp; + ngx_http_upstream_keepalive_srv_conf_t *kcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "default keepalive adapt peer"); + + kcf = r->upstream->conf->default_keepalive_cache; + + kp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_keepalive_peer_data_t)); + if (kp == NULL) { + return NGX_ERROR; + } + + kp->host = ur->host; + + kp->conf = kcf; + kp->upstream = r->upstream; + kp->data = r->upstream->peer.data; + kp->original_get_peer = r->upstream->peer.get; + kp->original_free_peer = r->upstream->peer.free; + + r->upstream->peer.data = kp; + r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer; + r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer; + +#if (NGX_HTTP_SSL) + kp->original_set_session = r->upstream->peer.set_session; + kp->original_save_session = r->upstream->peer.save_session; + r->upstream->peer.set_session = ngx_http_upstream_keepalive_set_session; + r->upstream->peer.save_session = ngx_http_upstream_keepalive_save_session; +#endif + + return NGX_OK; +} diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index d4dc1bd..4d54634 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -51,6 +51,10 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, #if (NGX_HTTP_SSL) #include <ngx_http_ssl_module.h> #endif +#if (NGX_HTTP_UPSTREAM_KEEPALIVE) +#include <ngx_http_upstream_keepalive_module.h> +#endif + struct ngx_http_log_ctx_s { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 45e2eb7..2a2ca1c 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -931,6 +931,15 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) goto failed; } +#if (NGX_HTTP_UPSTREAM_KEEPALIVE) + if (r->upstream->conf->default_keepalive) { + if (ngx_http_upstream_default_keepalive_adapt_peer(r, ur) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream default keepalive: can't keepalive peer"); + } + } +#endif + ngx_resolve_name_done(ctx); ur->ctx = NULL; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 29ebf9b..7564050 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -194,6 +194,12 @@ typedef struct { #endif ngx_str_t module; + +#if (NGX_HTTP_UPSTREAM_KEEPALIVE) + ngx_uint_t default_keepalive; + ngx_uint_t default_keepalive_max_connections; + void *default_keepalive_cache; +#endif } ngx_http_upstream_conf_t;