ももクロのUstreamを見逃さないために書いたust_noticeが、いまのところ順調に機能していて自己満足に浸っているわけなんですが、さくらレンタルサーバの制約で監視のタイミングが2分間隔になってしまっていて、それが心のどこかで引っかかっていました。

このままだと月々500円を払う生活からも抜け出せないし、なんかウマイ方法はないものかと思ってたら、ありましたよその方法が。
ていうか、忘れてましたよdotcloudの存在を。

こういうときにも使えたんですね、こやつ。
ということで、dotcloudに設置してみましたっていうのとそのメモ。
使い方すっかり忘れてたし。

dotcloudのインストール方法とかは端折ります。

まずdotcloudにプロジェクトをつくって

$ dotcloud create ustnotice

ust_noticeをクローンします。

$ git clone git://github.com/utahta/ust_notice.git

クローンしたust_noticeに移動して、設定ファイルをいじくり、commitします

$ cd ust_notice
$ vi config.yml
ユーストAPIとかgmailのアカウントとか
$ git add -A
$ git commit -m 'update'

dotcloudにうpします。

$ dotcloud push ustnotice .

dotcloudに繋いで、cronの設定をします。

$ dotcloud ssh ustnotice.www
$ crontab -e
PATH=/usr/local/rvm/gems/ruby-1.9.2-p136@dotcloud/bin:/usr/local/rvm/gems/ruby-1.9.2-p136@global/bin:/usr/local/rvm/rubies/ruby-1.9.2-p136/bin:/usr/local/rvm/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/java-6-sun/bin
GEM_HOME=/usr/local/rvm/gems/ruby-1.9.2-p136@dotcloud
# m h  dom mon dow   command
* * * * * ruby /home/dotcloud/current/ust_notice.rb

こんなの無料で出来ちゃっていいんですかね。
ありがたいです。

 

GREEエンジニアブログのグリーの大規模分散ストレージ戦略(nanofs) Vol.2を見ていて、Apache の Request Counting ってなんぞやと思ったので、調べたメモ。

Request Counting アルゴリズムとは

Apache の mod_proxy_balancer モジュールに組み込まれているロードバランサのスケジューラアルゴリズムの1つ。

やってきたリクエストが、各ワーカーにちゃんと分担されるようにというか詳細は、こちら

リンク先に擬似コードが示されていたので、試しにいくつかの言語で実装してみた。

lbfactor が重み、lbstatus が優先度みたいなものっぽい。

Python

#!/usr/bin/env python
 
class Worker(object):
    def __init__(self, name, factor):
        self.name = name
        self.lbfactor = factor
        self.lbstatus = 0
        self.debug_count = 0
 
def request_counting(workers):
    """Request Counting Algorithm"""
    candidate = None
    total_factor = 0
 
    for worker in workers:
        worker.lbstatus += worker.lbfactor
        total_factor += worker.lbfactor
        if not candidate or worker.lbstatus > candidate.lbstatus:
            candidate = worker
 
    candidate.lbstatus -= total_factor
    return candidate
 
if __name__ == "__main__":
    workers = [Worker('A', 70), 
               Worker('B', 30)]
 
    for i in xrange(10):
        worker = request_counting(workers)
        print "(%s) %s" % (worker.name, ", ".join(["%3d" % w.lbstatus for w in workers]))
        worker.debug_count += 1
 
    for worker in workers:
        print "%s:%3d" % (worker.name, worker.debug_count)

Perl

#!/usr/bin/env perl
use strict;
use warnings;
 
{
    package Worker;
 
    sub new{
        my $pkg = shift;
        my %hash = (
            name => shift,
            lbfactor => shift,
            lbstatus => 0,
            debug_count => 0,
        );
        return bless \%hash, $pkg;
    }
}
 
package main;
 
sub request_counting{
    my $candidate = undef;
    my $total_factor = 0;
    my $workers = shift;
 
    foreach my $worker (@$workers){
        $worker->{lbstatus} += $worker->{lbfactor};
        $total_factor += $worker->{lbfactor};
        if(!defined($candidate) or $worker->{lbstatus} > $candidate->{lbstatus}){
            $candidate = $worker;
        }
    }
 
    $candidate->{lbstatus} -= $total_factor;
    return $candidate;
}
 
my @workers = (Worker->new('A', 70),
               Worker->new('B', 30));
 
