[go: nahoru, domu]

Skip to content

Commit

Permalink
Merge pull request h2o#1471 from h2o/kazuho/lb-vs-non-keep-alive
Browse files Browse the repository at this point in the history
load balancing using non-persistent backends
  • Loading branch information
kazuho committed Oct 25, 2017
2 parents 0c70f27 + 63e6dfa commit 24ab9c6
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 165 deletions.
6 changes: 6 additions & 0 deletions h2o.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,9 @@
E9708B061E49A3130029E0A5 /* sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sha256.c; sourceTree = "<group>"; };
E9708B071E49A3130029E0A5 /* tassert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tassert.h; sourceTree = "<group>"; };
E9708B1B1E49A3480029E0A5 /* handy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = handy.h; sourceTree = "<group>"; };
E9A410951F9EA2E400D9B0FB /* 50reverse-proxy-multiple-backends-with-down.t */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "50reverse-proxy-multiple-backends-with-down.t"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
E9A410961F9EA2F100D9B0FB /* 50reverse-proxy-multiple-backends.t */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "50reverse-proxy-multiple-backends.t"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
E9A410971F9EA2F200D9B0FB /* 50reverse-proxy-round-robin.t */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "50reverse-proxy-round-robin.t"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
E9BC76BF1EE3D71000EB7A09 /* 40redis-session-resumption.t */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "40redis-session-resumption.t"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
E9BC76C01EE3D8A100EB7A09 /* 40server-push-attrs.t */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "40server-push-attrs.t"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
E9BC76C11EE3D9A900EB7A09 /* 50compress-hint.t */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "50compress-hint.t"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
Expand Down Expand Up @@ -1681,8 +1684,11 @@
104C65021A6DF36B000AC190 /* 50reverse-proxy-config.t */,
108102151C3DB05100C024CD /* 50reverse-proxy-disconnected-keepalive.t */,
10DA969A1CCEF2C200679165 /* 50reverse-proxy-https.t */,
E9A410961F9EA2F100D9B0FB /* 50reverse-proxy-multiple-backends.t */,
E9A410951F9EA2E400D9B0FB /* 50reverse-proxy-multiple-backends-with-down.t */,
E9BC76C31EE4AA4600EB7A09 /* 50reverse-proxy-preserve-case.t */,
10FEF2441D6444E900E11B1D /* 50reverse-proxy-proxy-protocol.t */,
E9A410971F9EA2F200D9B0FB /* 50reverse-proxy-round-robin.t */,
E9BC76C41EE4AA9700EB7A09 /* 50reverse-proxy-session-resumption.t */,
10AA2EB21A9479B4004322AC /* 50reverse-proxy-upstream-down.t */,
104B9A2B1A4BBDA4009EEE64 /* 50server-starter.t */,
Expand Down
32 changes: 18 additions & 14 deletions include/h2o/socketpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,26 @@ typedef enum en_h2o_socketpool_target_type_t {
} h2o_socketpool_target_type_t;

