taiyoh's memorandum

@ttaiyoh が、技術ネタで気づいたことを書き溜めておきます。

有限オートマトンの習作として

PerlFSM::Simpleというモジュールを書いてみた。

#!perl -w
use strict;
use warnings;
use FSM::Simple;

my $count = 0;

my $fsm = FSM::Simple->new({
    rules => {
        init => sub {
            my $state = shift;
            if ($count < 20) {
                $state->next('add');
            }
            else {
                $state->next('end');
            }
        },
        add => sub {
            ++$count;
            shift->next('init');
        }
    }
});

$fsm->register(end => sub { $count *= 5; });

$fsm->run;

print "${count}\n"; # => 100

Perl Automata
ここを参考にしながら書きました。
ソースはこっちにあります。
taiyoh/p5-FSM-Simple · GitHub

(追記:9/3)
同僚からtransaction guardはちゃんと実装した方がいいと言われたので、
インターフェイスを大幅変更。
contextオブジェクトを内部で持つようにして、それで値を取り回すように。
あとはon_entry/on_exit/on_transactionも入れた。
stateのコードとtransaction guardを分けてみたらFSA::Rulesに近くなった。

use FSM::Simple;

my $fsm = FSM::Simple->new({
    on_enter      => sub {
        my $context = shift;
        $context->{count} = 0;
        $context->{str}   = "foo";
    },
    on_transition => sub { shift->{str} .= "bar" },
    on_exit       => sub { shift->{str} .= "baz" }
});

$fsm->register(init => sub {}, [
    add => sub { shift->{count} < 20 },
    end => sub { shift->{count} >= 20 }
]);

$fsm->register(add => sub { ++shift->{count} }, [
    init => 1
]);

$fsm->register(end => sub { shift->{count} *= 5 });

$fsm->run;

print $fsm->context->{count}, # => 100

Sub::Deferredなんてモジュール書いてみた

 最近、全然ブログ書いてないな、と思ったのですが、よくよく考えると、今年に入ってコード全然書いてなかったわけで、こりゃちょっといかん、と思いまして。
 リハビリついでに、jQuery1.7の$.Deferredの機能をなるべくほぼそのままPerlに移植してみました。完全じゃないけど。
 → taiyoh/p5-Sub-Deferred · GitHub
 これを使うと、

#!perl

use strict;
use warnings;
use utf8;

use FindBin;
use Perl6::Say;

use Sub::Deferred;
use AnyEvent;

my $cv = AE::cv;
my @defs = map { Sub::Deferred->new } 1 .. 3;
my $when = Sub::Deferred->when(@defs);
my $foo = 2;
my @timers = map {
    my $def = $_;
    my $sec = int(rand 5) + 1;
    AE::timer $sec, 0, sub {
        say "$sec sec after";
        $foo *= 2;
        $def->resolve;
    };
} @defs;
$when->done(sub {
    $foo *= 3;
    $cv->send($foo);
});

say "result: ". $cv->recv; # => 48

 こんな感じで、「あれ、なんかjQueryで見たことある書き方」みたいなことができるようになります。CPANにはObject::Deferredとかいうモジュールもあるのですが、機能が少ない上にそれのためにMoose使うってなんじゃ、と思ったもので。
 一応依存モジュールもなく Pure Perlで、5.8.8以降で動くはずですが、真っ当な方はData::Monadを応援するか、Coroを使いこなす方がいいと思います!

Test_myqld.phpを更新しました

以前のエントリ→ "Test_mysqld", ported from cpan's Test::mysqld - taiyoh独言
taiyoh/Test_mysqld-php · GitHub
このモジュールを作ってまもなく、id:memememomoさんに色々直していただいたのですが、

例外でプログラムが終了しないように気をつけるようにするのはそうなんですが、テスト中のプログラムではやっぱ例外で終了しちゃうケースもある気がするのです。そのたびに、mysqldが残っちゃうのはやだなーと思うのです。

