| 1 | package Apache2::BalanceLogic; |
|---|
| 2 | |
|---|
| 3 | use strict; |
|---|
| 4 | use warnings; |
|---|
| 5 | use Apache2::RequestRec (); |
|---|
| 6 | use Apache2::RequestIO (); |
|---|
| 7 | use Apache2::Connection (); |
|---|
| 8 | use APR::Table (); |
|---|
| 9 | use Apache2::Const -compile => qw( OK DECLINED ); |
|---|
| 10 | use YAML qw 'LoadFile'; |
|---|
| 11 | use CGI::Cookie; |
|---|
| 12 | use Net::CIDR::Lite; |
|---|
| 13 | use UNIVERSAL::require; |
|---|
| 14 | |
|---|
| 15 | our $VERSION = '0.0.1'; |
|---|
| 16 | |
|---|
| 17 | our $conf; |
|---|
| 18 | our $plugin; |
|---|
| 19 | |
|---|
| 20 | sub handler { |
|---|
| 21 | |
|---|
| 22 | my $r = shift; |
|---|
| 23 | |
|---|
| 24 | # load main config file. |
|---|
| 25 | $conf ||= LoadFile( $r->dir_config('CONFIG_PATH') ) or die; |
|---|
| 26 | |
|---|
| 27 | # load plugin config file and generate plugin object. |
|---|
| 28 | $plugin ||= do { |
|---|
| 29 | my $p_conf = LoadFile( $conf->{Plugin}->{Config} ) or die; |
|---|
| 30 | my $class = __PACKAGE__ . '::Plugin::' . $conf->{Plugin}->{Name}; |
|---|
| 31 | $class->use or die $@; |
|---|
| 32 | $class->new($p_conf); |
|---|
| 33 | }; |
|---|
| 34 | |
|---|
| 35 | # run! |
|---|
| 36 | my $route_id = $plugin->run($r); |
|---|
| 37 | return Apache2::Const::DECLINED unless $route_id; |
|---|
| 38 | |
|---|
| 39 | # you can forward a request for a server apointed in '__force__' query string. |
|---|
| 40 | my $args = $r->args; |
|---|
| 41 | if ( $args =~ /__force__=(\d+)$/ ) { |
|---|
| 42 | my $force = $1; |
|---|
| 43 | my $ip = $r->connection->remote_ip; |
|---|
| 44 | my $cidr = Net::CIDR::Lite->new; |
|---|
| 45 | my $admin_ip = $conf->{ADMIN_IP} or die($!); |
|---|
| 46 | for (@$admin_ip) { |
|---|
| 47 | $cidr->add_any($_); |
|---|
| 48 | } |
|---|
| 49 | $route_id = $force if $cidr->find($ip); |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | # a inner cookie trick for "stickysession" in mod_proxy_balancer. |
|---|
| 53 | my $cookie_str = $r->headers_in->get('Cookie'); |
|---|
| 54 | $cookie_str =~ s/route_id=\d+\;?//; |
|---|
| 55 | $cookie_str = 'route_id=x.' . $route_id . '; ' . $cookie_str . ';'; |
|---|
| 56 | $r->headers_in->set( 'Cookie' => $cookie_str ); |
|---|
| 57 | |
|---|
| 58 | # return OK |
|---|
| 59 | return Apache2::Const::OK; |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | 1; |
|---|
| 63 | |
|---|
| 64 | __END__ |
|---|
| 65 | |
|---|
| 66 | =head1 NAME |
|---|
| 67 | |
|---|
| 68 | Apache2::BalanceLogic - Perl extension for mod_proxy_balancer |
|---|
| 69 | |
|---|
| 70 | =head1 SYNOPSIS |
|---|
| 71 | |
|---|
| 72 | in httpd.conf |
|---|
| 73 | |
|---|
| 74 | PerlRequire /foo/bar/perl/startup.pl |
|---|
| 75 | PerlHeaderParserHandler +Apache2::BalanceLogic |
|---|
| 76 | perlSetVar CONFIG_PATH '/foo/bar/perl/Apache2/BalanceLogic/Config/MainConfig.yaml' |
|---|
| 77 | |
|---|
| 78 | and write for mod_proxy_balancer |
|---|
| 79 | |
|---|
| 80 | ProxyPass / balancer://TEST/ stickysession=route_id |
|---|
| 81 | <Proxy balancer://TEST/> |
|---|
| 82 | BalancerMember http://your.backend.server_01/ route=1 |
|---|
| 83 | BalancerMember http://your.backend.server_02/ route=2 |
|---|
| 84 | BalancerMember http://your.backend.server_03/ route=3 |
|---|
| 85 | BalancerMember http://your.backend.server_04/ route=4 |
|---|
| 86 | BalancerMember http://your.backend.server_05/ route=5 |
|---|
| 87 | </Proxy> |
|---|
| 88 | |
|---|
| 89 | Applcation Config file ( MainConfig.yaml ) |
|---|
| 90 | |
|---|
| 91 | #--- select one Plugin module and config file |
|---|
| 92 | Plugin: |
|---|
| 93 | Name: 'DistByURL' |
|---|
| 94 | Config: '/foo/bar/perl/Apache2/BalanceLogic/Config/PluginConfig/DistByURL.yaml' |
|---|
| 95 | #--- |
|---|
| 96 | #Name: 'DistByTime' |
|---|
| 97 | #Config: '/foo/bar/perl/Apache2/BalanceLogic/Config/PluginConfig/DistByTime.yaml' |
|---|
| 98 | #--- |
|---|
| 99 | #Name: 'DistByCookie' |
|---|
| 100 | #Config: '/foo/bar/perl/Apache2/BalanceLogic/Config/PluginConfig/DistByCookie.yaml' |
|---|
| 101 | #--- your server admin ipaddress. it can use __force__ option. |
|---|
| 102 | ADMIN_IP: |
|---|
| 103 | - 192.168.1.0/24 |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | =head1 DESCRIPTION |
|---|
| 107 | |
|---|
| 108 | This is a simple extention for 'mod_proxy_balancer'. |
|---|
| 109 | You can put your original Plungin code that distribute the requests among the backend servers by your original algorithm. |
|---|
| 110 | In other words, this is a "inner cookie trick" for stickysession in mod_proxy_balancer. |
|---|
| 111 | Let's enjoy! |
|---|
| 112 | |
|---|
| 113 | =head1 Plugin |
|---|
| 114 | |
|---|
| 115 | There are 3 sample Plugin modules. ( in Plugin directory ) |
|---|
| 116 | |
|---|
| 117 | L<Apache2::BalanceLogic::Plugin::DistByCookie> |
|---|
| 118 | distribute the requests by unique user cookie that maybe generated by usertrac module. |
|---|
| 119 | this is implemented by a simple slurp division code. |
|---|
| 120 | L<Apache2::BalanceLogic::Plugin::DistByTime> |
|---|
| 121 | distribute the requests by time number ( hour ). see config file. |
|---|
| 122 | L<Apache2::BalanceLogic::Plugin::DistByURL> |
|---|
| 123 | by reqular expression on URL path string. |
|---|
| 124 | |
|---|
| 125 | |
|---|
| 126 | =head1 SEE ALSO |
|---|
| 127 | |
|---|
| 128 | L<mod_perl> |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | =head1 AUTHOR |
|---|
| 132 | |
|---|
| 133 | Takeshi Miki <miki@cpan.org> |
|---|
| 134 | |
|---|
| 135 | =head1 COPYRIGHT AND LICENSE |
|---|
| 136 | |
|---|
| 137 | Copyright (C) 2007 Takeshi Miki |
|---|
| 138 | |
|---|
| 139 | This library is free software; you can redistribute it and/or modify |
|---|
| 140 | it under the same terms as Perl itself, either Perl version 5.8.8 or, |
|---|
| 141 | at your option, any later version of Perl 5 you may have available. |
|---|
| 142 | |
|---|
| 143 | =cut |
|---|