You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Harrie Hazewinkel <ha...@covalent.net> on 2001/07/06 21:24:12 UTC

[PATCH-concept] more dynamic configuration

HI all,


Attached is a patch that adds more dynamic configuration.
It places some of the MPM variables such as 'ap_max_daemons_limit',
'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free' 
in the scoreboard. This enables management modules to do
dynamic (runtime) configuration without requiring a restart of the
Apache HTTP server.


How is it done:
1) The patch adds a hook after the creation of the scoreboard
	which is used by the MPM to transfer the variables in
	the scoreboard and allows a management modules to change
	those.
2) The MPM during its server maintenance (or spawning of extra
processes)
	use the variables that are now in the scoreboard.
	The children are not influenced in performance from this
	for the variables: 'ap_max_daemons_limit',
	'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free'.
3) The a child uses now the 'max_requests_per_child' from the
scoreboard.
	Which is has little or no impact on the request processing.

This patch works only for the PREFORK MPM. If it is seen as usefull,
we can do the same with the other MPMs and, for instance, add
'ap_threads_min_spare' in the scoreboard as well to allow dynamic
configuration.

Let me know what you think of it.

Harrie
-- 
address: Covalent Technologies, 645 Howard St, San Francisco, CA - 94105
phone: +1-415-536-5221                               fax:+1-415-536-5210
personal website: http://www.lisanza.net/

Re: [PATCH-concept] more dynamic configuration

Posted by Harrie Hazewinkel <ha...@covalent.net>.
Bill Stoddard wrote:
> 
> -1 in concept.
> 
> The server is not architected to handle dynamically changing runtime parameters.

I agree here. But having a few of those dynamically configurable is a
good thing.
What happens when your server reaches the limit of MaxClients where that
limit
is not even close to the HARD_SERVER_LIMIT. Now you have to do a
gracefull
restart to change the situation. I have been told by many people
that during the high load when your server is close to its limits
like MaxClients, they do not want to do a restart.

With this you have the ability to change it without the restart..

> I have
> worked on network servers with dynamic runtime configuration (more than one) and it is a
> support nightmare. This will add a lot of complexity and non intuitive bahaviour to the
> server for relatively little benefit.

There is not complexity involved. Instead of having that variable 
as currently used in the Apache server that variable is in shared 
memory. For the rest it is the same where on top of it modules
like SNMP and MOD_BACKHAND could benefit from it by doing more
adaptive management based on the load of the server.


> If lots of Apache users come out in support for
> function like this, I'll reconsider.

May I read this as "if more poeple want it then it is OK"??


Harrie

Re: [PATCH-concept] more dynamic configuration

Posted by Bill Stoddard <bi...@wstoddard.com>.
-1 in concept.

The server is not architected to handle dynamically changing runtime parameters.  I have
worked on network servers with dynamic runtime configuration (more than one) and it is a
support nightmare. This will add a lot of complexity and non intuitive bahaviour to the
server for relatively little benefit. If lots of Apache users come out in support for
function like this, I'll reconsider.

Bill

>
> Attached is a patch that adds more dynamic configuration.
> It places some of the MPM variables such as 'ap_max_daemons_limit',
> 'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free'
> in the scoreboard. This enables management modules to do
> dynamic (runtime) configuration without requiring a restart of the
> Apache HTTP server.
>
>
> How is it done:
> 1) The patch adds a hook after the creation of the scoreboard
> which is used by the MPM to transfer the variables in
> the scoreboard and allows a management modules to change
> those.
> 2) The MPM during its server maintenance (or spawning of extra
> processes)
> use the variables that are now in the scoreboard.
> The children are not influenced in performance from this
> for the variables: 'ap_max_daemons_limit',
> 'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free'.
> 3) The a child uses now the 'max_requests_per_child' from the
> scoreboard.
> Which is has little or no impact on the request processing.
>
> This patch works only for the PREFORK MPM. If it is seen as usefull,
> we can do the same with the other MPMs and, for instance, add
> 'ap_threads_min_spare' in the scoreboard as well to allow dynamic
> configuration.
>
> Let me know what you think of it.
>
> Harrie
> --
> address: Covalent Technologies, 645 Howard St, San Francisco, CA - 94105
> phone: +1-415-536-5221                               fax:+1-415-536-5210
> personal website: http://www.lisanza.net/


