You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Jim Jagielski <ji...@jaguNET.com> on 2017/06/01 12:55:30 UTC
Re: Ideas from ApacheCon
I really like where this is going... I just have a few questions:
1. The style, esp with array usage is different; eg APR_ARRAY_PUSH
and APR_ARRAY_IDX... any particular reason why?
2. I understand the logic behind creating the arrays, but doesn't
this increase the overhead. We go thru the full list of workers
one time, and then go thru the list of avail works and spares
right after that. Assume that all workers are available; doesn't
it mean we go thru that last 2x?
> On May 31, 2017, at 1:44 PM, Jim Riggs <ap...@riggs.me> wrote:
>
>> On 23 May 2017, at 09:16, Jim Riggs <ap...@riggs.me> wrote:
>>
>>> On 18 May 2017, at 13:22, Rainer Jung <ra...@kippdata.de> wrote:
>>>
>>> Am 18.05.2017 um 19:46 schrieb Jim Jagielski:
>>>> Based on feedback from various sessions:
>>>>
>>>> o A new-kind of "hot standby" in mod_proxy which kicks
>>>> in whenever a worker moves out of the pool (ie, doesn't
>>>> wait until all workers are out)... ala a redundant
>>>> hard drive.
>>>
>>> Maybe "spare worker" (and we could have more than one such spares).
>>
>> Exactly. I am already working on some code for this, though it to seems to necessarily be a bit convoluted in the current codebase.
>>
>> The way we treat a "hot standby" in mod_proxy_balancer is as a last-ditch effort to return something. I.e. *all* workers are unavailable, so then we use the hot standby. (This problem can actually be solved a different way by setting a high value for lbset.)
>>
>> In my mind, though, what is proposed here is actually how I actually expect a "hot standby" to work. Think of it more like a "hot spare" in disk RAID terms. That is, if *any* worker is unavailable, the hot spare will be used (or at least added to the list of potential workers...still to be determined by the lbmethod implementation).
>>
>> Example:
>>
>> <Proxy "balancer://mycluster">
>> BalancerMember "http://192.168.1.50:80"
>> BalancerMember "http://192.168.1.51:80"
>> BalancerMember "http://192.168.1.52:80"
>> BalancerMember "http://192.168.1.53:80" status=+H
>> </Proxy>
>>
>> In this case, .53 will only get used if .50, .51, and .52 are *all* unavailable.
>>
>> <Proxy "balancer://mycluster">
>> BalancerMember "http://192.168.1.50:80"
>> BalancerMember "http://192.168.1.51:80"
>> BalancerMember "http://192.168.1.52:80"
>> BalancerMember "http://192.168.1.53:80" status=+R # new "hot spare" status
>> BalancerMember "http://192.168.1.54:80" status=+R # new "hot spare" status
>> </Proxy>
>>
>> In this case, if .50 becomes unavailable, .53 (or .54 depending on implementation) will be treated as an available worker for the lbmethod to potentially choose. If 2 or more of .50, .51, and .52 become unavailable, both .53 and .54 would be available to be chosen.
>>
>> So, instead of having a single fallback option when *all* workers are dead, we will have a way of trying to ensure that a specific number of workers (3 in the example above) are always available...just like a hot spare drive plugs into the RAID array when one of the members dies. In our case, though, once the main worker recovers, the hot spare will go back to being a hot spare (except for matching routes).
>>
>> Comments welcome.
>
>
> As promised, balancer hot spare support: https://bz.apache.org/bugzilla/show_bug.cgi?id=61140
>
Implement hot spares in mod_proxy_balancer [was Re: Ideas from ApacheCon]
Posted by Jim Riggs <ap...@riggs.me>.
> On 1 Jun 2017, at 17:15, Yann Ylavic <yl...@gmail.com> wrote:
>
> On Thu, Jun 1, 2017 at 10:48 PM, Jim Riggs <ap...@riggs.me> wrote:
>>> On 1 Jun 2017, at 15:25, Yann Ylavic <yl...@gmail.com> wrote:
>>>
>>> On Thu, Jun 1, 2017 at 10:22 PM, Yann Ylavic <yl...@gmail.com>
>>> wrote:
>>>> On Thu, Jun 1, 2017 at 7:29 PM, Jim Riggs <ap...@riggs.me>
>>>> wrote:
>>>>>> On 1 Jun 2017, at 07:55, Jim Jagielski <ji...@jaguNET.com>
>>>>>> wrote: 2. I understand the logic behind creating the arrays,
>>>>>> but doesn't this increase the overhead. We go thru the full
>>>>>> list of workers one time, and then go thru the list of avail
>>>>>> works and spares right after that. Assume that all workers
>>>>>> are available; doesn't it mean we go thru that last 2x?
>>>> []
>>>>>
>>>>> The only way I can think of to avoid this without going back
>>>>> to duplicating code across lbmethods, which I would argue is
>>>>> worse, is to maybe have the lbmethod provide a callback
>>>>> function and context pointer to
>>>>> ap_proxy_balancer_usable_workers() that gets called during the
>>>>> loop iteration to pick the best member in flight.
>>>>
>>>> Couldn't a simple 'best' for ap_proxy_balancer_usable_workers()
>>>> make it return a single entry?
>>>
>>> ... a simple 'best' *flag* (as argument) ...
>>
>> I'm not sure I follow what this flag would be. The lbmethod would
>> somehow have to tell ap_proxy_balancer_usable_workers() how to pick
>> the best worker (e.g. by comparing the number of bytes sent or the
>> number of requests processed). I'm not sure how that information
>> could be passed as a flag unless we baked the behavior of byrequests,
>> bybusyness, and bytraffic into ap_proxy_balancer_usable_workers().
>> But then how would we allow for plugging in additional lbmethods?
>
> Oh right, nevermind, I thought per lbmethod logic was already there.
> After a better look into it, a callback (and its baton) with that
> logic looks straightforward, though.
Indeed. I put a new patch that uses callbacks on BZ61140 (and visually available at https://github.com/jhriggs/httpd/pull/1/files). So, the lbmethods call ap_proxy_balancer_get_best_worker() with a callback and baton so that the best worker is chosen in flight during iteration of the workers, addressing Jim's overhead concern. Changes:
- use a callback and baton to the lbmethod in
ap_proxy_balancer_get_best_worker() (previously
ap_proxy_balancer_usable_workers()) so that we can find the best worker in
flight while iterating rather than returning an array of usable workers that
has to then in turn be iterated
- consider a draining worker unusable and suitable for replacement by a spare
> Regarding:
> worker = &APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
> I don't see why worker needs to be a 'proxy_worker**' ('*worker' is
> never updated IIUC).
>
> Looks like:
> proxy_worker *worker = APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
> would be fine and allow using 'worker->xxx' instead of
> '(*worker)->xxx' all over the place...
Much of what I did was based on what already existed. The existing code was iterating through proxy_worker**, so mine did too. You are correct, though, that there is no real reason for it. The latest patch switches to just using * rather than **.
Thanks for putting eyes on this! I appreciate it.
Re: Ideas from ApacheCon
Posted by Yann Ylavic <yl...@gmail.com>.
On Thu, Jun 1, 2017 at 10:48 PM, Jim Riggs <ap...@riggs.me> wrote:
>> On 1 Jun 2017, at 15:25, Yann Ylavic <yl...@gmail.com> wrote:
>>
>> On Thu, Jun 1, 2017 at 10:22 PM, Yann Ylavic <yl...@gmail.com>
>> wrote:
>>> On Thu, Jun 1, 2017 at 7:29 PM, Jim Riggs <ap...@riggs.me>
>>> wrote:
>>>>> On 1 Jun 2017, at 07:55, Jim Jagielski <ji...@jaguNET.com>
>>>>> wrote: 2. I understand the logic behind creating the arrays,
>>>>> but doesn't this increase the overhead. We go thru the full
>>>>> list of workers one time, and then go thru the list of avail
>>>>> works and spares right after that. Assume that all workers
>>>>> are available; doesn't it mean we go thru that last 2x?
>>> []
>>>>
>>>> The only way I can think of to avoid this without going back
>>>> to duplicating code across lbmethods, which I would argue is
>>>> worse, is to maybe have the lbmethod provide a callback
>>>> function and context pointer to
>>>> ap_proxy_balancer_usable_workers() that gets called during the
>>>> loop iteration to pick the best member in flight.
>>>
>>> Couldn't a simple 'best' for ap_proxy_balancer_usable_workers()
>>> make it return a single entry?
>>
>> ... a simple 'best' *flag* (as argument) ...
>
> I'm not sure I follow what this flag would be. The lbmethod would
> somehow have to tell ap_proxy_balancer_usable_workers() how to pick
> the best worker (e.g. by comparing the number of bytes sent or the
> number of requests processed). I'm not sure how that information
> could be passed as a flag unless we baked the behavior of byrequests,
> bybusyness, and bytraffic into ap_proxy_balancer_usable_workers().
> But then how would we allow for plugging in additional lbmethods?
Oh right, nevermind, I thought per lbmethod logic was already there.
After a better look into it, a callback (and its baton) with that
logic looks straightforward, though.
Regarding:
worker = &APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
I don't see why worker needs to be a 'proxy_worker**' ('*worker' is
never updated IIUC).
Looks like:
proxy_worker *worker = APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
would be fine and allow using 'worker->xxx' instead of
'(*worker)->xxx' all over the place...
Regards,
Yann.
Re: Ideas from ApacheCon
Posted by Jim Riggs <ap...@riggs.me>.
> On 1 Jun 2017, at 15:25, Yann Ylavic <yl...@gmail.com> wrote:
>
> On Thu, Jun 1, 2017 at 10:22 PM, Yann Ylavic <yl...@gmail.com> wrote:
>> On Thu, Jun 1, 2017 at 7:29 PM, Jim Riggs <ap...@riggs.me> wrote:
>>>> On 1 Jun 2017, at 07:55, Jim Jagielski <ji...@jaguNET.com> wrote:
>>>> 2. I understand the logic behind creating the arrays, but doesn't
>>>> this increase the overhead. We go thru the full list of workers
>>>> one time, and then go thru the list of avail works and spares
>>>> right after that. Assume that all workers are available; doesn't
>>>> it mean we go thru that last 2x?
>> []
>>>
>>> The only way I can think of to avoid this without going back to
>>> duplicating code across lbmethods, which I would argue is worse, is
>>> to maybe have the lbmethod provide a callback function and context
>>> pointer to ap_proxy_balancer_usable_workers() that gets called during
>>> the loop iteration to pick the best member in flight.
>>
>> Couldn't a simple 'best' for ap_proxy_balancer_usable_workers() make
>> it return a single entry?
>
> ... a simple 'best' *flag* (as argument) ...
I'm not sure I follow what this flag would be. The lbmethod would somehow have to tell ap_proxy_balancer_usable_workers() how to pick the best worker (e.g. by comparing the number of bytes sent or the number of requests processed). I'm not sure how that information could be passed as a flag unless we baked the behavior of byrequests, bybusyness, and bytraffic into ap_proxy_balancer_usable_workers(). But then how would we allow for plugging in additional lbmethods?
>>
>> By the way, retrieving ap_proxy_retry_worker() via an OPTIONAL_FN
>> looks unnecessary since it's implemented in the exact same
>> "proxy_util.c" file.
LOL! That's a copy-paste remnant from when I had that function in a different file originally. Patch updated. Thanks for catching it!
Re: Ideas from ApacheCon
Posted by Yann Ylavic <yl...@gmail.com>.
On Thu, Jun 1, 2017 at 10:22 PM, Yann Ylavic <yl...@gmail.com> wrote:
> On Thu, Jun 1, 2017 at 7:29 PM, Jim Riggs <ap...@riggs.me> wrote:
>>> On 1 Jun 2017, at 07:55, Jim Jagielski <ji...@jaguNET.com> wrote:
>>>
>>> I really like where this is going... I just have a few questions:
>>>
>>> 1. The style, esp with array usage is different; eg APR_ARRAY_PUSH
>>> and APR_ARRAY_IDX... any particular reason why?
>>
>> Well, we don't seem to be entirely consistent with using elts and
>> apr_array*() directly vs. the helper #defines across the codebase. I
>> was doing everything with direct pointer access and arithmetic until
>> I started looking at the heartbeat lbmethod that was using some of
>> the helpers. IMNSHO, I think they are a little cleaner and easier
>> use/read. I got lost in dereferencing hell with all of the `&((*...)
>> **)->(*)'! :-) The helpers are there, and I think they are convenient
>> and worth using, but I'm not digging through all of this code as
>> regularly as some of the others on here. If the standard/consensus is
>> the other way, it's easy to change.
>
> I also (much, much) prefer the macros, and preferably would like all
> the 'elts' usages and cast trickeries changed to them rather. But
> that's another (own) story...
>
>>
>>
>>> 2. I understand the logic behind creating the arrays, but doesn't
>>> this increase the overhead. We go thru the full list of workers
>>> one time, and then go thru the list of avail works and spares
>>> right after that. Assume that all workers are available; doesn't
>>> it mean we go thru that last 2x?
> []
>>
>> The only way I can think of to avoid this without going back to
>> duplicating code across lbmethods, which I would argue is worse, is
>> to maybe have the lbmethod provide a callback function and context
>> pointer to ap_proxy_balancer_usable_workers() that gets called during
>> the loop iteration to pick the best member in flight.
>
> Couldn't a simple 'best' for ap_proxy_balancer_usable_workers() make
> it return a single entry?
... a simple 'best' *flag* (as argument) ...
>
> By the way, retrieving ap_proxy_retry_worker() via an OPTIONAL_FN
> looks unnecessary since it's implemented in the exact same
> "proxy_util.c" file.
>
>>
>> Regardless, even worst case, we are looking at what, iterating 6
>> pointers instead of 3 or 10 instead of 5? We probably have some lower
>> hanging fruit across the request lifecycle code to increase
>> performance than saving some arithmetic on a handful of structs, no?
>> ;-)
>
> Agreed.
Re: Ideas from ApacheCon
Posted by Yann Ylavic <yl...@gmail.com>.
On Thu, Jun 1, 2017 at 7:29 PM, Jim Riggs <ap...@riggs.me> wrote:
>> On 1 Jun 2017, at 07:55, Jim Jagielski <ji...@jaguNET.com> wrote:
>>
>> I really like where this is going... I just have a few questions:
>>
>> 1. The style, esp with array usage is different; eg APR_ARRAY_PUSH
>> and APR_ARRAY_IDX... any particular reason why?
>
> Well, we don't seem to be entirely consistent with using elts and
> apr_array*() directly vs. the helper #defines across the codebase. I
> was doing everything with direct pointer access and arithmetic until
> I started looking at the heartbeat lbmethod that was using some of
> the helpers. IMNSHO, I think they are a little cleaner and easier
> use/read. I got lost in dereferencing hell with all of the `&((*...)
> **)->(*)'! :-) The helpers are there, and I think they are convenient
> and worth using, but I'm not digging through all of this code as
> regularly as some of the others on here. If the standard/consensus is
> the other way, it's easy to change.
I also (much, much) prefer the macros, and preferably would like all
the 'elts' usages and cast trickeries changed to them rather. But
that's another (own) story...
>
>
>> 2. I understand the logic behind creating the arrays, but doesn't
>> this increase the overhead. We go thru the full list of workers
>> one time, and then go thru the list of avail works and spares
>> right after that. Assume that all workers are available; doesn't
>> it mean we go thru that last 2x?
[]
>
> The only way I can think of to avoid this without going back to
> duplicating code across lbmethods, which I would argue is worse, is
> to maybe have the lbmethod provide a callback function and context
> pointer to ap_proxy_balancer_usable_workers() that gets called during
> the loop iteration to pick the best member in flight.
Couldn't a simple 'best' for ap_proxy_balancer_usable_workers() make
it return a single entry?
By the way, retrieving ap_proxy_retry_worker() via an OPTIONAL_FN
looks unnecessary since it's implemented in the exact same
"proxy_util.c" file.
>
> Regardless, even worst case, we are looking at what, iterating 6
> pointers instead of 3 or 10 instead of 5? We probably have some lower
> hanging fruit across the request lifecycle code to increase
> performance than saving some arithmetic on a handful of structs, no?
> ;-)
Agreed.
Re: Ideas from ApacheCon
Posted by Jim Jagielski <ji...@jaguNET.com>.
> On Jun 1, 2017, at 1:29 PM, Jim Riggs <ap...@riggs.me> wrote:
>
>
> Regardless, even worst case, we are looking at what, iterating 6 pointers instead of 3 or 10 instead of 5? We probably have some lower hanging fruit across the request lifecycle code to increase performance than saving some arithmetic on a handful of structs, no? ;-)
>
Oh I agree... it just seems that we add overhead during the
normal and nominal case (everybody is up and available) and
that the overhead is worse the more workers we have. I am
personally OK with abnormal situations being slower....
And yeah, I also have never like the duplication that's inherent
in all the lbmethods, and so I really like it being simplified.
But I could never figure out a way to remove that without making
it more complex or slower. Last idea I had was to create some
sort of looping cpp MACRO to encapsulate it at some level :/
Re: Ideas from ApacheCon
Posted by Jim Jagielski <ji...@jaguNET.com>.
Will do! THX!
> On Jun 2, 2017, at 9:46 AM, Jim Riggs <ap...@riggs.me> wrote:
>
>> On 2 Jun 2017, at 07:20, Jim Jagielski <ji...@jaguNET.com> wrote:
>>
>>> On Jun 1, 2017, at 1:29 PM, Jim Riggs <ap...@riggs.me> wrote:
>>>
>>> Regardless, even worst case, we are looking at what, iterating 6 pointers instead of 3 or 10 instead of 5? We probably have some lower hanging fruit across the request lifecycle code to increase performance than saving some arithmetic on a handful of structs, no? ;-)
>>>
>>
>> Oh I agree... it just seems that we add overhead during the
>> normal and nominal case (everybody is up and available) and
>> that the overhead is worse the more workers we have. I am
>> personally OK with abnormal situations being slower....
>>
>> And yeah, I also have never like the duplication that's inherent
>> in all the lbmethods, and so I really like it being simplified.
>> But I could never figure out a way to remove that without making
>> it more complex or slower. Last idea I had was to create some
>> sort of looping cpp MACRO to encapsulate it at some level :/
>
> Yeah. Take a look at the callback version I submitted last night. It has reduced the code in the lbmethods to almost nothing. The find_best_*() functions just call ap_proxy_balancer_get_best_worker() with a small, quick callback function and then do a little housekeeping. Nothing else.
>
> BUT, this implementation makes it extremely flexible if someone want to create a complex lbmethod. It can do whatever special/custom things it wants to in its find_best_() function and/or in the is_best_() callback...or maybe it wants to implement its own iteration for finding usable workers and doesn't want to use ap_proxy_balancer_get_best_worker()'s logic at all. Just because the 3 existing lbmethods use that flow doesn't mean everything has to, but we removed a lot of duplicate code with a shared function for them (and future lbmethods?) to use. I think it's a big win for extensibility and simplification of the lbmethod interface.
>
Re: Ideas from ApacheCon
Posted by Jim Riggs <ap...@riggs.me>.
> On 2 Jun 2017, at 07:20, Jim Jagielski <ji...@jaguNET.com> wrote:
>
>> On Jun 1, 2017, at 1:29 PM, Jim Riggs <ap...@riggs.me> wrote:
>>
>> Regardless, even worst case, we are looking at what, iterating 6 pointers instead of 3 or 10 instead of 5? We probably have some lower hanging fruit across the request lifecycle code to increase performance than saving some arithmetic on a handful of structs, no? ;-)
>>
>
> Oh I agree... it just seems that we add overhead during the
> normal and nominal case (everybody is up and available) and
> that the overhead is worse the more workers we have. I am
> personally OK with abnormal situations being slower....
>
> And yeah, I also have never like the duplication that's inherent
> in all the lbmethods, and so I really like it being simplified.
> But I could never figure out a way to remove that without making
> it more complex or slower. Last idea I had was to create some
> sort of looping cpp MACRO to encapsulate it at some level :/
Yeah. Take a look at the callback version I submitted last night. It has reduced the code in the lbmethods to almost nothing. The find_best_*() functions just call ap_proxy_balancer_get_best_worker() with a small, quick callback function and then do a little housekeeping. Nothing else.
BUT, this implementation makes it extremely flexible if someone want to create a complex lbmethod. It can do whatever special/custom things it wants to in its find_best_() function and/or in the is_best_() callback...or maybe it wants to implement its own iteration for finding usable workers and doesn't want to use ap_proxy_balancer_get_best_worker()'s logic at all. Just because the 3 existing lbmethods use that flow doesn't mean everything has to, but we removed a lot of duplicate code with a shared function for them (and future lbmethods?) to use. I think it's a big win for extensibility and simplification of the lbmethod interface.
Re: Ideas from ApacheCon
Posted by Jim Jagielski <ji...@jaguNET.com>.
> On Jun 1, 2017, at 1:29 PM, Jim Riggs <ap...@riggs.me> wrote:
>
>
> Regardless, even worst case, we are looking at what, iterating 6 pointers instead of 3 or 10 instead of 5? We probably have some lower hanging fruit across the request lifecycle code to increase performance than saving some arithmetic on a handful of structs, no? ;-)
>
Oh I agree... it just seems that we add overhead during the
normal and nominal case (everybody is up and available) and
that the overhead is worse the more workers we have. I am
personally OK with abnormal situations being slower....
And yeah, I also have never like the duplication that's inherent
in all the lbmethods, and so I really like it being simplified.
But I could never figure out a way to remove that without making
it more complex or slower. Last idea I had was to create some
sort of looping cpp MACRO to encapsulate it at some level :/
Re: Ideas from ApacheCon
Posted by Jim Riggs <ap...@riggs.me>.
> On 1 Jun 2017, at 07:55, Jim Jagielski <ji...@jaguNET.com> wrote:
>
> I really like where this is going... I just have a few questions:
>
> 1. The style, esp with array usage is different; eg APR_ARRAY_PUSH
> and APR_ARRAY_IDX... any particular reason why?
Well, we don't seem to be entirely consistent with using elts and apr_array*() directly vs. the helper #defines across the codebase. I was doing everything with direct pointer access and arithmetic until I started looking at the heartbeat lbmethod that was using some of the helpers. IMNSHO, I think they are a little cleaner and easier use/read. I got lost in dereferencing hell with all of the `&((*...) **)->(*)'! :-) The helpers are there, and I think they are convenient and worth using, but I'm not digging through all of this code as regularly as some of the others on here. If the standard/consensus is the other way, it's easy to change.
> 2. I understand the logic behind creating the arrays, but doesn't
> this increase the overhead. We go thru the full list of workers
> one time, and then go thru the list of avail works and spares
> right after that. Assume that all workers are available; doesn't
> it mean we go thru that last 2x?
If everything is available, the old implementation only goes through the list once and picks a worker. This new implementation goes through the list once and returns a *subset* that the lbmethod then has to loop through to pick a worker. Worst case (e.g. X workers all available in lbset 0), yes, we would now do 2X.
In a more complex scenario (e.g. X workers all available in each lbsets 0, 1, and 2), we do 3X (1st loop) + X (2nd loop) = 4X, not 2 * 3X = 6X. So, yes, there is slightly more overhead...but, the second loop (in the lbmethod) has at most one lbset's worth of workers and really isn't doing anything except an arithmetic comparison to pick the best from them.
If a number of workers are unavailable, however, it's different. The old implementation loops the whole list twice per lbset if it doesn't find a worker, once for workers and once for standbys, whereas this new implementation still loops the whole list only once per lbset. In the example above, 2 * 3X = 6X for old, 3X + X = 4X for new.
The only way I can think of to avoid this without going back to duplicating code across lbmethods, which I would argue is worse, is to maybe have the lbmethod provide a callback function and context pointer to ap_proxy_balancer_usable_workers() that gets called during the loop iteration to pick the best member in flight. I am open to that...it just seemed to add unnecessary complexity.
Regardless, even worst case, we are looking at what, iterating 6 pointers instead of 3 or 10 instead of 5? We probably have some lower hanging fruit across the request lifecycle code to increase performance than saving some arithmetic on a handful of structs, no? ;-)
>> On May 31, 2017, at 1:44 PM, Jim Riggs <ap...@riggs.me> wrote:
>>
>>> On 23 May 2017, at 09:16, Jim Riggs <ap...@riggs.me> wrote:
>>>
>>>> On 18 May 2017, at 13:22, Rainer Jung <ra...@kippdata.de> wrote:
>>>>
>>>> Am 18.05.2017 um 19:46 schrieb Jim Jagielski:
>>>>> Based on feedback from various sessions:
>>>>>
>>>>> o A new-kind of "hot standby" in mod_proxy which kicks
>>>>> in whenever a worker moves out of the pool (ie, doesn't
>>>>> wait until all workers are out)... ala a redundant
>>>>> hard drive.
>>>>
>>>> Maybe "spare worker" (and we could have more than one such spares).
>>>
>>> Exactly. I am already working on some code for this, though it to seems to necessarily be a bit convoluted in the current codebase.
>>>
>>> The way we treat a "hot standby" in mod_proxy_balancer is as a last-ditch effort to return something. I.e. *all* workers are unavailable, so then we use the hot standby. (This problem can actually be solved a different way by setting a high value for lbset.)
>>>
>>> In my mind, though, what is proposed here is actually how I actually expect a "hot standby" to work. Think of it more like a "hot spare" in disk RAID terms. That is, if *any* worker is unavailable, the hot spare will be used (or at least added to the list of potential workers...still to be determined by the lbmethod implementation).
>>>
>>> Example:
>>>
>>> <Proxy "balancer://mycluster">
>>> BalancerMember "http://192.168.1.50:80"
>>> BalancerMember "http://192.168.1.51:80"
>>> BalancerMember "http://192.168.1.52:80"
>>> BalancerMember "http://192.168.1.53:80" status=+H
>>> </Proxy>
>>>
>>> In this case, .53 will only get used if .50, .51, and .52 are *all* unavailable.
>>>
>>> <Proxy "balancer://mycluster">
>>> BalancerMember "http://192.168.1.50:80"
>>> BalancerMember "http://192.168.1.51:80"
>>> BalancerMember "http://192.168.1.52:80"
>>> BalancerMember "http://192.168.1.53:80" status=+R # new "hot spare" status
>>> BalancerMember "http://192.168.1.54:80" status=+R # new "hot spare" status
>>> </Proxy>
>>>
>>> In this case, if .50 becomes unavailable, .53 (or .54 depending on implementation) will be treated as an available worker for the lbmethod to potentially choose. If 2 or more of .50, .51, and .52 become unavailable, both .53 and .54 would be available to be chosen.
>>>
>>> So, instead of having a single fallback option when *all* workers are dead, we will have a way of trying to ensure that a specific number of workers (3 in the example above) are always available...just like a hot spare drive plugs into the RAID array when one of the members dies. In our case, though, once the main worker recovers, the hot spare will go back to being a hot spare (except for matching routes).
>>>
>>> Comments welcome.
>>
>>
>> As promised, balancer hot spare support: https://bz.apache.org/bugzilla/show_bug.cgi?id=61140
>>
>