You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Jeff Trawick <tr...@gmail.com> on 2007/11/13 14:30:40 UTC
keepalive connections and exiting MPM processes
When the MPM process handling the connection is or will be exiting, we
can incorrectly tell the client that the connection will be held open
after the current request. This can result in user intervention
(retry the POST?) or failures for some requests sent subsequently on
that connection.
The case where we already know we're exiting at the time we determine
the keep-alive setting is simple to handle:
Index: modules/http/http_protocol.c
===================================================================
--- modules/http/http_protocol.c (revision 593813)
+++ modules/http/http_protocol.c (working copy)
@@ -48,6 +48,7 @@
#include "util_charset.h"
#include "util_ebcdic.h"
#include "util_time.h"
+#include "ap_mpm.h"
#include "mod_core.h"
@@ -187,6 +188,7 @@
* or they're a buggy twit coming through a HTTP/1.1 proxy
* and the client is requesting an HTTP/1.0-style keep-alive
* or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
+ * and this MPM process is not already exiting
* THEN we can be persistent, which requires more headers be output.
*
* Note that the condition evaluation order is extremely important.
@@ -212,7 +214,8 @@
&& (!apr_table_get(r->subprocess_env, "nokeepalive")
|| apr_table_get(r->headers_in, "Via"))
&& ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
- || (r->proto_num >= HTTP_VERSION(1,1)))) {
+ || (r->proto_num >= HTTP_VERSION(1,1)))
+ && !ap_graceful_stop_signalled()) {
int left = r->server->keep_alive_max - r->connection->keepalives;
r->connection->keepalive = AP_CONN_KEEPALIVE;
It isn't so clear how to handle the remaining window, in which the MPM
process starts exiting while we send the response (and after we've
already determined the keepalive setting).
>From ap_process_http_connection():
if (r->status == HTTP_OK) {
cs->state = CONN_STATE_HANDLER;
ap_process_request(r);
r = NULL;
}
if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
break;
XXXXXXXXXXX
We could skip checking for graceful exit here since it is checked
as part of the keepalive determination, but the MPM process
could remain active much longer than expected (maybe we just
downloaded a very large file).
XXXXXXXXXXX
if (ap_graceful_stop_signalled())
break;
For the remaining timing window, I'm afraid that a vhost-specific
setting is needed to control whether we respect the connection
keepalive setting or the MPM state. (The latter is apparently good
enough for most folks, and it does avoid unexpected delays in child
processes exiting and switching to new configs.)
Thoughts?
Re: keepalive connections and exiting MPM processes
Posted by Jim Jagielski <ji...@jaguNET.com>.
On Nov 13, 2007, at 8:30 AM, Jeff Trawick wrote:
> When the MPM process handling the connection is or will be exiting, we
> can incorrectly tell the client that the connection will be held open
> after the current request. This can result in user intervention
> (retry the POST?) or failures for some requests sent subsequently on
> that connection.
>
> The case where we already know we're exiting at the time we determine
> the keep-alive setting is simple to handle:
>
> #include "mod_core.h"
>
> @@ -187,6 +188,7 @@
> * or they're a buggy twit coming through a HTTP/1.1 proxy
> * and the client is requesting an HTTP/1.0-style keep-alive
> * or the client claims to be HTTP/1.1 compliant
> (perhaps a proxy);
> + * and this MPM process is not already exiting
> * THEN we can be persistent, which requires more headers be
> output.
> *
> * Note that the condition evaluation order is extremely
> important.
> @@ -212,7 +214,8 @@
> && (!apr_table_get(r->subprocess_env, "nokeepalive")
> || apr_table_get(r->headers_in, "Via"))
> && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
> - || (r->proto_num >= HTTP_VERSION(1,1)))) {
> + || (r->proto_num >= HTTP_VERSION(1,1)))
> + && !ap_graceful_stop_signalled()) {
> int left = r->server->keep_alive_max - r->connection-
> >keepalives;
>
> r->connection->keepalive = AP_CONN_KEEPALIVE;
>
Concept-wise, this makes sense...
Re: keepalive connections and exiting MPM processes
Posted by Jeff Trawick <tr...@gmail.com>.
On Nov 13, 2007 10:38 AM, Jeff Trawick <tr...@gmail.com> wrote:
> On Nov 13, 2007 8:57 AM, Plüm, Rüdiger, VF-Group
> <ru...@vodafone.com> wrote:
> >
> >
> > > -----Ursprüngliche Nachricht-----
> > > Von: Jeff Trawick
> > > Gesendet: Dienstag, 13. November 2007 14:31
> > > An: dev@httpd.apache.org
> > > Betreff: keepalive connections and exiting MPM processes
> >
> > >
> > >
> > > When the MPM process handling the connection is or will be exiting, we
> > > can incorrectly tell the client that the connection will be held open
> > > after the current request. This can result in user intervention
> > > (retry the POST?) or failures for some requests sent subsequently on
> > > that connection.
>
> ...
>
>
> > > It isn't so clear how to handle the remaining window, in which the MPM
> > > process starts exiting while we send the response (and after we've
> > > already determined the keepalive setting).
> > >
> > > From ap_process_http_connection():
> > >
> > > if (r->status == HTTP_OK) {
> > > cs->state = CONN_STATE_HANDLER;
> > > ap_process_request(r);
> > > r = NULL;
> > > }
> > >
> > > if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
> > > break;
> > >
> > > XXXXXXXXXXX
> > > We could skip checking for graceful exit here since
> > > it is checked
> > > as part of the keepalive determination, but the MPM process
> > > could remain active much longer than expected (maybe we just
> > > downloaded a very large file).
> > > XXXXXXXXXXX
> > >
> > > if (ap_graceful_stop_signalled())
> > > break;
> > >
> > > For the remaining timing window, I'm afraid that a vhost-specific
> > > setting is needed to control whether we respect the connection
> > > keepalive setting or the MPM state. (The latter is apparently good
> >
> > I guess we can leave it as it is in this situation. Although we SHOULD
> > send connection: close if want to close the connection it is no MUST
> > (8.1.2.1, last sentence first paragraph). And for pipelined requests the
> > client must be prepared to resend anyway if we do not process all pipelined
> > requests (8.1.2.2).
>
> Apart from the SHOULD vs. MUST is the end-user issue when the client
> software can't or won't retry automatically when confronted with a
> validly-dropped connection ;)
Here's a patch to address that issue:
http://people.apache.org/~trawick/keepalive.txt
(KeepAliveWhileExiting On|Off, default Off)
It comes down to this check in ap_process_http_connection():
while ((r = ap_read_request(c)) != NULL) {
...
if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
break;
...
if (!c->base_server->keep_alive_while_exiting &&
ap_graceful_stop_signalled())
break;
}
The only commentary I've seen on the general idea so far is that the
RFC doesn't force us to respect that persistence.
Re: keepalive connections and exiting MPM processes
Posted by Jeff Trawick <tr...@gmail.com>.
On Nov 13, 2007 8:57 AM, Plüm, Rüdiger, VF-Group
<ru...@vodafone.com> wrote:
>
>
> > -----Ursprüngliche Nachricht-----
> > Von: Jeff Trawick
> > Gesendet: Dienstag, 13. November 2007 14:31
> > An: dev@httpd.apache.org
> > Betreff: keepalive connections and exiting MPM processes
>
> >
> >
> > When the MPM process handling the connection is or will be exiting, we
> > can incorrectly tell the client that the connection will be held open
> > after the current request. This can result in user intervention
> > (retry the POST?) or failures for some requests sent subsequently on
> > that connection.
...
> > It isn't so clear how to handle the remaining window, in which the MPM
> > process starts exiting while we send the response (and after we've
> > already determined the keepalive setting).
> >
> > From ap_process_http_connection():
> >
> > if (r->status == HTTP_OK) {
> > cs->state = CONN_STATE_HANDLER;
> > ap_process_request(r);
> > r = NULL;
> > }
> >
> > if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
> > break;
> >
> > XXXXXXXXXXX
> > We could skip checking for graceful exit here since
> > it is checked
> > as part of the keepalive determination, but the MPM process
> > could remain active much longer than expected (maybe we just
> > downloaded a very large file).
> > XXXXXXXXXXX
> >
> > if (ap_graceful_stop_signalled())
> > break;
> >
> > For the remaining timing window, I'm afraid that a vhost-specific
> > setting is needed to control whether we respect the connection
> > keepalive setting or the MPM state. (The latter is apparently good
>
> I guess we can leave it as it is in this situation. Although we SHOULD
> send connection: close if want to close the connection it is no MUST
> (8.1.2.1, last sentence first paragraph). And for pipelined requests the
> client must be prepared to resend anyway if we do not process all pipelined
> requests (8.1.2.2).
Apart from the SHOULD vs. MUST is the end-user issue when the client
software can't or won't retry automatically when confronted with a
validly-dropped connection ;)
Re: keepalive connections and exiting MPM processes
Posted by Plüm,
Rüdiger,
VF-Group <ru...@vodafone.com>.
> -----Ursprüngliche Nachricht-----
> Von: Jeff Trawick
> Gesendet: Dienstag, 13. November 2007 14:31
> An: dev@httpd.apache.org
> Betreff: keepalive connections and exiting MPM processes
>
>
> When the MPM process handling the connection is or will be exiting, we
> can incorrectly tell the client that the connection will be held open
> after the current request. This can result in user intervention
> (retry the POST?) or failures for some requests sent subsequently on
> that connection.
>
> The case where we already know we're exiting at the time we determine
> the keep-alive setting is simple to handle:
>
> Index: modules/http/http_protocol.c
> ===================================================================
> --- modules/http/http_protocol.c (revision 593813)
> +++ modules/http/http_protocol.c (working copy)
> @@ -48,6 +48,7 @@
> #include "util_charset.h"
> #include "util_ebcdic.h"
> #include "util_time.h"
> +#include "ap_mpm.h"
>
> #include "mod_core.h"
>
> @@ -187,6 +188,7 @@
> * or they're a buggy twit coming through a HTTP/1.1 proxy
> * and the client is requesting an HTTP/1.0-style keep-alive
> * or the client claims to be HTTP/1.1 compliant
> (perhaps a proxy);
> + * and this MPM process is not already exiting
> * THEN we can be persistent, which requires more
> headers be output.
> *
> * Note that the condition evaluation order is extremely
> important.
> @@ -212,7 +214,8 @@
> && (!apr_table_get(r->subprocess_env, "nokeepalive")
> || apr_table_get(r->headers_in, "Via"))
> && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
> - || (r->proto_num >= HTTP_VERSION(1,1)))) {
> + || (r->proto_num >= HTTP_VERSION(1,1)))
> + && !ap_graceful_stop_signalled()) {
> int left = r->server->keep_alive_max -
> r->connection->keepalives;
>
> r->connection->keepalive = AP_CONN_KEEPALIVE;
Looks like a reasonable patch.
>
> It isn't so clear how to handle the remaining window, in which the MPM
> process starts exiting while we send the response (and after we've
> already determined the keepalive setting).
>
> From ap_process_http_connection():
>
> if (r->status == HTTP_OK) {
> cs->state = CONN_STATE_HANDLER;
> ap_process_request(r);
> r = NULL;
> }
>
> if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
> break;
>
> XXXXXXXXXXX
> We could skip checking for graceful exit here since
> it is checked
> as part of the keepalive determination, but the MPM process
> could remain active much longer than expected (maybe we just
> downloaded a very large file).
> XXXXXXXXXXX
>
> if (ap_graceful_stop_signalled())
> break;
>
> For the remaining timing window, I'm afraid that a vhost-specific
> setting is needed to control whether we respect the connection
> keepalive setting or the MPM state. (The latter is apparently good
I guess we can leave it as it is in this situation. Although we SHOULD
send connection: close if want to close the connection it is no MUST
(8.1.2.1, last sentence first paragraph). And for pipelined requests the
client must be prepared to resend anyway if we do not process all pipelined
requests (8.1.2.2).
Regards
Rüdiger
Re: keepalive connections and exiting MPM processes
Posted by "Akins, Brian" <Br...@turner.com>.
On 11/13/07 8:30 AM, "Jeff Trawick" <tr...@gmail.com> wrote:
> * Note that the condition evaluation order is extremely important.
> @@ -212,7 +214,8 @@
> && (!apr_table_get(r->subprocess_env, "nokeepalive")
> || apr_table_get(r->headers_in, "Via"))
> && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
> - || (r->proto_num >= HTTP_VERSION(1,1)))) {
> + || (r->proto_num >= HTTP_VERSION(1,1)))
> + && !ap_graceful_stop_signalled()) {
> int left = r->server->keep_alive_max - r->connection->keepalives;
>
> r->connection->keepalive = AP_CONN_KEEPALIVE;
Looks reasonable.
We do so many checks in this function, and it's a pain to modify. I wish
this were a hook. I have selfish reasons for this, as I want an easy way to
limit the number of keepalives per child (especially in event mpm). It
would be so much easier if this were a hook:
In event somewhere:
static can_http_keepalive(request_rec *r) {
if (current_num_of_keepalives + 1 > configured_max) {
return NO; /*whatever, not OK or declined...*/
}
return OK;
}
When resources get tight, I'd like to disable keepalives so I don't have all
the "freeloading" connections hanging around. (Sometimes every little bit
helps...)
Also, shouldn't Keepalive become HTTPKeepalive and live in the http_module's
config (which doesn't exist, I don't think) rather than is "global"
server_rec. Keepalive doesn't make sense for mod_ftp, mod_dns, etc.
While I'm thinking about this, shouldn't virtual server selection be a hook
rather than the current "core" way... Would make eventually "dynamic"
server_rec creation easier.
--
Brian Akins
Chief Operations Engineer
Turner Digital Media Technologies