package Apache2::BalanceLogic; use strict; use warnings; use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::Connection (); use APR::Table (); use Apache2::Const -compile => qw( OK DECLINED ); use YAML qw 'LoadFile'; use CGI::Cookie; use Net::CIDR::Lite; use UNIVERSAL::require; our $VERSION = '0.0.1'; our $conf; our $plugin; sub handler { my $r = shift; # load main config file. $conf ||= LoadFile( $r->dir_config('CONFIG_PATH') ) or die; # load plugin config file and generate plugin object. $plugin ||= do { my $p_conf = LoadFile( $conf->{Plugin}->{Config} ) or die; my $class = __PACKAGE__ . '::Plugin::' . $conf->{Plugin}->{Name}; $class->use or die $@; $class->new($p_conf); }; # run! my $route_id = $plugin->run($r); return Apache2::Const::DECLINED unless $route_id; # you can forward a request for a server apointed in '__force__' query string. my $args = $r->args; if ( $args =~ /__force__=(\d+)$/ ) { my $force = $1; my $ip = $r->connection->remote_ip; my $cidr = Net::CIDR::Lite->new; my $admin_ip = $conf->{ADMIN_IP} or die($!); for (@$admin_ip) { $cidr->add_any($_); } $route_id = $force if $cidr->find($ip); } # a inner cookie trick for "stickysession" in mod_proxy_balancer. my $cookie_str = $r->headers_in->get('Cookie'); $cookie_str =~ s/route_id=\d+\;?//; $cookie_str = 'route_id=x.' . $route_id . '; ' . $cookie_str . ';'; $r->headers_in->set( 'Cookie' => $cookie_str ); # return OK return Apache2::Const::OK; } 1; __END__ =head1 NAME Apache2::BalanceLogic - Perl extension for mod_proxy_balancer =head1 SYNOPSIS in httpd.conf PerlRequire /foo/bar/perl/startup.pl PerlHeaderParserHandler +Apache2::BalanceLogic perlSetVar CONFIG_PATH '/foo/bar/perl/Apache2/BalanceLogic/Config/MainConfig.yaml' and write for mod_proxy_balancer ProxyPass / balancer://TEST/ stickysession=route_id BalancerMember http://your.backend.server_01/ route=1 BalancerMember http://your.backend.server_02/ route=2 BalancerMember http://your.backend.server_03/ route=3 BalancerMember http://your.backend.server_04/ route=4 BalancerMember http://your.backend.server_05/ route=5 Applcation Config file ( MainConfig.yaml ) #--- select one Plugin module and config file Plugin: Name: 'DistByURL' Config: '/foo/bar/perl/Apache2/BalanceLogic/Config/PluginConfig/DistByURL.yaml' #--- #Name: 'DistByTime' #Config: '/foo/bar/perl/Apache2/BalanceLogic/Config/PluginConfig/DistByTime.yaml' #--- #Name: 'DistByCookie' #Config: '/foo/bar/perl/Apache2/BalanceLogic/Config/PluginConfig/DistByCookie.yaml' #--- your server admin ipaddress. it can use __force__ option. ADMIN_IP: - 192.168.1.0/24 =head1 DESCRIPTION This is a simple extention for 'mod_proxy_balancer'. You can put your original Plungin code that distribute the requests among the backend servers by your original algorithm. In other words, this is a "inner cookie trick" for stickysession in mod_proxy_balancer. Let's enjoy! =head1 Plugin There are 3 sample Plugin modules. ( in Plugin directory ) L distribute the requests by unique user cookie that maybe generated by usertrac module. this is implemented by a simple slurp division code. L distribute the requests by time number ( hour ). see config file. L by reqular expression on URL path string. =head1 SEE ALSO L =head1 AUTHOR Takeshi Miki =head1 COPYRIGHT AND LICENSE Copyright (C) 2007 Takeshi Miki This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available. =cut