読者です 読者をやめる 読者になる 読者になる

HTTP::Async で XML-RPC

perl

仕事で結構な数のサーバスペックを管理してるんだけど、こいつらの情報収集が結構大変。

サーバに仕込んだXMLRPCなAPIに対して、管理サーバのアプリを大量にfork->並列リクエストしてるんだけど、消費メモリが尋常じゃない。こんな無駄使いは環境に宜しくない。つか管理サーバがOOMで死む。

そんな訳で、HTTP::Asyncを使って書き直してみた。
こいつはすげーぜ!早い!軽い!省エネ!

#!/usr/bin/perl

use strict;
use warnings;

use XMLRPC::Lite;
use HTTP::Async;
use HTTP::Request;
use HTTP::Headers;
use JSON::Syck;
use YAML::Syck;

my $ua = LWP::UserAgent->new;
my $async = HTTP::Async->new;
my $serializer   = XMLRPC::Serializer->new;
my $deserializer = XMLRPC::Deserializer->new;
my $xml = $serializer->envelope(method => 'spec', qw/machine memory os kernel/);
my $header = HTTP::Headers->new->header(
    "Content-Type" => 'text/xml',
);

my $hosts = LoadFile(shift);

my %req;
for my $host (@$hosts) {
    my $id = $async->add( xmlrpc_req($host) );
    $req{$id}->{hostname} = $host;
}

while ( my ($res, $id) = $async->wait_for_next_response ) {
    if ($res->is_success) {
        my $som = eval { $deserializer->deserialize($res->content) };
        if ($@) {
            warn $@;
        } else {
            printf "%s :\t%s\n", $req{$id}->{hostname}, JSON::Syck::Dump($som->result);
        }
    } else {
        warn $res->status_line;
    }
}

sub xmlrpc_req {
    my $host = shift;
    return HTTP::Request->new(
        POST => "http://$host/rpc",
        $header,
        $xml,
    );
}

実際は取ってきた情報はDBにぶちこんだり、webで表示したりしとる。

ちなみに今まではこんな感じでやってた。

use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new($num);

for my $host (@hosts) {
    $pm->start and next;
    my $som = XMLRPC::Lite
        ->proxy("http://$host/rpc")
        ->call('spec', qw/machine memory os kernel/);

     # hogehoge

    $pm->finish;
}

$pm->wait_all_children;

ベンチ取ってないけど、取るまでもなく全くパフォーマンスが違う。