確実にmysqldを終了させる方法があるのでしょうか?

[php]Test_mysqldというものができたけど、まだ問題があって悩んでいる件 - メメメモモ

というのを今更ながらに見つけまして><
あんまりいい解決策じゃないかもしれませんが、子プロセスのPIDを定数としてキープしておいて、register_shutdown_functionでサクッと該当するPIDを落とすようにしてみました。

<?php

// モジュール読み込み
include_once('Test_mysqld.php');

// 設定
$my_cnf = array('skip-networking' => '');
$opts   = array();

// mysqld起動
$mysqld = new Test_mysqld($my_cnf, $opts);

// 例外で終わる
throw new Exception();

上記コードで子プロセスがなくなっていることは確認しました。微妙に終わり方はアレなのですが。
あと、気づいたらテストコードがセグフォで落ちるようになってた。。。上のコードは問題ないのですが。。。

(追記)
PDOでなんか起きてた。うむむ。。。

はてな x DeNA合同企画 Mobage 運用技術勉強会に行ってきた

 はてなの方からメールにて招待いただき(ありがとうございます!)、折角だからと体調悪い上に台風近づいてるにも関わらず昨日行って来ました。
 口外するな、と書かれていたので、相当やばい情報も話してくれるのか、とか、「活発に」リクルーターが話しかけにきてくれたりするのか、とか、妙な妄想たっぷりで臨んだのですが、その辺は見事に裏切られ、発表内容は「Mobageを支える技術」にほぼ含まれていて、リクルートエージェントについては、基本裏方にいるだけで、最後にアンケート書くだけで終わってしまいました。なんか残念。

 以下、発表内容のメモ(他の方の方がより詳しいかも。。。)

Mobage 運用技術 Web編

  • speaker: 樋口さん
  • Mobageのサーバ群構成について
    • 基本的にLAMP
    • HTTPサーバ(Apache)とFastCGIアプリのプロセスが同期
      • UNIX domain socket
      • ゲームごとに変えたりしていない。一枚岩
  • Webサーバ機の資源管理について
    • FastCGIワーカー数の管理
      • メモリ量がまたはCPU使用率がネック
        • ほぼPerlだけど、ちょっとだけC
        • ソフトウェア起因のネックはない
        • 1枚岩アプリなので、メモリ使用量が1GB超える
      • メモリ使用量がネック
        • サーバ1台あたり〜100プロセス程度
        • FastCGIワーカープロセス数は、CPUコア数の2〜3倍は必要
        • ワーカー数が不測すると、リクエストを捌き切れない
        • 多ければ多いほど耐障害性が高まる
          • バックエンドのDBなどが詰まった時に影響を受けにくくなる
          • でも、増やしすぎるとメモリ不足
    • デバッガを使った状況モニタリング
      • ワーカープロセスがいくつ空いてるか
        • あと何%余裕あるか
        • 走っているプロセスにデバッガをアタッチする
        • スタックトレースを取り、すぐにデタッチ
        • 前プロセスのスタックトレースを一定周期で取得
        • HTTPDFastCGIプロセスが対象
        • リクエスト受付状態にあるプロセスが「空き」
      • bulkdbgというツールを作った。gdb遅い
        • 5秒おきにhttpdFastCGIの前プロセスのスタックトレースを取得、ログに出力
        • オーバーヘッドほぼなし
        • acceptでブロックしているワーカーの数が減ってきたら枯渇が近い
          • メールで警告
    • 障害調査の手法
      • Perlスタックトレースと言っても、gdbで見れるのはCのもの
      • Perlコードのどこを実行中なのか知りたい
        • gdbperl.plを作った(これ、去年のYAPCのだ)
        • Perlデバッグシンボル付きでコンパイルされていないと動かないけど。。。
        • よくやること
          • gdbperl.plをアタッチ
          • straceをアタッチ
          • bolkdbgを使ったモニタリング
          • NYTProfでプロファイルデータ取得
          • DBアクセス等のログ
  • メモリ利用効率化のための取り組み
    • 使用するPerlモジュールがなるべく独立しているようなサーバグループに分ける
    • 他に
      • Perlモジュールプリロード
      • OSページキャッシュ利用の効率化
    • 昔: forkされたワーカープロセスがPerlをexecしてモジュールを読む
    • 今: アプリのモジュールを読み込んだあとにワーカープロセスをforkしリクエスト処理
    • 今の方式へは時間をかけて慎重に移行
      • forkのタイミングでsocket等を開いたままだと問題を起こす
      • 処理の実行順序が変わることによる影響もあった
      • 移行後、メモリ使用量が半分になった
    • アプリが吐くログファイルがキャッシュされてしまう
      • メモリ足りないと1日1回のログ改修のタイミングでswapする
    • posix_fadvise(POSIX_FADV_DONTNEED)
      • これを10秒に1回、ログファイルをposix_fadviseするdaemonを動かす
        • ログがキャッシュに乗らなくなり、swapもしなくなった