--------------------------------------------------------------------------------


> diff -ru ../httpd-2.0/include/ap_mpm.h ./include/ap_mpm.h
> --- ../httpd-2.0/include/ap_mpm.h Wed Jun 27 10:43:28 2001
> +++ ./include/ap_mpm.h Tue Jul  3 14:18:43 2001
> @@ -169,6 +169,7 @@
>  #define AP_MPMQ_MAX_SPARE_DAEMONS     9  /* Max # of spare daemons       */
>  #define AP_MPMQ_MAX_SPARE_THREADS    10  /* Max # of spare threads       */
>  #define AP_MPMQ_MAX_REQUESTS_DEAMON  11  /* Max # of requests per daemon */
> +#define AP_MPMQ_DAEMONS_USED         12  /* Used # of scoreboard slots   */
>
>
>  /**
> diff -ru ../httpd-2.0/include/scoreboard.h ./include/scoreboard.h
> --- ../httpd-2.0/include/scoreboard.h Sat Jun  9 17:37:59 2001
> +++ ./include/scoreboard.h Thu Jul  5 09:09:19 2001
> @@ -73,6 +73,8 @@
>  #include "apr_thread_proc.h"
>  #include "apr_portable.h"
>
> +AP_DECLARE_HOOK(void,setup_shared_info,(apr_pool_t *pconf,apr_pool_t *plog,server_rec
*s));
> +
>  /* Scoreboard info on a process is, for now, kept very brief ---
>   * just status value and pid (the latter so that the caretaker process
>   * can properly update the scoreboard when a process dies).  We may want
> @@ -169,6 +171,11 @@
>      ap_scoreboard_e sb_type;
>      ap_generation_t running_generation; /* the generation of children which
>                                           * should still be serving requests. */
> +    int ap_max_daemons_limit;           /* used # of scoreboard slots        */
> +    int ap_daemons_limit;               /* max # of clients                  */
> +    int ap_daemons_max_free;            /* max # of spare servers            */
> +    int ap_daemons_min_free;            /* min # of spare servers            */
> +    int ap_max_requests_per_child;      /* max # of requests per child       */
>  } global_score;
>
>  /* stuff which the parent generally writes and the children rarely read */
> diff -ru ../httpd-2.0/server/mpm/prefork/mpm.h ./server/mpm/prefork/mpm.h
> --- ../httpd-2.0/server/mpm/prefork/mpm.h Wed Jun  6 17:09:16 2001
> +++ ./server/mpm/prefork/mpm.h Tue Jul  3 13:56:27 2001
> @@ -75,7 +75,6 @@
>  #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
>
>  extern int ap_threads_per_child;
> -extern int ap_max_daemons_limit;
>  extern server_rec *ap_server_conf;
>  extern char ap_coredump_dir[MAX_STRING_LEN];
>  #endif /* APACHE_MPM_PREFORK_H */
> diff -ru ../httpd-2.0/server/mpm/prefork/prefork.c ./server/mpm/prefork/prefork.c
> --- ../httpd-2.0/server/mpm/prefork/prefork.c Wed Jun 27 10:43:39 2001
> +++ ./server/mpm/prefork/prefork.c Thu Jul  5 11:37:25 2001
> @@ -151,7 +151,6 @@
>   * to deal with MaxClients changes across SIGWINCH restarts.  We use this
>   * value to optimize routines that have to scan the entire scoreboard.
>   */
> -int ap_max_daemons_limit = -1;
>  server_rec *ap_server_conf;
>
>  char ap_coredump_dir[MAX_STRING_LEN];
> @@ -316,7 +315,10 @@
>  {
>      switch(query_code){
>          case AP_MPMQ_MAX_DAEMONS:
> -            *result = ap_daemons_limit;
> +            *result = ap_scoreboard_image->global.ap_daemons_limit;
> +            return APR_SUCCESS;
> +        case AP_MPMQ_DAEMONS_USED:
> +            *result = ap_scoreboard_image->global.ap_max_daemons_limit;
>              return APR_SUCCESS;
>          case AP_MPMQ_IS_THREADED:
>              *result = AP_MPMQ_NOT_SUPPORTED;
> @@ -334,19 +336,19 @@
>              *result = 0;
>              return APR_SUCCESS;
>          case AP_MPMQ_MIN_SPARE_DEAMONS:
> -            *result = ap_daemons_min_free;
> +            *result = ap_scoreboard_image->global.ap_daemons_min_free;
>              return APR_SUCCESS;
>          case AP_MPMQ_MIN_SPARE_THREADS:
>              *result = 0;
>              return APR_SUCCESS;
>          case AP_MPMQ_MAX_SPARE_DAEMONS:
> -            *result = ap_daemons_max_free;
> +            *result = ap_scoreboard_image->global.ap_daemons_max_free;
>              return APR_SUCCESS;
>          case AP_MPMQ_MAX_SPARE_THREADS:
>              *result = 0;
>              return APR_SUCCESS;
>          case AP_MPMQ_MAX_REQUESTS_DEAMON:
> -            *result = ap_max_requests_per_child;
> +            *result = ap_scoreboard_image->global.ap_max_requests_per_child;
>              return APR_SUCCESS;
>      }
>      return APR_ENOTIMPL;
> @@ -361,7 +363,7 @@
>  {
>      int n, pid;
>
> -    for (n = 0; n < ap_max_daemons_limit; ++n) {
> +    for (n = 0; n < ap_scoreboard_image->global.ap_max_daemons_limit; ++n) {
>          ap_sync_scoreboard_image();
>   if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
>   kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
> @@ -598,8 +600,8 @@
>
>   apr_pool_clear(ptrans);
>
> - if ((ap_max_requests_per_child > 0
> -      && requests_this_child++ >= ap_max_requests_per_child)) {
> + if ((ap_scoreboard_image->global.ap_max_requests_per_child > 0
> +      && requests_this_child++ >=
ap_scoreboard_image->global.ap_max_requests_per_child)) {
>       clean_child_exit(0);
>   }
>
> @@ -836,8 +838,8 @@
>  {
>      int pid;
>
> -    if (slot + 1 > ap_max_daemons_limit) {
> - ap_max_daemons_limit = slot + 1;
> +    if (slot + 1 > ap_scoreboard_image->global.ap_max_daemons_limit) {
> + ap_scoreboard_image->global.ap_max_daemons_limit = slot + 1;
>      }
>
>      if (one_process) {
> @@ -920,7 +922,7 @@
>  {
>      int i;
>
> -    for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
> +    for (i = 0; number_to_start && i < ap_scoreboard_image->global.ap_daemons_limit;
++i) {
>   if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
>       continue;
>   }
> @@ -964,10 +966,10 @@
>      total_non_dead = 0;
>
>      ap_sync_scoreboard_image();
> -    for (i = 0; i < ap_daemons_limit; ++i) {
> +    for (i = 0; i < ap_scoreboard_image->global.ap_daemons_limit; ++i) {
>   int status;
>
> - if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
> + if (i >= ap_scoreboard_image->global.ap_max_daemons_limit && free_length ==
idle_spawn_rate)
>       break;
>   ws = &ap_scoreboard_image->servers[i][0];
>   status = ws->status;
> @@ -1000,8 +1002,8 @@
>       last_non_dead = i;
>   }
>      }
> -    ap_max_daemons_limit = last_non_dead + 1;
> -    if (idle_count > ap_daemons_max_free) {
> +    ap_scoreboard_image->global.ap_max_daemons_limit = last_non_dead + 1;
> +    if (idle_count > ap_scoreboard_image->global.ap_daemons_max_free) {
>   /* kill off one child... we use the pod because that'll cause it to
>   * shut down gracefully, in case it happened to pick up a request
>   * while we were counting
> @@ -1009,7 +1011,7 @@
>   ap_mpm_pod_signal(pod);
>   idle_spawn_rate = 1;
>      }
> -    else if (idle_count < ap_daemons_min_free) {
> +    else if (idle_count < ap_scoreboard_image->global.ap_daemons_min_free) {
>   /* terminate the free list */
>   if (free_length == 0) {
>       /* only report this condition once */
> @@ -1110,9 +1112,13 @@
>          return 1;
>      }
>
> +    if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */
> + ap_daemons_max_free = ap_daemons_min_free + 1;
> +
>      SAFE_ACCEPT(accept_mutex_init(pconf));
>      if (!is_graceful) {
>          ap_create_scoreboard(pconf, SB_SHARED);
> +        ap_run_setup_shared_info(pconf, plog, s);
>      }
>  #ifdef SCOREBOARD_FILE
>      else {
> @@ -1123,9 +1129,6 @@
>
>      set_signals();
>
> -    if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */
> - ap_daemons_max_free = ap_daemons_min_free + 1;
> -
>      /* If we're doing a graceful_restart then we're going to see a lot
>   * of children exiting immediately when we get into the main loop
>   * below (because we just sent them SIGWINCH).  This happens pretty
> @@ -1135,8 +1138,8 @@
>   * supposed to start up without the 1 second penalty between each fork.
>   */
>      remaining_children_to_start = ap_daemons_to_start;
> -    if (remaining_children_to_start > ap_daemons_limit) {
> - remaining_children_to_start = ap_daemons_limit;
> +    if (remaining_children_to_start > ap_scoreboard_image->global.ap_daemons_limit) {
> + remaining_children_to_start = ap_scoreboard_image->global.ap_daemons_limit;
>      }
>      if (!is_graceful) {
>   startup_children(remaining_children_to_start);
> @@ -1176,7 +1179,7 @@
>   (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(child_slot), SERVER_DEAD,
>       (request_rec *) NULL);
>   if (remaining_children_to_start
> -     && child_slot < ap_daemons_limit) {
> +     && child_slot < ap_scoreboard_image->global.ap_daemons_limit) {
>       /* we're still doing a 1-for-1 replacement of dead
>   * children with new children
>   */
> @@ -1267,7 +1270,7 @@
>      ap_scoreboard_image->global.running_generation = ap_my_generation;
>      update_scoreboard_global();
>
> -    for (index = 0; index < ap_daemons_limit; ++index) {
> +    for (index = 0; index < ap_scoreboard_image->global.ap_daemons_limit; ++index) {
>          ap_scoreboard_image->parent[index].process_status = SB_IDLE_DIE;
>      }
>
> @@ -1276,7 +1279,7 @@
>       "Graceful restart requested, doing restart");
>
>   /* kill off the idle ones */
> -        ap_mpm_pod_killpg(pod, ap_daemons_limit);
> +        ap_mpm_pod_killpg(pod, ap_scoreboard_image->global.ap_daemons_limit);
>
>  #ifndef SCOREBOARD_FILE
>   /* This is mostly for debugging... so that we know what is still
> @@ -1285,7 +1288,7 @@
>       * corruption too easily.
>       */
>   ap_sync_scoreboard_image();
> - for (index = 0; index < ap_daemons_limit; ++index) {
> + for (index = 0; index < ap_scoreboard_image->global.ap_daemons_limit; ++index) {
>       if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {
>   ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL;
>       }
> @@ -1339,6 +1342,15 @@
>      apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
>  }
>
> +static void prefork_init_shared(apr_pool_t *pconf, apr_pool_t *plog, server_rec *s)
> +{
> +    ap_scoreboard_image->global.ap_max_daemons_limit = -1;
> +    ap_scoreboard_image->global.ap_daemons_limit = ap_daemons_limit;
> +    ap_scoreboard_image->global.ap_daemons_max_free = ap_daemons_max_free;
> +    ap_scoreboard_image->global.ap_daemons_min_free = ap_daemons_min_free;
> +    ap_scoreboard_image->global.ap_max_requests_per_child = ap_max_requests_per_child;
> +}
> +
>  static void prefork_hooks(apr_pool_t *p)
>  {
>  #ifdef AUX3
> @@ -1346,6 +1358,7 @@
>  #endif
>
>      ap_hook_pre_config(prefork_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
> +    ap_hook_setup_shared_info(prefork_init_shared, NULL, NULL, APR_HOOK_MIDDLE);
>  }
>
>  static const char *set_pidfile(cmd_parms *cmd, void *dummy, const char *arg)
> diff -ru ../httpd-2.0/server/scoreboard.c ./server/scoreboard.c
> --- ../httpd-2.0/server/scoreboard.c Mon May 21 18:31:12 2001
> +++ ./server/scoreboard.c Tue Jul  3 13:30:35 2001
> @@ -84,6 +84,14 @@
>  AP_DECLARE_DATA int ap_extended_status = 0;
>  AP_DECLARE_DATA apr_time_t ap_restart_time = 0;
>
> +APR_HOOK_STRUCT(
> +                   APR_HOOK_LINK(setup_shared_info)
> +)
> +
> +AP_IMPLEMENT_HOOK_VOID(setup_shared_info,
> +                       (apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
> +                       (pconf,plog,s))
> +
>  #if APR_HAS_SHARED_MEMORY
>  #include "apr_shmem.h"
>  static apr_shmem_t *scoreboard_shm = NULL;
>
>


Re: [PATCH-concept] more dynamic configuration

Posted by Harrie Hazewinkel <ha...@lisanza.net>.
dean gaudet wrote:
> 
> On Fri, 6 Jul 2001, Harrie Hazewinkel wrote:
> 
> > Attached is a patch that adds more dynamic configuration.
> > It places some of the MPM variables such as 'ap_max_daemons_limit',
> > 'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free'
> > in the scoreboard.
> 
> -1.
> 
> the concept is ok, but the implementation sucks.
> 
> you've just allowed arbitrary code to do such broken things as set
> ap_daemons_min_free to be greater than ap_daemons_max_free... or lots of
> other brokenness.

Hmm, I see what you mean. In my case I expected that to be done
in the management module itself. For instance, SNMP needs to test
it first if it would be allowed to make the change before it is
allowed to change.

> 
> a more correct approach would be to call functions supplied by the MPM to
> modify those parameters.

I already thought that an interface towards these variables
would be better. On top of that protection against inconsistent
values is good as well.

> 
> assuming the MPM you're referring to even has such a parameter ;)

Of course, that should be protected by that interfce.



Harrie
-- 
address: Covalent Technologies, 645 Howard St, San Francisco, CA - 94105
phone: +1-415-536-5221                               fax:+1-415-536-5210
personal website: http://www.lisanza.net/

Re: [PATCH-concept] more dynamic configuration

Posted by dean gaudet <dg...@arctic.org>.
On Fri, 6 Jul 2001, Harrie Hazewinkel wrote:

> Attached is a patch that adds more dynamic configuration.
> It places some of the MPM variables such as 'ap_max_daemons_limit',
> 'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free'
> in the scoreboard.

-1.

the concept is ok, but the implementation sucks.

you've just allowed arbitrary code to do such broken things as set
ap_daemons_min_free to be greater than ap_daemons_max_free... or lots of
other brokenness.

a more correct approach would be to call functions supplied by the MPM to
modify those parameters.

assuming the MPM you're referring to even has such a parameter ;)

this would fall naturally out of the XML RPC-type scoreboard i was
suggesting a while back :)

-dean