From: Jim Jagielski Date: Wed, 6 May 2009 13:48:54 +0000 (+0000) Subject: Add these in from trunk... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bbc0d504e547a66e2d4802d962c29be6a6e8059d;p=thirdparty%2Fapache%2Fhttpd.git Add these in from trunk... We can easily remove should we wish to maintain the 2.2 dev struct... git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/httpd-2.2-proxy@772263 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/proxy/balancers/.deps b/modules/proxy/balancers/.deps new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/proxy/balancers/Makefile.in b/modules/proxy/balancers/Makefile.in new file mode 100644 index 00000000000..7c5c149d852 --- /dev/null +++ b/modules/proxy/balancers/Makefile.in @@ -0,0 +1,3 @@ +# a modules Makefile has no explicit targets -- they will be defined by +# whatever modules are enabled. just grab special.mk to deal with this. +include $(top_srcdir)/build/special.mk diff --git a/modules/proxy/balancers/config2.m4 b/modules/proxy/balancers/config2.m4 new file mode 100644 index 00000000000..f7232661a84 --- /dev/null +++ b/modules/proxy/balancers/config2.m4 @@ -0,0 +1,8 @@ +APACHE_MODPATH_INIT(proxy/balancers) + +APACHE_MODULE(lbmethod_byrequests, Apache proxy Load balancing by request counting, , , $proxy_mods_enable) +APACHE_MODULE(lbmethod_bytraffic, Apache proxy Load balancing by traffic counting, , , $proxy_mods_enable) +APACHE_MODULE(lbmethod_bybusyness, Apache proxy Load balancing by busyness, , , $proxy_mods_enable) +APACHE_MODULE(lbmethod_heartbeat, Apache proxy Load balancing from Heartbeats, , , $proxy_mods_enable) + +APACHE_MODPATH_FINISH diff --git a/modules/proxy/balancers/mod_lbmethod_bybusyness.c b/modules/proxy/balancers/mod_lbmethod_bybusyness.c new file mode 100644 index 00000000000..1861084a5c4 --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_bybusyness.c @@ -0,0 +1,139 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mod_proxy.h" +#include "scoreboard.h" +#include "ap_mpm.h" +#include "apr_version.h" +#include "apr_hooks.h" + +module AP_MODULE_DECLARE_DATA lbmethod_bybusyness_module; + +static proxy_worker *find_best_bybusyness(proxy_balancer *balancer, + request_rec *r) +{ + + int i; + proxy_worker **worker; + proxy_worker *mycandidate = NULL; + int cur_lbset = 0; + int max_lbset = 0; + int checking_standby; + int checked_standby; + + int total_factor = 0; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: Entering bybusyness for BALANCER (%s)", + balancer->name); + + /* First try to see if we have available candidate */ + do { + + checking_standby = checked_standby = 0; + while (!mycandidate && !checked_standby) { + + worker = (proxy_worker **)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if (!checking_standby) { /* first time through */ + if ((*worker)->s->lbset > max_lbset) + max_lbset = (*worker)->s->lbset; + } + + if ((*worker)->s->lbset != cur_lbset) + continue; + + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker)) ) + continue; + + /* If the worker is in error state run + * retry on that worker. It will be marked as + * operational if the retry timeout is elapsed. + * The worker might still be unusable, but we try + * anyway. + */ + if (!PROXY_WORKER_IS_USABLE(*worker)) + ap_proxy_retry_worker("BALANCER", *worker, r->server); + + /* Take into calculation only the workers that are + * not in error state or not disabled. + */ + if (PROXY_WORKER_IS_USABLE(*worker)) { + + (*worker)->s->lbstatus += (*worker)->s->lbfactor; + total_factor += (*worker)->s->lbfactor; + + if (!mycandidate + || (*worker)->s->busy < mycandidate->s->busy + || ((*worker)->s->busy == mycandidate->s->busy && (*worker)->s->lbstatus > mycandidate->s->lbstatus)) + mycandidate = *worker; + + } + + } + + checked_standby = checking_standby++; + + } + + cur_lbset++; + + } while (cur_lbset <= max_lbset && !mycandidate); + + if (mycandidate) { + mycandidate->s->lbstatus -= total_factor; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: bybusyness selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d", + mycandidate->name, mycandidate->s->busy, mycandidate->s->lbstatus); + + } + + return mycandidate; + +} + +static apr_status_t reset(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +static apr_status_t age(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +static const proxy_balancer_method bybusyness = +{ + "bybusyness", + &find_best_bybusyness, + &reset, + &age, + NULL +}; + + +static void register_hook(apr_pool_t *p) +{ + ap_register_provider(p, PROXY_LBMETHOD, "bybusyness", "0", &bybusyness); +} + +module AP_MODULE_DECLARE_DATA lbmethod_bybusyness_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + NULL, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + NULL, /* command apr_table_t */ + register_hook /* register hooks */ +}; diff --git a/modules/proxy/balancers/mod_lbmethod_bybusyness.dsp b/modules/proxy/balancers/mod_lbmethod_bybusyness.dsp new file mode 100644 index 00000000000..8ba0da00efa --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_bybusyness.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="mod_lbmethod_bybusyness" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_lbmethod_bybusyness - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_bybusyness.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_bybusyness.mak" CFG="mod_lbmethod_bybusyness - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_lbmethod_bybusyness - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_lbmethod_bybusyness - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_lbmethod_bybusyness - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_lbmethod_bybusyness_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/mod_lbmethod_bybusyness.res" /i "../../../include" /i "../../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_lbmethod_bybusyness.so" /d LONG_NAME="lbmethod_bybusyness_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_lbmethod_bybusyness.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bybusyness.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_lbmethod_bybusyness.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bybusyness.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_lbmethod_bybusyness.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "mod_lbmethod_bybusyness - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_lbmethod_bybusyness_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/mod_lbmethod_bybusyness.res" /i "../../../include" /i "../../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_lbmethod_bybusyness.so" /d LONG_NAME="lbmethod_bybusyness_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_bybusyness.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bybusyness.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_bybusyness.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bybusyness.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_lbmethod_bybusyness.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "mod_lbmethod_bybusyness - Win32 Release" +# Name "mod_lbmethod_bybusyness - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\mod_lbmethod_bybusyness.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ".h" +# Begin Source File + +SOURCE=..\mod_proxy.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/proxy/balancers/mod_lbmethod_byrequests.c b/modules/proxy/balancers/mod_lbmethod_byrequests.c new file mode 100644 index 00000000000..a895d443710 --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_byrequests.c @@ -0,0 +1,175 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mod_proxy.h" +#include "scoreboard.h" +#include "ap_mpm.h" +#include "apr_version.h" +#include "apr_hooks.h" + +module AP_MODULE_DECLARE_DATA lbmethod_byrequests_module; + +/* + * The idea behind the find_best_byrequests scheduler is the following: + * + * lbfactor is "how much we expect this worker to work", or "the worker's + * normalized work quota". + * + * lbstatus is "how urgent this worker has to work to fulfill its quota + * of work". + * + * We distribute each worker's work quota to the worker, and then look + * which of them needs to work most urgently (biggest lbstatus). This + * worker is then selected for work, and its lbstatus reduced by the + * total work quota we distributed to all workers. Thus the sum of all + * lbstatus does not change.(*) + * + * If some workers are disabled, the others will + * still be scheduled correctly. + * + * If a balancer is configured as follows: + * + * worker a b c d + * lbfactor 25 25 25 25 + * + * And b gets disabled, the following schedule is produced: + * + * a c d a c d a c d ... + * + * Note that the above lbfactor setting is the *exact* same as: + * + * worker a b c d + * lbfactor 1 1 1 1 + * + * Asymmetric configurations work as one would expect. For + * example: + * + * worker a b c d + * lbfactor 1 1 1 2 + * + * would have a, b and c all handling about the same + * amount of load with d handling twice what a or b + * or c handles individually. So we could see: + * + * b a d c d a c d b d ... + * + */ + +static proxy_worker *find_best_byrequests(proxy_balancer *balancer, + request_rec *r) +{ + int i; + int total_factor = 0; + proxy_worker **worker; + proxy_worker *mycandidate = NULL; + int cur_lbset = 0; + int max_lbset = 0; + int checking_standby; + int checked_standby; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: Entering byrequests for BALANCER (%s)", + balancer->name); + + /* First try to see if we have available candidate */ + do { + checking_standby = checked_standby = 0; + while (!mycandidate && !checked_standby) { + worker = (proxy_worker **)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if (!checking_standby) { /* first time through */ + if ((*worker)->s->lbset > max_lbset) + max_lbset = (*worker)->s->lbset; + } + if ((*worker)->s->lbset != cur_lbset) + continue; + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker)) ) + continue; + /* If the worker is in error state run + * retry on that worker. It will be marked as + * operational if the retry timeout is elapsed. + * The worker might still be unusable, but we try + * anyway. + */ + if (!PROXY_WORKER_IS_USABLE(*worker)) + ap_proxy_retry_worker("BALANCER", *worker, r->server); + /* Take into calculation only the workers that are + * not in error state or not disabled. + */ + if (PROXY_WORKER_IS_USABLE(*worker)) { + (*worker)->s->lbstatus += (*worker)->s->lbfactor; + total_factor += (*worker)->s->lbfactor; + if (!mycandidate || (*worker)->s->lbstatus > mycandidate->s->lbstatus) + mycandidate = *worker; + } + } + checked_standby = checking_standby++; + } + cur_lbset++; + } while (cur_lbset <= max_lbset && !mycandidate); + + if (mycandidate) { + mycandidate->s->lbstatus -= total_factor; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: byrequests selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d", + mycandidate->name, mycandidate->s->busy, mycandidate->s->lbstatus); + + } + + return mycandidate; +} + +static apr_status_t reset(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +static apr_status_t age(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +/* + * How to add additional lbmethods: + * 1. Create func which determines "best" candidate worker + * (eg: find_best_bytraffic, above) + * 2. Register it as a provider. + */ +static const proxy_balancer_method byrequests = +{ + "byrequests", + &find_best_byrequests, + &reset, + &age, + NULL +}; + +static void register_hook(apr_pool_t *p) +{ + /* Only the mpm_winnt has child init hook handler. + * make sure that we are called after the mpm + * initializes and after the mod_proxy + */ + ap_register_provider(p, PROXY_LBMETHOD, "byrequests", "0", &byrequests); +} + +module AP_MODULE_DECLARE_DATA lbmethod_byrequests_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + NULL, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + NULL, /* command apr_table_t */ + register_hook /* register hooks */ +}; diff --git a/modules/proxy/balancers/mod_lbmethod_byrequests.dsp b/modules/proxy/balancers/mod_lbmethod_byrequests.dsp new file mode 100644 index 00000000000..1f7d138ef43 --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_byrequests.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="mod_lbmethod_byrequests" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_lbmethod_byrequests - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_byrequests.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_byrequests.mak" CFG="mod_lbmethod_byrequests - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_lbmethod_byrequests - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_lbmethod_byrequests - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_lbmethod_byrequests - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_lbmethod_byrequests_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/mod_lbmethod_byrequests.res" /i "../../../include" /i "../../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_lbmethod_byrequests.so" /d LONG_NAME="lbmethod_byrequests_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_lbmethod_byrequests.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_byrequests.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_lbmethod_byrequests.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_byrequests.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_lbmethod_byrequests.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "mod_lbmethod_byrequests - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_lbmethod_byrequests_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/mod_lbmethod_byrequests.res" /i "../../../include" /i "../../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_lbmethod_byrequests.so" /d LONG_NAME="lbmethod_byrequests_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_byrequests.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_byrequests.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_byrequests.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_byrequests.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_lbmethod_byrequests.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "mod_lbmethod_byrequests - Win32 Release" +# Name "mod_lbmethod_byrequests - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\mod_lbmethod_byrequests.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ".h" +# Begin Source File + +SOURCE=..\mod_proxy.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/proxy/balancers/mod_lbmethod_bytraffic.c b/modules/proxy/balancers/mod_lbmethod_bytraffic.c new file mode 100644 index 00000000000..2c231d0e33f --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_bytraffic.c @@ -0,0 +1,142 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mod_proxy.h" +#include "scoreboard.h" +#include "ap_mpm.h" +#include "apr_version.h" +#include "apr_hooks.h" + +module AP_MODULE_DECLARE_DATA lbmethod_bytraffic_module; + +/* + * The idea behind the find_best_bytraffic scheduler is the following: + * + * We know the amount of traffic (bytes in and out) handled by each + * worker. We normalize that traffic by each workers' weight. So assuming + * a setup as below: + * + * worker a b c + * lbfactor 1 1 3 + * + * the scheduler will allow worker c to handle 3 times the + * traffic of a and b. If each request/response results in the + * same amount of traffic, then c would be accessed 3 times as + * often as a or b. If, for example, a handled a request that + * resulted in a large i/o bytecount, then b and c would be + * chosen more often, to even things out. + */ +static proxy_worker *find_best_bytraffic(proxy_balancer *balancer, + request_rec *r) +{ + int i; + apr_off_t mytraffic = 0; + apr_off_t curmin = 0; + proxy_worker **worker; + proxy_worker *mycandidate = NULL; + int cur_lbset = 0; + int max_lbset = 0; + int checking_standby; + int checked_standby; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: Entering bytraffic for BALANCER (%s)", + balancer->name); + + /* First try to see if we have available candidate */ + do { + checking_standby = checked_standby = 0; + while (!mycandidate && !checked_standby) { + worker = (proxy_worker **)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if (!checking_standby) { /* first time through */ + if ((*worker)->s->lbset > max_lbset) + max_lbset = (*worker)->s->lbset; + } + if ((*worker)->s->lbset != cur_lbset) + continue; + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker)) ) + continue; + /* If the worker is in error state run + * retry on that worker. It will be marked as + * operational if the retry timeout is elapsed. + * The worker might still be unusable, but we try + * anyway. + */ + if (!PROXY_WORKER_IS_USABLE(*worker)) + ap_proxy_retry_worker("BALANCER", *worker, r->server); + /* Take into calculation only the workers that are + * not in error state or not disabled. + */ + if (PROXY_WORKER_IS_USABLE(*worker)) { + mytraffic = ((*worker)->s->transferred/(*worker)->s->lbfactor) + + ((*worker)->s->read/(*worker)->s->lbfactor); + if (!mycandidate || mytraffic < curmin) { + mycandidate = *worker; + curmin = mytraffic; + } + } + } + checked_standby = checking_standby++; + } + cur_lbset++; + } while (cur_lbset <= max_lbset && !mycandidate); + + if (mycandidate) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: bytraffic selected worker \"%s\" : busy %" APR_SIZE_T_FMT, + mycandidate->name, mycandidate->s->busy); + + } + + return mycandidate; +} + +static apr_status_t reset(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +static apr_status_t age(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +static const proxy_balancer_method bytraffic = +{ + "bytraffic", + &find_best_bytraffic, + &reset, + &age, + NULL +}; + +static void register_hook(apr_pool_t *p) +{ + /* Only the mpm_winnt has child init hook handler. + * make sure that we are called after the mpm + * initializes and after the mod_proxy + */ + ap_register_provider(p, PROXY_LBMETHOD, "bytraffic", "0", &bytraffic); +} + +module AP_MODULE_DECLARE_DATA lbmethod_bytraffic_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + NULL, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + NULL, /* command apr_table_t */ + register_hook /* register hooks */ +}; diff --git a/modules/proxy/balancers/mod_lbmethod_bytraffic.dsp b/modules/proxy/balancers/mod_lbmethod_bytraffic.dsp new file mode 100644 index 00000000000..647c4b8f3a1 --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_bytraffic.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="mod_lbmethod_bytraffic" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_lbmethod_bytraffic - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_bytraffic.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_bytraffic.mak" CFG="mod_lbmethod_bytraffic - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_lbmethod_bytraffic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_lbmethod_bytraffic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_lbmethod_bytraffic - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_lbmethod_bytraffic_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/mod_lbmethod_bytraffic.res" /i "../../../include" /i "../../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_lbmethod_bytraffic.so" /d LONG_NAME="lbmethod_bytraffic_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_lbmethod_bytraffic.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bytraffic.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_lbmethod_bytraffic.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bytraffic.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_lbmethod_bytraffic.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "mod_lbmethod_bytraffic - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_lbmethod_bytraffic_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/mod_lbmethod_bytraffic.res" /i "../../../include" /i "../../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_lbmethod_bytraffic.so" /d LONG_NAME="lbmethod_bytraffic_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_bytraffic.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bytraffic.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_bytraffic.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_bytraffic.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_lbmethod_bytraffic.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "mod_lbmethod_bytraffic - Win32 Release" +# Name "mod_lbmethod_bytraffic - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\mod_lbmethod_bytraffic.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ".h" +# Begin Source File + +SOURCE=..\mod_proxy.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/proxy/balancers/mod_lbmethod_heartbeat.c b/modules/proxy/balancers/mod_lbmethod_heartbeat.c new file mode 100644 index 00000000000..914c367bb21 --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_heartbeat.c @@ -0,0 +1,382 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mod_proxy.h" +#include "scoreboard.h" +#include "ap_mpm.h" +#include "apr_version.h" +#include "apr_hooks.h" + +#ifndef LBM_HEARTBEAT_MAX_LASTSEEN +/* If we haven't seen a heartbeat in the last N seconds, don't count this IP + * as allive. + */ +#define LBM_HEARTBEAT_MAX_LASTSEEN (10) +#endif + +module AP_MODULE_DECLARE_DATA lbmethod_heartbeat_module; + +typedef struct lb_hb_ctx_t +{ + const char *path; +} lb_hb_ctx_t; + +typedef struct hb_server_t { + const char *ip; + int busy; + int ready; + int seen; + proxy_worker *worker; +} hb_server_t; + +static void +argstr_to_table(apr_pool_t *p, char *str, apr_table_t *parms) +{ + char *key; + char *value; + char *strtok_state; + + key = apr_strtok(str, "&", &strtok_state); + while (key) { + value = strchr(key, '='); + if (value) { + *value = '\0'; /* Split the string in two */ + value++; /* Skip passed the = */ + } + else { + value = "1"; + } + ap_unescape_url(key); + ap_unescape_url(value); + apr_table_set(parms, key, value); + /* + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Found query arg: %s = %s", key, value); + */ + key = apr_strtok(NULL, "&", &strtok_state); + } +} + +static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers, + apr_pool_t *pool) +{ + apr_finfo_t fi; + apr_status_t rv; + apr_file_t *fp; + + if (!path) { + return APR_SUCCESS; + } + + rv = apr_file_open(&fp, path, APR_READ|APR_BINARY|APR_BUFFERED, + APR_OS_DEFAULT, pool); + + if (rv) { + return rv; + } + + rv = apr_file_info_get(&fi, APR_FINFO_SIZE, fp); + + if (rv) { + return rv; + } + + { + char *t; + int lineno = 0; + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(pool); + apr_bucket_brigade *bb = apr_brigade_create(pool, ba); + apr_bucket_brigade *tmpbb = apr_brigade_create(pool, ba); + apr_table_t *hbt = apr_table_make(pool, 10); + + apr_brigade_insert_file(bb, fp, 0, fi.size, pool); + + do { + hb_server_t *server; + char buf[4096]; + apr_size_t bsize = sizeof(buf); + const char *ip; + + apr_brigade_cleanup(tmpbb); + + if (APR_BRIGADE_EMPTY(bb)) { + break; + } + + rv = apr_brigade_split_line(tmpbb, bb, + APR_BLOCK_READ, sizeof(buf)); + lineno++; + + if (rv) { + return rv; + } + + apr_brigade_flatten(tmpbb, buf, &bsize); + + if (bsize == 0) { + break; + } + + buf[bsize - 1] = 0; + + /* comment */ + if (buf[0] == '#') { + continue; + } + + /* line format: \n */ + t = strchr(buf, ' '); + if (!t) { + continue; + } + + ip = apr_pstrndup(pool, buf, t - buf); + t++; + + server = apr_hash_get(servers, ip, APR_HASH_KEY_STRING); + + if (server == NULL) { + server = apr_pcalloc(pool, sizeof(hb_server_t)); + server->ip = ip; + server->seen = -1; + + apr_hash_set(servers, server->ip, APR_HASH_KEY_STRING, server); + } + + apr_table_clear(hbt); + + argstr_to_table(pool, apr_pstrdup(pool, t), hbt); + + if (apr_table_get(hbt, "busy")) { + server->busy = atoi(apr_table_get(hbt, "busy")); + } + + if (apr_table_get(hbt, "ready")) { + server->ready = atoi(apr_table_get(hbt, "ready")); + } + + if (apr_table_get(hbt, "lastseen")) { + server->seen = atoi(apr_table_get(hbt, "lastseen")); + } + + if (server->busy == 0 && server->ready != 0) { + /* Server has zero threads active, but lots of them ready, + * it likely just started up, so lets /4 the number ready, + * to prevent us from completely flooding it with all new + * requests. + */ + server->ready = server->ready / 4; + } + + } while (1); + } + + return APR_SUCCESS; +} + +/* + * Finding a random number in a range. + * n' = a + n(b-a+1)/(M+1) + * where: + * n' = random number in range + * a = low end of range + * b = high end of range + * n = random number of 0..M + * M = maxint + * Algorithm 'borrowed' from PHP's rand() function. + */ +#define RAND_RANGE(__n, __min, __max, __tmax) \ +(__n) = (__min) + (long) ((double) ((__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0))) + +static apr_status_t random_pick(apr_uint32_t *number, + apr_uint32_t min, + apr_uint32_t max) +{ + apr_status_t rv = + apr_generate_random_bytes((void*)number, sizeof(apr_uint32_t)); + + if (rv) { + return rv; + } + + RAND_RANGE(*number, min, max, APR_UINT32_MAX); + + return APR_SUCCESS; +} + +static proxy_worker *find_best_hb(proxy_balancer *balancer, + request_rec *r) +{ + apr_status_t rv; + int i; + apr_uint32_t openslots = 0; + proxy_worker **worker; + hb_server_t *server; + apr_array_header_t *up_servers; + proxy_worker *mycandidate = NULL; + apr_pool_t *tpool; + apr_hash_t *servers; + + lb_hb_ctx_t *ctx = + ap_get_module_config(r->server->module_config, + &lbmethod_heartbeat_module); + + apr_pool_create(&tpool, r->pool); + + servers = apr_hash_make(tpool); + + rv = read_heartbeats(ctx->path, servers, tpool); + + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "lb_heartbeat: Unable to read heartbeats at '%s'", + ctx->path); + apr_pool_destroy(tpool); + return NULL; + } + + up_servers = apr_array_make(tpool, apr_hash_count(servers), sizeof(hb_server_t *)); + + for (i = 0; i < balancer->workers->nelts; i++) { + worker = &APR_ARRAY_IDX(balancer->workers, i, proxy_worker *); + server = apr_hash_get(servers, (*worker)->hostname, APR_HASH_KEY_STRING); + + if (!server) { + continue; + } + + if (!PROXY_WORKER_IS_USABLE(*worker)) { + ap_proxy_retry_worker("BALANCER", *worker, r->server); + } + + if (PROXY_WORKER_IS_USABLE(*worker)) { + server->worker = *worker; + if (server->seen < LBM_HEARTBEAT_MAX_LASTSEEN) { + openslots += server->ready; + APR_ARRAY_PUSH(up_servers, hb_server_t *) = server; + } + } + } + + if (openslots > 0) { + apr_uint32_t c = 0; + apr_uint32_t pick = 0;; + + rv = random_pick(&pick, 0, openslots); + + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "lb_heartbeat: failed picking a random number. how random."); + apr_pool_destroy(tpool); + return NULL; + } + + for (i = 0; i < up_servers->nelts; i++) { + server = APR_ARRAY_IDX(up_servers, i, hb_server_t *); + if (pick > c && pick <= c + server->ready) { + mycandidate = server->worker; + } + + c += server->ready; + } + } + + apr_pool_destroy(tpool); + + return mycandidate; +} + +static apr_status_t reset(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +static apr_status_t age(proxy_balancer *balancer, request_rec *r) { + return APR_SUCCESS; +} + +static const proxy_balancer_method heartbeat = +{ + "heartbeat", + &find_best_hb, + &reset, + &age, + NULL +}; + +static void register_hooks(apr_pool_t *p) +{ + ap_register_provider(p, PROXY_LBMETHOD, "heartbeat", "0", &heartbeat); +} + +static void *lb_hb_create_config(apr_pool_t *p, server_rec *s) +{ + lb_hb_ctx_t *ctx = (lb_hb_ctx_t *) apr_palloc(p, sizeof(lb_hb_ctx_t)); + + ctx->path = ap_server_root_relative(p, "logs/hb.dat"); + + return ctx; +} + +static void *lb_hb_merge_config(apr_pool_t *p, void *basev, void *overridesv) +{ + lb_hb_ctx_t *ps = apr_pcalloc(p, sizeof(lb_hb_ctx_t)); + lb_hb_ctx_t *base = (lb_hb_ctx_t *) basev; + lb_hb_ctx_t *overrides = (lb_hb_ctx_t *) overridesv; + + if (overrides->path) { + ps->path = apr_pstrdup(p, overrides->path); + } + else { + ps->path = apr_pstrdup(p, base->path); + } + + return ps; +} + +static const char *cmd_lb_hb_storage(cmd_parms *cmd, + void *dconf, const char *path) +{ + apr_pool_t *p = cmd->pool; + lb_hb_ctx_t *ctx = + (lb_hb_ctx_t *) ap_get_module_config(cmd->server->module_config, + &lbmethod_heartbeat_module); + + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + ctx->path = ap_server_root_relative(p, path); + + return NULL; +} + +static const command_rec cmds[] = { + AP_INIT_TAKE1("HeartbeatStorage", cmd_lb_hb_storage, NULL, RSRC_CONF, + "Path to read heartbeat data."), + {NULL} +}; + +module AP_MODULE_DECLARE_DATA lbmethod_heartbeat_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + lb_hb_create_config, /* create per-server config structure */ + lb_hb_merge_config, /* merge per-server config structures */ + cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; diff --git a/modules/proxy/balancers/mod_lbmethod_heartbeat.dsp b/modules/proxy/balancers/mod_lbmethod_heartbeat.dsp new file mode 100644 index 00000000000..fbafed74d11 --- /dev/null +++ b/modules/proxy/balancers/mod_lbmethod_heartbeat.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="mod_lbmethod_heartbeat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_lbmethod_heartbeat - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_heartbeat.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_heartbeat.mak" CFG="mod_lbmethod_heartbeat - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_lbmethod_heartbeat - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_lbmethod_heartbeat - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_lbmethod_heartbeat - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_lbmethod_heartbeat_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/mod_lbmethod_heartbeat.res" /i "../../../include" /i "../../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_lbmethod_heartbeat.so" /d LONG_NAME="lbmethod_heartbeat_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_lbmethod_heartbeat.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_heartbeat.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_lbmethod_heartbeat.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_heartbeat.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_lbmethod_heartbeat.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "mod_lbmethod_heartbeat - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_lbmethod_heartbeat_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/mod_lbmethod_heartbeat.res" /i "../../../include" /i "../../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_lbmethod_heartbeat.so" /d LONG_NAME="lbmethod_heartbeat_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_heartbeat.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_heartbeat.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_heartbeat.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_heartbeat.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_lbmethod_heartbeat.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "mod_lbmethod_heartbeat - Win32 Release" +# Name "mod_lbmethod_heartbeat - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\mod_lbmethod_heartbeat.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ".h" +# Begin Source File + +SOURCE=..\mod_proxy.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/proxy/balancers/modules.mk b/modules/proxy/balancers/modules.mk new file mode 100644 index 00000000000..bad51c14bf2 --- /dev/null +++ b/modules/proxy/balancers/modules.mk @@ -0,0 +1,11 @@ +libmod_lbmethod_byrequests.la: mod_lbmethod_byrequests.lo + $(MOD_LINK) mod_lbmethod_byrequests.lo $(MOD_LBMETHOD_BYREQUESTS_LDADD) +libmod_lbmethod_bytraffic.la: mod_lbmethod_bytraffic.lo + $(MOD_LINK) mod_lbmethod_bytraffic.lo $(MOD_LBMETHOD_BYTRAFFIC_LDADD) +libmod_lbmethod_bybusyness.la: mod_lbmethod_bybusyness.lo + $(MOD_LINK) mod_lbmethod_bybusyness.lo $(MOD_LBMETHOD_BYBUSYNESS_LDADD) +libmod_lbmethod_heartbeat.la: mod_lbmethod_heartbeat.lo + $(MOD_LINK) mod_lbmethod_heartbeat.lo $(MOD_LBMETHOD_HEARTBEAT_LDADD) +DISTCLEAN_TARGETS = modules.mk +static = libmod_lbmethod_byrequests.la libmod_lbmethod_bytraffic.la libmod_lbmethod_bybusyness.la libmod_lbmethod_heartbeat.la +shared = diff --git a/modules/proxy/examples/mod_lbmethod_rr.c b/modules/proxy/examples/mod_lbmethod_rr.c new file mode 100644 index 00000000000..775f2c45e6c --- /dev/null +++ b/modules/proxy/examples/mod_lbmethod_rr.c @@ -0,0 +1,119 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Round Robin lbmethod EXAMPLE module for Apache proxy */ + +/* NOTE: This is designed simply to provide some info on how to create + extra lbmethods via sub-modules... This code is ugly + and needs work to actually do round-robin "right" + but that is left as an exercise for the reader */ + +#include "mod_proxy.h" +#include "scoreboard.h" +#include "ap_mpm.h" +#include "apr_version.h" +#include "apr_hooks.h" + +#if APR_HAVE_UNISTD_H +#include /* for getpid() */ +#endif + +module AP_MODULE_DECLARE_DATA proxy_balancer_rr_module; + +typedef struct { + int index; +} rr_data ; + +/* + */ +static proxy_worker *find_best_roundrobin(proxy_balancer *balancer, + request_rec *r) +{ + int i; + proxy_worker **worker; + proxy_worker *mycandidate = NULL; + int checking_standby; + int checked_standby; + rr_data *ctx; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: Entering roundrobin for BALANCER %s (%d)", + balancer->name, (int)getpid()); + + /* The index of the candidate last chosen is stored in ctx->index */ + if (!balancer->context) { + /* UGLY */ + ctx = apr_pcalloc(r->server->process->pconf, sizeof(rr_data)); + balancer->context = (void *)ctx; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: Creating roundrobin ctx for BALANCER %s (%d)", + balancer->name, (int)getpid()); + } else { + ctx = (rr_data *)balancer->context; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: roundrobin index: %d (%d)", + ctx->index, (int)getpid()); + + checking_standby = checked_standby = 0; + while (!mycandidate && !checked_standby) { + worker = (proxy_worker **)balancer->workers->elts; + + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if (i < ctx->index) + continue; + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker)) ) + continue; + if (!PROXY_WORKER_IS_USABLE(*worker)) + ap_proxy_retry_worker("BALANCER", *worker, r->server); + if (PROXY_WORKER_IS_USABLE(*worker)) { + mycandidate = *worker; + break; + } + } + checked_standby = checking_standby++; + } + + + ctx->index += 1; + if (ctx->index >= balancer->workers->nelts) { + ctx->index = 0; + } + return mycandidate; +} + +static const proxy_balancer_method roundrobin = +{ + "roundrobin", + &find_best_roundrobin, + NULL +}; + + +static void ap_proxy_rr_register_hook(apr_pool_t *p) +{ + ap_register_provider(p, PROXY_LBMETHOD, "roundrobin", "0", &roundrobin); +} + +module AP_MODULE_DECLARE_DATA proxy_balancer_rr_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + NULL, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + NULL, /* command apr_table_t */ + ap_proxy_rr_register_hook /* register hooks */ +}; diff --git a/modules/proxy/examples/mod_lbmethod_rr.dsp b/modules/proxy/examples/mod_lbmethod_rr.dsp new file mode 100644 index 00000000000..96f29dba7dd --- /dev/null +++ b/modules/proxy/examples/mod_lbmethod_rr.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="mod_lbmethod_rr" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_lbmethod_rr - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_rr.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_lbmethod_rr.mak" CFG="mod_lbmethod_rr - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_lbmethod_rr - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_lbmethod_rr - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_lbmethod_rr - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_lbmethod_rr_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/mod_lbmethod_rr.res" /i "../../../include" /i "../../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_lbmethod_rr.so" /d LONG_NAME="lbmethod_rr_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_lbmethod_rr.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_rr.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_lbmethod_rr.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_rr.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_lbmethod_rr.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "mod_lbmethod_rr - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I ".." /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_lbmethod_rr_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/mod_lbmethod_rr.res" /i "../../../include" /i "../../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_lbmethod_rr.so" /d LONG_NAME="lbmethod_rr_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_rr.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_rr.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lbmethod_rr.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_lbmethod_rr.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_lbmethod_rr.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "mod_lbmethod_rr - Win32 Release" +# Name "mod_lbmethod_rr - Win32 Debug" +# Begin Source File + +SOURCE=.\mod_lbmethod_rr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project