воскресенье, 24 апреля 2011 г.

семафор для пары серверов

Допустим, некий интернет-проект работает на паре независимых серверов у разных провайдеров с разными доменными именами, на одном из которых (медленном - slow) в корне через .htaccess идет редирект на второй (быстрый - fast).  [Именно так, к слову, обстоит дело с нашим теннисным клубом где fast  -  tennismatchmachine.com , а slow - motivation.ru .] Медленный каждые три часа забирает с быстрого снимок БД и заливает у себя. Каким образом, в случае отказа fast-сервера, slow-сервер надежно узнает об этом и отменит редирект? И как, когда потом восстановит его обратно? Решаем задачу:

A. На трех хостах, включая fast, кладем незамысловатый скриптик reply_self:

#!/usr/bin/perl

use CGI;
$query      = new CGI;
print $query->header;
my $me=`/bin/hostname`;
$chop($me);
my $addr=$ENV{'REMOTE_ADDR'};
print $me."!";
print $addr."\n";



B. А на slow каждую минутe запускаем нечто вроде :

#!/usr/bin/perl

my $tainted = 0;

my $tested_host = 'tennismatchmachine.com';
$test_host_url = 'http://'.$tested_host.'/scripts/reply_self';
my $first_link_ip = 'onnnemoreee.ru';
my $first_link_test_url = 'http://'.$first_link_ip.'/protected/reply_self';
my $second_link_ip = 'anotttheer.ru';
my $second_link_test_url = 'http://'.$second_link_ip.'/scripts/reply_self';

my $user = 'wget';
my $passwd = 'dumbasspassword';

local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required

&Connect(0);


unless ($tainted) {
    
    &Connect(1);
    unless ($tainted) {
        &Connect(2);
        unless ($tainted) {
            sleep(30);
            &Connect(0);
        }

    } else {
        sleep(30);
        &Connect(0);    
    }
}


if (!(-f './tmm_flag_down') && $tainted && $tainted ne '3') {
system("echo > ./tmm_flag_down");
system("date >> ./tmm_changed");
system("echo 'DOWN' >> ./tmm_changed");
system("echo '==============' >> ./tmm_changed");
system("./if_mail_tmm_changed.sh");
system("/bin/rm -f ./public_html/.htaccess");
system("cd public_html;/bin/ln -s ./.htaccess.home ./.htaccess;cd ..;");
} elsif (-f './tmm_flag_down' && $tainted eq '3') {
system("/bin/rm -f ./tmm_flag_down");
system("date >> ./tmm_changed");
system("echo 'UP' >> ./tmm_changed");
system("echo '==============' >> ./tmm_changed");
system("./if_mail_tmm_changed.sh");
system("/bin/rm -f ./public_html/.htaccess");
system("cd public_html;/bin/ln -s ./.htaccess.tmm ./.htaccess;cd ..;");
}


sub Connect {
my $p = shift;
my $test_url;

if ($p eq '0') {
    $test_url = $test_host_url;
} elsif ($p eq '1') {
    $test_url = $first_link_test_url;
} elsif ($p eq '2') {
    $test_url = $second_link_test_url;
}
 
my $wget_cmd = 'wget --timeout=5 --http-user '.$user.' --http-passwd '.$passwd.' -O - '.$test_url;
eval {
    
alarm 5;
system($wget_cmd.' 2>/dev/null 1>/dev/null');
open (IN, '-|', $wget_cmd.' 2>&1')
    or die ("Can't wget");

my $r = '';

   while (!eof(IN)) {
    my $q = readline (*IN);

        $q =~ /(\S+)!(\d+\.\d+\.\d+\.\d+)/;
    
    if ($1 && $r ne $1) {

        $r = $1;
        $tainted = ($1 =~ /^tennismatchmachine/) ? 3 : 4;
        last if ($tainted eq '3');
    
    }
   }

close (IN);

alarm 0;
};
} #end Connect

Voila!