typedef struct st_h2o_socketpool_target_t {
/**
* target URL
*/
h2o_url_t url;
/**
* target type (extracted from url)
*/
h2o_socketpool_target_type_t type;
int is_ssl;
struct {
h2o_iovec_t host;
uint16_t port;
union {
/* used to specify servname passed to getaddrinfo */
h2o_iovec_t named_serv;
/* if type is sockaddr, the `host` is not resolved but is used for TLS SNI and hostname verification */
struct {
struct sockaddr_storage bytes;
socklen_t len;
} sockaddr;
};
/**
* peer address (extracted from url)
*/
union {
/* used to specify servname passed to getaddrinfo */
h2o_iovec_t named_serv;
/* if type is sockaddr, the `host` is not resolved but is used for TLS SNI and hostname verification */
struct {
struct sockaddr_storage bytes;
socklen_t len;
} sockaddr;
} peer;
h2o_url_t *url;

struct {
h2o_linklist_t sockets;
Expand Down
40 changes: 16 additions & 24 deletions lib/common/socketpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ static void lb_rr_dispose(void *data)

h2o_socketpool_target_type_t detect_target_type(h2o_url_t *url, struct sockaddr_storage *sa, socklen_t *salen)
{
memset(sa, 0, sizeof(*sa));
const char *to_sun_err = h2o_url_host_to_sun(url->host, (struct sockaddr_un *)sa);
if (to_sun_err == h2o_url_host_to_sun_err_is_not_unix_socket) {
sa->ss_family = AF_INET;
Expand All @@ -195,22 +196,20 @@ h2o_socketpool_target_type_t detect_target_type(h2o_url_t *url, struct sockaddr

void init_target(h2o_socketpool_target_t *target, h2o_url_t *origin)
{
assert(origin != NULL);

struct sockaddr_storage sa;
socklen_t salen;

memset(&sa, 0, sizeof(sa));

target->is_ssl = origin->scheme->is_ssl;
h2o_url_copy(NULL, &target->url, origin);
target->type = detect_target_type(origin, &sa, &salen);
target->peer.host = h2o_strdup(NULL, origin->host.base, origin->host.len);
target->peer.port = h2o_url_get_port(origin);
if (!(target->type == H2O_SOCKETPOOL_TYPE_SOCKADDR && sa.ss_family == AF_UNIX)) {
h2o_strtolower(target->url.authority.base, target->url.authority.len);
h2o_strtolower(target->url.host.base, target->url.host.len);
}

switch (target->type) {
case H2O_SOCKETPOOL_TYPE_NAMED:
target->peer.named_serv.base = h2o_mem_alloc(sizeof(H2O_UINT16_LONGEST_STR));
target->peer.named_serv.len = sprintf(target->peer.named_serv.base, "%u", (unsigned)target->peer.port);
target->peer.named_serv.len = sprintf(target->peer.named_serv.base, "%u", (unsigned)h2o_url_get_port(&target->url));
break;
case H2O_SOCKETPOOL_TYPE_SOCKADDR:
assert(salen <= sizeof(target->peer.sockaddr.bytes));
Expand All @@ -219,8 +218,6 @@ void init_target(h2o_socketpool_target_t *target, h2o_url_t *origin)
break;
}

target->url = h2o_mem_alloc(sizeof(*target->url));
h2o_url_copy(NULL, target->url, origin);
h2o_linklist_init_anchor(&target->_shared.sockets);
}

Expand Down Expand Up @@ -262,21 +259,16 @@ void h2o_socketpool_init_global(h2o_socketpool_t *pool, size_t capacity)

void dispose_target(h2o_socketpool_target_t *target)
{
free(target->peer.host.base);
switch (target->type) {
case H2O_SOCKETPOOL_TYPE_NAMED:
free(target->peer.named_serv.base);
break;
case H2O_SOCKETPOOL_TYPE_SOCKADDR:
break;
}
if (target->url != NULL) {
free(target->url->authority.base);
free(target->url->host.base);
free(target->url->path.base);
free(target->url);
}

free(target->url.authority.base);
free(target->url.host.base);
free(target->url.path.base);
free(target);
}

Expand Down Expand Up @@ -337,7 +329,7 @@ static void call_connect_cb(h2o_socketpool_connect_request_t *req, const char *e
}

free(req);
cb(sock, errstr, data, selected_target->url);
cb(sock, errstr, data, &selected_target->url);
}

static void try_connect(h2o_socketpool_connect_request_t *req)
Expand All @@ -356,7 +348,7 @@ static void try_connect(h2o_socketpool_connect_request_t *req)
switch (target->type) {
case H2O_SOCKETPOOL_TYPE_NAMED:
/* resolve the name, and connect */
req->getaddr_req = h2o_hostinfo_getaddr(req->getaddr_receiver, target->peer.host, target->peer.named_serv, AF_UNSPEC,
req->getaddr_req = h2o_hostinfo_getaddr(req->getaddr_receiver, target->url.host, target->peer.named_serv, AF_UNSPEC,
SOCK_STREAM, IPPROTO_TCP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, req);
break;
case H2O_SOCKETPOOL_TYPE_SOCKADDR:
Expand Down Expand Up @@ -435,11 +427,11 @@ static size_t lookup_target(h2o_socketpool_t *pool, h2o_url_t *url)
size_t i = 0;
for (; i != pool->targets.size; ++i) {
h2o_socketpool_target_t *target = pool->targets.entries[i];
if (target->is_ssl != url->scheme->is_ssl)
if (target->url.scheme != url->scheme)
continue;
if (target->peer.port != port)
if (h2o_url_get_port(&target->url) != port)
continue;
if (memcmp(target->peer.host.base, url->host.base, url->host.len) != 0)
if (!h2o_url_hosts_are_equal(&target->url, url))
continue;
return i;
}
Expand Down Expand Up @@ -497,7 +489,7 @@ void h2o_socketpool_connect(h2o_socketpool_connect_request_t **_req, h2o_socketp
close_data->target = entry_target;
sock->on_close.cb = on_close;
sock->on_close.data = close_data;
cb(sock, NULL, data, pool->targets.entries[entry_target]->url);
cb(sock, NULL, data, &pool->targets.entries[entry_target]->url);
return;
}

Expand Down
10 changes: 0 additions & 10 deletions lib/handler/configurator/proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,6 @@ static int on_config_reverse_backends(h2o_configurator_command_t *cmd, h2o_confi
case YOML_TYPE_SEQUENCE:
sequence = 1;
count = node->data.sequence.size;
if (self->vars->keepalive_timeout == 0 && count > 1) {
h2o_configurator_errprintf(cmd, node, "currently we do not support multiple backends with keep-alive disabled");
return -1;
}
upstreams = alloca(count * sizeof(h2o_url_t));
for (i = 0; i != node->data.sequence.size; ++i) {
yoml_t *element = node->data.sequence.elements[i];
Expand All @@ -353,12 +349,6 @@ static int on_config_reverse_backends(h2o_configurator_command_t *cmd, h2o_confi
return -1;
}

if (self->vars->use_proxy_protocol) {
h2o_configurator_errprintf(cmd, node,
"currently we do not support multiple backends with `proxy.use-proxy-protocol` enabled");
return -1;
}

if (self->vars->registered_as_url) {
h2o_configurator_errprintf(cmd, node,
"please either set `proxy.reverse.backends` with `proxy.reverse.path` to support "
Expand Down
2 changes: 1 addition & 1 deletion lib/handler/fastcgi.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ static int on_req(h2o_handler_t *_handler, h2o_req_t *req)
generator->timeout = (h2o_timeout_entry_t){0};

set_timeout(generator, &generator->ctx->io_timeout, on_connect_timeout);
h2o_socketpool_connect(&generator->connect_req, &handler->sockpool, handler->sockpool.targets.entries[0]->url,
h2o_socketpool_connect(&generator->connect_req, &handler->sockpool, &handler->sockpool.targets.entries[0]->url,
req->conn->ctx->loop, &req->conn->ctx->receivers.hostinfo_getaddr, on_connect, generator);

return 0;
Expand Down
67 changes: 28 additions & 39 deletions lib/handler/proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,22 @@

struct rp_handler_t {
h2o_handler_t super;
h2o_url_t upstream; /* host should be NULL-terminated */
h2o_socketpool_t *sockpool; /* non-NULL if config.use_keepalive == 1 */
h2o_socketpool_t sockpool;
h2o_proxy_config_vars_t config;
};

static int on_req(h2o_handler_t *_self, h2o_req_t *req)
{
struct rp_handler_t *self = (void *)_self;
h2o_req_overrides_t *overrides = h2o_mem_alloc_pool(&req->pool, sizeof(*overrides));
h2o_url_t *upstream_url = &self->sockpool.targets.entries[0]->url;
const h2o_url_scheme_t *scheme;
h2o_iovec_t *authority;

/* setup overrides */
*overrides = (h2o_req_overrides_t){NULL};
if (self->sockpool != NULL) {
overrides->socketpool = self->sockpool;
} else if (self->config.preserve_host) {
overrides->upstream = &self->upstream;
}
overrides->location_rewrite.match = &self->upstream;
overrides->socketpool = &self->sockpool;
overrides->location_rewrite.match = upstream_url;
overrides->location_rewrite.path_prefix = req->pathconf->path;
overrides->use_proxy_protocol = self->config.use_proxy_protocol;
overrides->max_buffer_size = self->config.max_buffer_size;
Expand All @@ -57,14 +53,14 @@ static int on_req(h2o_handler_t *_self, h2o_req_t *req)
authority = &req->authority;
overrides->proxy_preserve_host = 1;
} else {
scheme = self->upstream.scheme;
authority = &self->upstream.authority;
scheme = upstream_url->scheme;
authority = &upstream_url->authority;
overrides->proxy_preserve_host = 0;
}

/* request reprocess */
h2o_reprocess_request(req, req->method, scheme, *authority,
h2o_build_destination(req, self->upstream.path.base, self->upstream.path.len, 0), overrides, 0);
h2o_build_destination(req, upstream_url->path.base, upstream_url->path.len, 0), overrides, 0);

return 0;
}
Expand All @@ -74,8 +70,7 @@ static void on_context_init(h2o_handler_t *_self, h2o_context_t *ctx)
struct rp_handler_t *self = (void *)_self;

/* use the loop of first context for handling socketpool timeouts */
if (self->sockpool != NULL)
h2o_socketpool_register_loop(self->sockpool, ctx->loop);
h2o_socketpool_register_loop(&self->sockpool, ctx->loop);

/* setup a specific client context only if we need to */
if (ctx->globalconf->proxy.io_timeout == self->config.io_timeout &&
Expand Down Expand Up @@ -132,8 +127,7 @@ static void on_context_dispose(h2o_handler_t *_self, h2o_context_t *ctx)
h2o_timeout_dispose(client_ctx->loop, client_ctx->websocket_timeout);
free(client_ctx->websocket_timeout);
}
if (self->sockpool != NULL)
h2o_socketpool_unregister_loop(self->sockpool, ctx->loop);
h2o_socketpool_unregister_loop(&self->sockpool, ctx->loop);
free(client_ctx);
}

Expand All @@ -143,41 +137,36 @@ static void on_handler_dispose(h2o_handler_t *_self)

if (self->config.ssl_ctx != NULL)
SSL_CTX_free(self->config.ssl_ctx);
free(self->upstream.host.base);
free(self->upstream.path.base);
if (self->sockpool != NULL) {
h2o_socketpool_dispose(self->sockpool);
free(self->sockpool);
}
h2o_socketpool_dispose(&self->sockpool);
}

void h2o_proxy_register_reverse_proxy(h2o_pathconf_t *pathconf, h2o_url_t *upstreams, size_t count, h2o_proxy_config_vars_t *config)
void h2o_proxy_register_reverse_proxy(h2o_pathconf_t *pathconf, h2o_url_t *upstreams, size_t num_upstreams,
h2o_proxy_config_vars_t *config)
{
struct sockaddr_un sa;
const char *to_sa_err;
assert(num_upstreams != 0);

struct rp_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self));

self->super.on_context_init = on_context_init;
self->super.on_context_dispose = on_context_dispose;
self->super.dispose = on_handler_dispose;
self->super.on_req = on_req;
self->super.supports_request_streaming = 1;
if (config->keepalive_timeout != 0) {
self->config = *config;

/* init socket pool */
if (config->registered_as_backends && config->reverse_path.base != NULL) {
/* create shallow copy of upstreams so that we can modify them */
h2o_url_t *p = alloca(sizeof(*upstreams) * num_upstreams);
memcpy(p, upstreams, sizeof(*upstreams) * num_upstreams);
upstreams = p;
size_t i;
self->sockpool = h2o_mem_alloc(sizeof(*self->sockpool));
for (i = 0; i != count; ++i) {
if (config->registered_as_backends && config->reverse_path.base != NULL) {
upstreams[i].path = config->reverse_path;
}
}
h2o_socketpool_init_specific(self->sockpool, SIZE_MAX /* FIXME */, upstreams, count);
h2o_socketpool_set_timeout(self->sockpool, config->keepalive_timeout);
}
to_sa_err = h2o_url_host_to_sun(upstreams[0].host, &sa);
h2o_url_copy(NULL, &self->upstream, &upstreams[0]);
if (to_sa_err) {
h2o_strtolower(self->upstream.host.base, self->upstream.host.len);
for (i = 0; i != num_upstreams; ++i)
upstreams[i].path = config->reverse_path;
}
self->config = *config;
h2o_socketpool_init_specific(&self->sockpool, SIZE_MAX /* FIXME */, upstreams, num_upstreams);
h2o_socketpool_set_timeout(&self->sockpool, config->keepalive_timeout);

if (self->config.ssl_ctx != NULL)
SSL_CTX_up_ref(self->config.ssl_ctx);
}
Loading

0 comments on commit 24ab9c6

Please sign in to comment.