Mobage 運用技術 DB編

  • speaker: 岩永さん(りーおさん)
  • Many Servers
    • スケールアウト:レプリケーション
    • スレーブへの情報の遅延が起こりうるので、クリティカルな情報へのselectはmasterへ
    • シャーディング
      • 1つのデータベースに入りきらないデータを分散して登録
        • 負荷分散
        • joinするSQLは書けない
        • DeNAはjoinなるべくかかない
      • レコード単位でのシャーディング
        • クライアント側でどのレコードがどこにあるかを保持する必要がある
      • 2で割るとか4で割るとかの方法は段々数が増えるからよくない
      • memcachedやアプリのメモリに、そのマッピングテーブルを保持する
    • auto increment
      • レコード単位でのシャーディングとなると問題になる
      • ソレ用にMyISAMのDBを用意して、そこから発番
        • DeNAレベルで問題になってない
    • マルチインスタンス
      • mysqldを1マシンに複数上げる
      • マシン上に仮想IPを用意して、my.cnfのbind-addressをそれぞれ指定
    • バックアップ
      • 通常のスレーブではあるが、リクエストは来ない
        • アクティブスタンバイ
        • バックアップのダンプを流し込めばすぐにslaveができる
    • MHA
      • マスターが落ちた時にバックアップを昇格させる
  • Big Data
    • Purge
      • 古いデータを消す
    • データが増えると劣化する
    • 性能を維持するには、レコード数をある程度にする
    • 5.1時代はDELETEするしかない
      • でないと運用に支障がでる
      • 5.1移行はすぐできる
        • range partition
  • High Traffic
    • range scanには気をつけろとよく言ってる
    • なるべくPrimary Keyで引っ張る
      • それなんてhandler socket
    • memcachedとmysqlでデータのストアが2層になる
      • memcachedへのデータ更新。。。
      • なので、Handler Socketでmemcached使わずに済む
    • 5.6ではmemcached APIがサポートされた
    • update は色々ネック
      • ちょっとしたことがネックになる
        • SIN?
    • マスターサーバに対する更新の場合、デッドロックが起こりうる
    • Optimistic Lock
    • レプリケーションの遅延の測り方
      • バックアップサーバの遅延をモニタリングする
      • SSD
        • slaveはかなりの量がSSD
        • レプリ遅延が少ない
      • SATA-SSDが今のところ一番リーズナブル


 懇親会(但し酒はない)の時にりーおさんと話す機会があったのですが、特にDB周りについては、あまり独自のことはせずに、MySQL自体のバージョンアップに任せるとか、MySQLの仕様をきっちり理解した上でアプリで本当にやりたいことを曲げずに、基本に忠実なチューニングで対処できるようにするか、という辺りに気を配っている印象でした。また、樋口さんともお話させていただいて、去年のYAPC::Asiaの発表見てました!と伝えられたのがよかった。あの発表はこういうところに使われていたんですね。
 にしても、テーブルを囲んで話してる中で、DeNAのT部さんが「Perl使ってる人ー」と言って手を上げたのが自分だけだった。。。

