use strict;
use APR::Table ();
use Apache2::Const -compile => qw( OK DECLINED );
use YAML qw 'LoadFile';
use CGI::Cookie;
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
</Proxy>
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<Apache2::BalanceLogic::Plugin::DistByCookie>
distribute the requests by unique user cookie that maybe generated by usertrac module.
this is implemented by a simple slurp division code.
L<Apache2::BalanceLogic::Plugin::DistByTime>
distribute the requests by time number ( hour ). see config file.
L<Apache2::BalanceLogic::Plugin::DistByURL>
by reqular expression on URL path string.
=head1 SEE ALSO
L<mod_perl>
=head1 AUTHOR
Takeshi Miki <miki@cpan.org>
=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