for(my $i = 0; $i < 10; $i++){
    my $worker = request_counting(\@workers);
 
    my $debug_str = "";
    foreach my $tmp (@workers){
        $debug_str .= ($debug_str eq "") ? "" : ", ";
        $debug_str .= sprintf("%3d", $tmp->{lbstatus});
    }
    printf("(%s) %s\n", $worker->{name}, $debug_str);
    $worker->{debug_count}++;
}
 
foreach my $worker (@workers){
    printf("%s:%3d\n", $worker->{name}, $worker->{debug_count});
}

Ruby

#!/usr/bin/env ruby
 
class Worker
    def initialize(name, lbfactor)
        @name = name
        @lbfactor = lbfactor
        @lbstatus = 0
        @debug_count = 0
    end
 
    def get_name()
        return @name
    end
 
    def get_lbfactor()
        return @lbfactor
    end
 
    def add_lbstatus(lbstatus)
        @lbstatus += lbstatus
    end
    def sub_lbstatus(lbstatus)
        @lbstatus -= lbstatus
    end
    def get_lbstatus()
        return @lbstatus
    end
 
    def incl_debug_count()
        @debug_count += 1
    end
    def get_debug_count()
        return @debug_count
    end
end
 
def request_counting(workers)
    candidate = nil
    total_factor = 0
 
    for worker in workers:
        worker.add_lbstatus(worker.get_lbfactor)
        total_factor += worker.get_lbfactor
        if not candidate or worker.get_lbstatus > candidate.get_lbstatus:
            candidate = worker
        end
    end
 
    candidate.sub_lbstatus(total_factor)
    return candidate
end
 
workers = [Worker.new('A', 70),
           Worker.new('B', 30)]
 
for i in 1..10
    worker = request_counting(workers)
 
    debug_str = ""
    for tmp in workers
        debug_str += (debug_str == "") ? "" : ", "
        debug_str += sprintf("%3d", tmp.get_lbstatus)
    end
    printf("(%s) %s\n", worker.get_name, debug_str)
    worker.incl_debug_count
end
 
for worker in workers
    printf("%s:%3d\n", worker.get_name, worker.get_debug_count)
end

結果

(A) -30,  30
(B)  40, -40
(A)  10, -10
(A) -20,  20
(A) -50,  50
(B)  20, -20
(A) -10,  10
(A) -40,  40
(B)  30, -30
(A)   0,   0
A:  7
B:  3

ちゃんと重みに基づいて分散された。

いつか、バランシング処理を書く機会があったら、使ってみようかな。

 

ここ最近、まつもとゆきひろコードの世界 を読んでる。
それに載ってるサンプルを実践しようと tk 付き ruby のインストールを試みたらつまずいたのでメモ。

インストール

普通に MacPorts を使ってインストールを試みたところ、

$ sudo port install ruby +thread_hooks +mactk
...
/usr/bin/gcc-4.2 -dynamic -bundle -undefined suppress -flat_namespace -o ../../.ext/i686-darwin10/tcltklib.bundle stubs.o tcltklib.o -L. -L../.. -L. -L/opt/local/lib -framework Tk -framework Tcl  -arch x86_64  -lruby -lm -ldl  -lpthread -ldl -lobjc  
ld: in /opt/local/lib/libsqlite3.dylib, file is not of required architecture
collect2: ld returned 1 exit status
make[1]: *** [../../.ext/i686-darwin10/tcltklib.bundle] Error 1
make: *** [all] Error 1

失敗。
-arch x86_64 や file is not of required architecture があやしい。
アーキテクチャがどうのこうの。
調べたら標準の OS 10.6 は dynamic libraries が 64bit で動作しているんだとか。
Snow Leopard にアップデートしたことが原因っぽい。

いったん・・・

MacPorts でインストールしたライブラリなどを
全部アンインストール&リビルドすればいけるようだったので、

$ port installed
$ sudo port -f uninstall installed
...
$ port installed
No ports are installed.

何をインストールしてたか確認してから、キレイに全部アンインストール。

もう一度インストール

もう一度 ruby を最初からインストール。

$ sudo port install ruby +thread_hooks +mactk
...
--->  Installing ruby @1.8.7-p174_0+darwin+mactk+thread_hooks
--->  Activating ruby @1.8.7-p174_0+darwin+mactk+thread_hooks
--->  Cleaning ruby

無事成功した。
Leopard からの互換性を保ちつつ進化したように感じた Snow Leopard だったけど、
意外と対応してないアプリだとかしばらく弊害あるのかね。

参考

Snow Leopardにアップデートした後に気をつけること 主にMacPortsとrubygemsについて