nginxでステータスコード404,500,503時に特定の静的なファイルを表示する

 というメモ。

    server {
        listen       80;
        server_name  example.com;

        root /path/to/docroot;
        access_log  logs/example.access.log  main;

        location ~ ^/(js/|img/|css/|swf/) {
            index  index.html index.htm;
        }

        error_page 404  /404.html;
        error_page 500  /500.html;
        error_page 503  /503.html;

        location ~ /(404|503|500).html {
        }

        location / {
            proxy_intercept_errors on;
            proxy_set_header       Host $host;
            proxy_pass   http://127.0.0.1:5000;
        }
    }

 ミソは"proxy_intercept_errors"で、アプリケーションのレスポンスから特定のエラーコードを検知した時、システムではなくnginx側で所定の表示内容を出力するというフラグを立てる。

mac osxにmroongaをインストールしてみる

 承前として、osxにはmysqlとgroongaはインストールされているものとする(どちらもbrew installできますね!)

$ wget https://github.com/downloads/mroonga/mroonga/mroonga-1.11.tar.gz
$ wget http://downloads.mysql.com/archives/mysql-5.5/mysql-5.5.14.tar.gz
$ tar xvzf mysql-5.5.14.tar.gz
$ tar xvzf mroonga-1.11.tar.gz
$ mv mysql-5.5.14 /usr/local/mysql
$ cd mroonga-1.1
$ CPPFLAGS="-DDISABLE_DTRACE" ./configure --with-mysql-source=/usr/local/mysql
$ make
$ make install

 インストール完了後、mysqlのコンソールに入り

INSTALL PLUGIN groonga SONAME 'ha_groonga.so';
CREATE FUNCTION last_insert_grn_id RETURNS INTEGER soname 'ha_groonga.so';

 これでひとまず完了。
 ミソなのはconfigureの時のCPPFLAGSで、これ付けないとmake時に「probes_mysql_dtrace.hがない」と言われてしまう><(確かにファイルがない)。そのファイルを探すのが億劫だったので、もうフラグ変えることで対処。

「モチベーション3.0」読了

モチベーション3.0 持続する「やる気!」をいかに引き出すか
モチベーション3.0 持続する「やる気!」をいかに引き出すかダニエル・ピンク 大前 研一

講談社 2010-07-07
売り上げランキング : 783


Amazonで詳しく見る
by G-Tools

 昼間、bookoffに行ったら950円で売られていて、しかも三が日は半額になるらしく、500円弱でゲットできた。
 個人的に、リーダーとして重要な業務の一つにチームメンバーのモチベーション管理があると思っているので、今知りたかったことについてある程度知れたのがよかった。以前から感覚的に捉えている部分はあったが、それだけでは気づかなかった部分があったり、事例を踏まえた科学的な裏付けを含んでいて、もっと体系的に書かれていたので、だいぶ整理できた。
 これを読みながら、何人かの知り合いに、これの「タイプX」に当てはまってしまってる人がいるなぁ、と、ぼんやり思ったりしていた(会社のメンバーではないよ)。ホントは知的産業にいるはずの人が、時間労働的な尺度でしか自分の価値基準や給与基準を考えられてないとか。あと、昔「フラット化する世界」を読んで、将来的にオフショアリングがガンガン進んでいくと思っていたけど、ザッポスのように、ワントップでなるべく完結させることでブランドトータルの価値を高めつつ、(かつて「モチベーション2.0」的な職業だった職種の)働く人の自己実現にも寄与する「ホームショアリング」といった考え方が進んできてるのを見て、なんか色々始まってきてるな、とも思った。