<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10japanesefull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
    <title>blog.nomadscafe.jp</title>
    <link rel="alternate" type="text/html" href="http://blog.nomadscafe.jp/" />
    
    <id>tag:blog.nomadscafe.jp,2009-07-12://1</id>
    <updated>2012-01-15T14:51:25Z</updated>
    <subtitle>湘南新宿ラインで通勤する Operations Engineer のBlog</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.27-ja</generator>

<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/nomadscafejp" /><feedburner:info uri="nomadscafejp" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><logo>http://feeds.feedburner.jp/~fc/nomadscafejp?bg=99CCFF&amp;fg=444444&amp;anim=0</logo><entry>
    <title>hb qp bp study 新年LT&amp;ビアバッシュ2012に参加してビール飲んでピザ食べてきた</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/V3OYELX7QfM/hb-qp-bp-study-lt2012.html" />
    <id>tag:blog.nomadscafe.jp,2012://1.159</id>

    <published>2012-01-15T14:44:58Z</published>
    <updated>2012-01-15T14:51:25Z</updated>

    <summary><![CDATA[hb qp bp study 新年LT&amp;ビアバッシュ2012に参加して発...]]></summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p><a href="https://connpass.com/event/213/">hb qp bp study 新年LT&amp;ビアバッシュ2012</a>に参加して発表してきました。</p>

<p>資料はこちら</p>

<div style="width:425px" id="__ss_11057661"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/kazeburo/operation-11057661" title="捗れ！Operation" target="_blank">捗れ！Operation</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/11057661" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe> <div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/kazeburo" target="_blank">Masahiro Nagano</a> </div> </div>

<p>内容は今年の目標と俺俺waresの紹介です。</p>

<p>ビール飲んでピザ食べて、面白いLT聞けて、みなさん大人でとても良い会でした。</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2012/01/hb-qp-bp-study-lt2012.html</feedburner:origLink></entry>

<entry>
    <title>Plack::Middleware::ReverseProxy でリモートホストを確認する理由</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/72JVzYbaevA/plackmiddlewarereverseproxy.html" />
    <id>tag:blog.nomadscafe.jp,2012://1.158</id>

    <published>2012-01-06T07:44:09Z</published>
    <updated>2012-01-06T07:49:58Z</updated>

    <summary>Reverse Proxyの後ろでApplication Serverを動かす際...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>Reverse Proxyの後ろでApplication Serverを動かす際に、REMOTE_HOSTを本当のアクセス元に書き換えてくれる仕組みはいくつかありますが^1、Plackでは壇上氏の <a href="http://search.cpan.org/~danjou/Plack-Middleware-ReverseProxy/lib/Plack/Middleware/ReverseProxy.pm">Plack::Middleware::ReverseProxy</a> がそれにあたります。</p>

<blockquote>
  <p>^1 例えば mod_extract_forwarded <a href="http://www.openinfo.co.uk/apache/">http://www.openinfo.co.uk/apache/</a></p>
</blockquote>

<p>PM::ReverseProxy のSYNOPSISでもそうなってますが、このような仕組みを使う場合、REMOTE_HOSTを指定するのが安全です。</p>

<pre><code>builder {
    enable_if { $_[0]-&gt;{REMOTE\_ADDR} eq '127.0.0.1' } 
        "Plack::Middleware::ReverseProxy";
    $app;
};
</code></pre>

<p>拙作の <a href="http://search.cpan.org/~kazeburo/Plack-Builder-Conditionals/lib/Plack/Builder/Conditionals.pm">Plack::Builder::Conditionals</a> を使うと以下のように書けます。</p>

<pre><code>use Plack::Builder;
use Plack::Builder::Conditionals;

builder {
    enable match_if addr(['192.168.0.0/24','127.0.0.1']),
        "Plack::Middleware::ReverseProxy";
    $app
};
</code></pre>

<p>このようにREMOTE_HOSTを指定するのは、改ざんされたリクエストを防ぐためです。</p>

<p>PM::ReverseProxyの仕組みは以下の図のようになります。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="reverseproxy1.png" src="http://blog.nomadscafe.jp/2012/01/06/reverseproxy1.png" width="450" height="373" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>ブラウザ(IPアドレス:v.x.y.z)からReverse Proxyに対してリクエストを行うと、Reverse Proxyは「X-Forwarded-For」ヘッダにREMOTE_ADDRを追加してApplication Serverにリクエストします。Application Serverでは当然REMOTE_ADDRがReverse Proxyの物(ここではlocalhost)になりますが、PM::ReverseProxyはX-Forwarded-Forをみて、REMOTE_ADDRを上書きします。これにより本来のアクセス元がApplication ServerでもREMOTE_ADDRで取得できます。</p>

<p>ここで、Application Server側でREMOTE_ADDRを確認しないと、以下のような事態がおきます。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="reverseproxy2.png" src="http://blog.nomadscafe.jp/2012/01/06/reverseproxy2.png" width="450" height="231" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>X-Forwarded-Forヘッダに任意のIPアドレス(v.x.y.z)を追加し、Application Serverに直接アクセスするとPM::ReverseProxyは同じようにREMOTE_ADDRを設定します。本来REMOTE_ADDRは「192.168.9.41」にも関わらず、「v.x.y.z」と名乗れてしまいます。もし、v.x.y.zからしか閲覧することができないコンテンツがあっても、この方法で見る事ができてしまいます。</p>

<pre><code>use Plack::Builder;
use Plack::Builder::Conditionals;

builder {
    enable 'ReverseProxy';
    mount '/private' =&gt; builder {
        enable match_if addr('!','v.x.y.z'), 
            sub { sub { [403,['Content-Type'=&gt;'text/plain'],['Forbidden']] } };
        $private_app;
    };
    $app
};
</code></pre>

<p>↑こういうの危険。</p>

<p>Application Serverに直接アクセスできないのは普通だと思いますが、なんらかの設定漏れでアクセスができてしまうことも考えられます。念をいれてREMOTE_ADDRをチェックするのをお勧めします。</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2012/01/plackmiddlewarereverseproxy.html</feedburner:origLink></entry>

<entry>
    <title>Plack::Middleware::AccessLog でありがちな罠</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/Yv_Ht4ZTKps/plackmiddlewareaccesslog.html" />
    <id>tag:blog.nomadscafe.jp,2012://1.157</id>

    <published>2012-01-06T03:17:26Z</published>
    <updated>2012-01-06T03:26:06Z</updated>

    <summary>Plack::Middleware::AccessLog は Apacheライク...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>Plack::Middleware::AccessLog は Apacheライクなログが残せる便利ミドルウェアなんですが使う上で一つ注意点があります。</p>

<pre><code>use Plack::Builder;

builder {
    enable "AccessLog", format =&gt; "combined";
    sub { die };
};
</code></pre>

<p>これで、500エラーのログが残ることを期待するかもしれませんが、実際は記録されません。</p>

<p>例外がMiddleware層を飛ばしてServerまで伝わる為で、何らかの形で例外を補足してあげる必要があります。</p>

<p>例えば、Plack::Middleware::HTTPExceptions</p>

<pre><code>builder {
    enable "AccessLog", format =&gt; "combined";
    enable "HTTPExceptions";
    sub { die };
};
</code></pre>

<p>もしくは自前でMiddlewareを書く方法。</p>

<pre><code>use Plack::Builder
use Try::Tiny

builder {
    enable "AccessLog", format =&gt; "combined";
    enable_if { ($ENV{PLACK_ENV} || '') ne 'development'} sub {
        my $app = shift;
        sub {
            my $env = shift;
            try {
                $app-&gt;($env);
            } catch {
                $env-&gt;{'psgi.errors'}-&gt;print($_);
                [500,['Content-Type'=&gt;'text/plain'],['Internal Server Error']];
            }
        }
    };
    sub { die };
};
</code></pre>

<p>やってることはHTTPExceptionsとほぼ同じです</p>

<p>Middlewareを使う場合は、miyagawaさんの<a href="http://www.slideshare.net/miyagawa/plack-at-oscon-2010/93">slide</a>にも登場する。この図を思い浮かべるといいと思います。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="pylons_as_onion.png" src="http://blog.nomadscafe.jp/2012/01/06/pylons_as_onion.png" width="478" height="435" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p><a href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/concepts.html#wsgi-middleware">pylonsのドキュメント</a>から転載です</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2012/01/plackmiddlewareaccesslog.html</feedburner:origLink></entry>

<entry>
    <title>そろそろSTFのデータベース運用についてひとこと言っておくか</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/ngiHa0vrxzM/stf.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.156</id>

    <published>2011-12-31T14:29:26Z</published>
    <updated>2011-12-31T14:37:19Z</updated>

    <summary>祝オープンソース化。 STF 分散オブジェクトストレージシステム http://...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>祝オープンソース化。</p>

<p>STF 分散オブジェクトストレージシステム<br />
<a href="http://labs.edge.jp/stf/">http://labs.edge.jp/stf/</a></p>

<p>ライブドアのサービスで主に画像管理用に使っているSTFがオープンソースで公開されています。</p>

<p>Perl/PSGI、Q4M、MySQL、Apacheという、Webアプリケーションエンジニアにとってとてもなじみやすい構成を取っており、実際運用もしやすくなっています。</p>

<p>ただひとつ気になるのはMySQLのデータのデカさ。3億オブジェクト／10億エンティティを保存した段階でのMySQLのデータサイズは、約220GBにもなります。これを潤沢にメモリを積み、SSDを4本RAID10にしたサーバにて運用しております。</p>

<p>データの取り回しも大変で、データのダンプに数時間、リストアに数十時間、レプリケーションが追いつくのにまた数時間と移設作業を行うのにまるまる一週間かかるような感じです。とってもカジュアルではありませんね。</p>

<h2>テーブル構成</h2>

<p>STFの主なテーブルは以下の4つです。</p>

<ul>
<li>bucket</li>
<li>object</li>
<li>entity</li>
<li>storage</li>
</ul>

<p>bucketはオジェクトをまとめる単位。objectは外から見えるファイル、entityはファイルの実体でサーバに分散配置されます。そのサーバについて定義するのがstorageテーブルです。</p>

<p>すべてのスキーマはソースコードの中に含まれるので以下から取得可能です。</p>

<p>h<a href="ttps://github.com/stf-storage/stf/blob/master/misc/stf.sql">ttps://github.com/stf-storage/stf/blob/master/misc/stf.sql</a></p>

<p>このテーブルのうち、データサイズが大きくなるのはobjectとentityの2つ。</p>

<pre><code>CREATE TABLE object (
       id BIGINT NOT NULL PRIMARY KEY,
       bucket_id BIGINT NOT NULL,
       name VARCHAR(255) NOT NULL,
       internal_name VARCHAR(128) NOT NULL,
       size INT NOT NULL DEFAULT 0,
       num_replica INT NOT NULL DEFAULT 1,
       status TINYINT DEFAULT 1 NOT NULL,
       created\_at INT NOT NULL,
       updated\_at TIMESTAMP,
       UNIQUE KEY(bucket_id, name),
       UNIQUE KEY(internal_name)
) ENGINE=InnoDB;

CREATE TABLE entity (
       object_id BIGINT NOT NULL,
       storage_id INT NOT NULL,
       status TINYINT DEFAULT 1 NOT NULL,
       created_at INT NOT NULL,
       updated_at TIMESTAMP,
       PRIMARY KEY id (object_id, storage_id),
       KEY(object_id, status),
       KEY(storage_id),
       FOREIGN KEY(storage_id) REFERENCES storage(id) ON DELETE RESTRICT
) ENGINE=InnoDB;
</code></pre>

<h2>データサイズを小さく保つための工夫</h2>

<p>まず object テーブルをみて気になるのが、ユニーク属性を保つインデックスが3つあるということ。</p>

<ul>
<li>PRIMARY KEY</li>
<li>UNIQUE KEY(bucket_id, name)</li>
<li>UNIQUE KEY(internal_name)</li>
</ul>

<p>PRIMARY KEYはBIGINTで時間とDispatcherサーバに割り当てられたIDから計算されるユニークな数値です。2つは目システムの外から見えるバケットとファイル名のユニーク制限。そして3つ目がSTF内部でのファイル名です。</p>

<p>nameもinternal_nameもVARCHARとなるので、インデックスのサイズも大きくなりそうです。そこで利用できるのがMurmurHash等を使いより小さいデータにインデックスを張る方法。</p>

<p>データ分散とインデックス最適化のためのハッシュ関数の利用 - Perl Advent Calendar Japan 2011 Hacker Track<br />
<a href="http://perl-users.jp/articles/advent-calendar/2011/hacker/11">http://perl-users.jp/articles/advent-calendar/2011/hacker/11</a></p>

<p>MurmurHashは32bitの数値となるのでハッシュ値が衝突する可能性が割と高いと思われるので、実際に使う場合はhash値をにユニークインデックスを張らず、通常のインデックスとし、データ追加時にトランザクションを使ってデータが被らないようにする必要があります。</p>

<p>internal_nameについては、本当にこの値が必要かどうか考えることが必要そうです。ここまで既にテーブル上に2つのユニークな値があるので、そっちを活用すればインデックスだけではなくカラム自体の削除もできそうです。例えば、PRIMARY KEYのBIGINTを内部のファイル名にしても良いはずです。</p>

<p>entityテーブルについては、2点ほど気になる点があります。1つはcreated_atとupdated_atのカラム、もう一つがKEY(object_id, status)のインデックスです。</p>

<p>MySQLのドキュメントに各データタイプにおける必要保存領域が書かれています。</p>

<p>10.5. データタイプが必要とする記憶容量<br />
<a href="http://dev.mysql.com/doc/refman/5.1/ja/storage-requirements.html">http://dev.mysql.com/doc/refman/5.1/ja/storage-requirements.html</a></p>

<p>created_atとupdated_atはそれぞれINTとTIMESTAMPなので、4byte+4byte=8byte必要となります。10億レコードあれば8GB分のデータにもなります。消すと若干節約できますね。</p>

<p>KEY(object_id, status)のインデックスも基本必要ないはずです。object_idを指定した段階で結果はオブジェクトの複製数（せいぜい3から5）にしぼらるので、statusをインデックスに含めなくても高速に検索可能です。PRIMARY KEYが(object_id, storage_id)なのでこちらで十分に事足ります。</p>

<p>ここまでぐだぐだと書いた内容を入れ込むとスキーマはこんな感じかな</p>

<pre><code>CREATE TABLE object (
       id BIGINT NOT NULL PRIMARY KEY,
       bucket_id BIGINT NOT NULL,
       name VARCHAR(255) NOT NULL,
       name_hash INT UNSIGNED NOT NULL,
       size INT NOT NULL DEFAULT 0,
       num_replica INT NOT NULL DEFAULT 1,
       status TINYINT DEFAULT 1 NOT NULL,
       created_at INT NOT NULL,
       updated_at TIMESTAMP,
       KEY(bucket_id, name_hash)
) ENGINE=InnoDB;

CREATE TABLE entity (
       object_id BIGINT NOT NULL,
       storage_id INT NOT NULL,
       status TINYINT DEFAULT 1 NOT NULL,
       PRIMARY KEY id (object_id, storage_id),
       KEY(storage_id),
       FOREIGN KEY(storage_id) REFERENCES storage(id) ON DELETE RESTRICT
) ENGINE=InnoDB;
</code></pre>

<p>データサイズがどれくらいになるかはやってみないとわからないけど、確実に小さくはなって、データのハンドリングが楽になると思うので、仕事が始まったらできるところからやってみたいです ＞ 誰か</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/12/stf.html</feedburner:origLink></entry>

<entry>
    <title> この一年のブログエントリまとめ - 2011 </title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/YESej8IZxc4/---2011.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.155</id>

    <published>2011-12-30T15:02:42Z</published>
    <updated>2011-12-30T15:21:37Z</updated>

    <summary>去年に引き続き、今年も書いてみる。 今年を振り返って公私共に影響が大きかったのは...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p><a href="http://blog.nomadscafe.jp/2010/12/post-10.html">去年</a>に引き続き、今年も書いてみる。</p>

<p>今年を振り返って公私共に影響が大きかったのは、やはり3/11の東北関東大震災。幸い家族には影響なく過ごしていますが、まだまだ被災された方は大変な思いをされていると思います。今自分ができることを少しだけでもつづけて行きたいと思います</p>

<p>当日は交通手段がすべてストップしてしまったので、新宿から横浜まで歩いて帰ってきました。</p>

<p><a href="http://blog.nomadscafe.jp/2011/03/311.html">3.11 新宿から横浜まで歩いて帰ってきた</a></p>

<p>このあと自宅作業期間や、ノーエンジニアデーがあり、リモートで仕事できる環境が整いました。最近は朝はカフェで仕事しています。</p>

<h2>山の8月/9月</h2>

<p>今年のブログ記事を振り返って行くと、9月だけまったく記事がない。9月に何をやっていたかというと、一つは沖縄へ旅行行ってたことと、もう一つは大規模メンテナンス。</p>

<p><a href="http://blog.livedoor.jp/staff/archives/51705956.html">[完了報告][9/14] メンテナンスのお知らせ</a></p>

<p>この裏側では記事のデータベースを一気に移動する作業を行っていました。この作業とその後の対応で生まれたのがmysql40dump。Kansai.pmでも少し紹介しましたが、12月に公開版を用意し記事として書きました。</p>

<p><a href="http://blog.nomadscafe.jp/2011/12/-mysql40dump-mysqldump-wrapper.html">レプリケーション作成を簡単にする mysql40dump という mysqldump の wrapper を作った話</a></p>

<p>この9月の前の8月もわりとイベントが多い月でした。8/27 に開催したISUCONはその一つ。かなりもりあがりました</p>

<p><a href="http://blog.nomadscafe.jp/2011/08/http-load-isucon.html">チート対策とhttp_loadに仕掛けた罠の話 #isucon</a></p>

<p>後日こんなGoogleでサジェストがされたようです。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="kazeburo-wana.png" src="http://blog.nomadscafe.jp/2011/12/31/kazeburo-wana.png" width="687" height="142" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>ひどい＞＜</p>

<h2>まとめてみたシリーズ</h2>

<p>8月までは自分の考えを記事としてまとめてみた系が多い。ブックマース数もそれなり伸びた。</p>

<p><a href="http://blog.nomadscafe.jp/2011/01/psgi.html">PSGIアプリケーションをリバースプロキシ下で使う際の静的コンテンツの配信方法について</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/02/httpplack.html">HTTPコンテンツ圧縮とPlack</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/02/http.html">HTTPコンテンツ圧縮はどのレイヤーで行うのがいいか</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/03/web.html">Webアプリケーションエンジニアに知っていて欲しいインフラの知識</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/06/web-1.html">Webアプリケーションエンジニアはノマドであれ（特定のサーバに依存しない方法）</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/06/web-job-queue-worker.html">Webアプリケーションにおける Job Queue システムの構成例と Worker を作る際に気をつけること</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/06/efficent-server-operarion.html">私家版省サーバ運用2011またはWebシステムのコンポーネントの配置について</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/06/memcached-1.html">memcached を使ったアプリケーションの設計について</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/07/for-efficient-use-of-resources.html">ディレクターやエンジニアが運用エンジニアにインフラの相談をする際に持って来て欲しい5つのこと</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/07/apache.html">今こそ見直すApacheの設定</a></p>

<p>新規サービスだったり、既存サービスの設計・サーバ設定をする際に、こんなところに気をつけて欲しいなというのを書き出していったってのが実際のところです。記事を書くだけはなく、仕事ではエンジニアがサーバの設定を迷わずにできるツールを用意して、使ってもらったりしています。</p>

<h2>作った話</h2>

<p>新しく作ったモジュール・システムもいくつかあります。</p>

<p><a href="http://blog.nomadscafe.jp/2011/01/sqldbixsunny.html">SQLを書くプロジェクトのためのDBIx::Sunnyってのを書いている</a></p>

<p>DBIx::Sunnyはこのあと若干の方針転換があり、Sunny.pmとSchema.pmに分かれました。俺俺的に便利でこの後に書いたプロジェクトではほぼ必ず採用しています。</p>

<p><a href="http://blog.nomadscafe.jp/2011/02/-thundering-herd-cacheisolator.html">キャッシュシステムの Thundering Herd 問題対策モジュール Cache::Isolatorというのを書いた</a></p>

<p>CPANにもリリース済み。某Blogサービスでもこのモジュールではないけど同じ仕組みを導入して重い処理を捌いている。</p>

<p><a href="http://blog.nomadscafe.jp/2011/02/orepancpanmcpancpan.html">OrePANとcpanmでCPANの部分ミラーを作ってCPANモジュールを管理する</a></p>

<p>新規サーバ用にperlbrewで新しめのperlとよく使うperlモジュールを最初から入れるという仕事があり、その結果として生まれたのがOrePAN(へのpatch)。最近では他の会社さんでも使っているそうな</p>

<p><a href="http://blog.nomadscafe.jp/2011/05/plack-mod-deflate-plackmiddlewaredeflater.html">Plack版 mod_deflate の Plack::Middleware::Deflater がバージョンアップしました</a></p>

<p>miyagawaさんのモジュールですが、Co-Maintainerにして頂いたので機能追加してアップデートしました。HTTP圧縮周りのバッドノウハウにも対応できます</p>

<p><a href="http://blog.nomadscafe.jp/2011/05/greenbuckets-object-storage.html">GreenBuckets という Object Storage を作りました</a></p>

<p>いわゆる「僕の考える最強の分散オブジェクトストレージ」。実際は最強を目指しているわけではなくシンプルに使えるものを目指しました。作った当初はなんの予定もありませんでしたが、なんと11月にサービスで使われ始めました。</p>

<p><a href="http://blog.nomadscafe.jp/2011/12/kossy-dbixsunny-nopaste.html">Kossy と DBIx::Sunny で作る nopaste</a></p>

<p>ISUCONの際に用意したWeb Application FrameworkをCPANにあげました。GrowthForecastを始め、いくつかのツールで使っています。</p>

<p><a href="http://blog.nomadscafe.jp/2011/12/growthforecast.html">GrowthForecastというグラフ表示ツールで捗る話</a></p>

<p>Yappoさんのlivedoorへの参加は個人的にすごく影響のあったことの一つ。Yappo氏の形にしていく力はいつも勉強になる。GrowthForecastもYappo氏のアイディアとプロトタイプが元になってます。</p>

<p>簡単にグラフにして見える化できるのでGrowthForecastはほんと便利です。</p>

<h2>喋ってきた話／書いた話</h2>

<p><a href="http://blog.nomadscafe.jp/2011/04/web3.html">Webサーバ勉強会#3に参加してきました</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/05/yokohamapm7.html">Yokohama.pm#7 で喋って来たよ!</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/08/software-design-20119.html">Software Design 2011年9月号に運用エンジニアに関する記事を寄稿しました</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/08/mysql-40-casual-talks-vol2-lt.html">MySQL 4.0 Casual Talks Vol.2 で LT してきました</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/10/yapcasia-tokyo-2011.html">YAPC::Asia Tokyo 2011 で発表してきました。</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/11/kansaipm-14.html">Kansai.pm #14 に参加して発表しました</a></p>

<p><a href="http://blog.nomadscafe.jp/2011/11/webdb-press-vol65-perl-hackers-hub.html">WEB+DB PRESS Vol.65 Perl Hackers Hubに寄稿しました</a></p>

<p>いろんな方にお世話になりました。</p>

<h2>さよなライブドア。こんにちはNHN Japan</h2>

<p>来年1/1にライブドアはNHN Japanに会社統合され、株式会社ライブドアという名称はなくなります。なじみのある（そして昔からのあこがれであった）会社名がなくなる若干の寂しさはありますが、引き続きBlogをはじめとするlivedoorブランドのメディア、サービスを運用やスケーラビリティといった立場から支えて行く事になるとおもうので、これからもよろしくお願いします。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="livedoor.jpg" src="http://blog.nomadscafe.jp/2011/12/31/livedoor.jpg" width="320" height="427" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>最終日の帰り際に入り口を見に行ったらもうロゴが外されていた。。</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/12/---2011.html</feedburner:origLink></entry>

<entry>
    <title>ImageMagickとOpenMPの件</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/RwidYmLqDqc/imagemagickopenmp.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.154</id>

    <published>2011-12-29T12:33:10Z</published>
    <updated>2011-12-29T12:43:18Z</updated>

    <summary>「PerlMagick が OpenMP 有効だと高負荷になる件 :: drk7...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>「<a href="http://www.drk7.jp/MT/archives/001841.html">PerlMagick が OpenMP 有効だと高負荷になる件 :: drk7jp</a>」の件</p>

<p>どうやら、Perlに限らずマルチプロセスでOpenMPが有効なImageMagickを動かすとパフォーマンスが悪くなるようです。</p>

<blockquote>
  <p>Enabling OpenMP for most algorithms creates 8 threads (1 per core). If your process creates 8 threads that&#8217;s a total of 64 threads and that is a whole lot of contention and possible misuse of your processor cache.</p>
</blockquote>

<p>「<a href="http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&amp;t=14307">ImageMagick &bull; View topic - Multi Process Contention?</a>」より</p>

<p>ということで、<a href="http://labs.edge.jp/smalllight/">small_light</a>が動いているサーバ1台でImageMagickをビルドし直してみました。</p>

<p>その結果が以下のグラフ。16:30過ぎにmakeしているため一旦CPU使用率があがりますが、その後は1%強で推移。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="disable-openmp.png" src="http://blog.nomadscafe.jp/2011/12/29/disable-openmp.png" width="482" height="257" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>すごく&#8230; 効果がありました.. ///</p>

<p>年があけたら全台入れ替えて、そしてサーバを減らそう</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/12/imagemagickopenmp.html</feedburner:origLink></entry>

<entry>
    <title>Kossy と DBIx::Sunny で作る nopaste</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/Z0MjtUA6xho/kossy-dbixsunny-nopaste.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.153</id>

    <published>2011-12-24T14:31:47Z</published>
    <updated>2011-12-24T14:37:32Z</updated>

    <summary>GrowthForecastや社内のサーバアラートビュアーで使っているWeb A...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p><a href="https://github.com/kazeburo/GrowthForecast">GrowthForecast</a>や社内のサーバアラートビュアーで使っているWeb Application Framework <a href="https://metacpan.org/module/Kossy">Kossy</a>の使い方。</p>

<p>KossyはCPANにリリースされているので、cpanm でインストールができます</p>

<pre><code>$ cpanm Kossy
</code></pre>

<p>アプリケーションのひな形を作る kossy-setup というコマンドもインストールされるので、これを使います。今回のサンプルアプリケーションの名前は KoPaste としましょう。</p>

<pre><code>$ kossy-setup KoPaste
mkdir lib/KoPaste
mkdir views
mkdir public
mkdir public/js
mkdir public/css
mkdir public/images
mkdir t
writing lib/KoPaste.pm
writing t/00_compile.t
writing lib/KoPaste/Web.pm
writing app.psgi
writing views/index.tx
writing views/base.tx
writing Makefile.PL
writing public/favicon.ico
writing public/js/bootstrap-alerts.js
writing public/css/bootstrap.min.css
writing public/js/jquery-1.7.1.min.js
writing public/js/bootstrap-modal.js
</code></pre>

<p>スケルトンのコードとcss/jsなどが展開されました。早速ディレクトリに移動し、plackupでサーバを起動してみます。</p>

<pre><code>$ cd KoPaste
$ plackup -r app.psgi
</code></pre>

<p>すごく&#8230; bootstrapです.. ///</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://blog.nomadscafe.jp/2011/12/24/kossy-setup.png"><img alt="kossy-setup.png" src="http://blog.nomadscafe.jp/assets_c/2011/12/kossy-setup-thumb-600x369-121.png" width="600" height="369" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>ここからNoPasteに必要な機能をつくっていきましょう。今回作るアプリケーションは十分に小さいのでデータを操作する関数も一つのクラスにいれます。</p>

<p>KoPaste::Web が Dispatcherクラスなのでこれを編集します</p>

<pre><code>use DBIx::Sunny;
use Digest::SHA;

sub dbh {
    my $self = shift;
    my $db = $self-&gt;root_dir .'/nopaste.db';
    $self-&gt;{_dbh} ||= DBIx::Sunny-&gt;connect("dbi:SQLite:dbname=$db",'','',{
        Callbacks =&gt; {
            connected =&gt; sub {
                my $conn = shift;
                $conn-&gt;do(&lt;&lt;EOF);
CREATE TABLE IF NOT EXISTS entry (
    id VARCHAR(255) NOT NULL PRIMARY KEY,
    nickname VARCHAR(255) NOT NULL,
    body TEXT,
    created_at DATETIME NOT NULL
);
EOF
                $conn-&gt;do(q{CREATE INDEX IF NOT EXISTS index_created_at ON entry ( created_at )});
                return;
            },
        },
    });
}
</code></pre>

<p>データベースとしてSQLiteを使って、Callbackで接続時にテーブルがなければ作ります。 $self->root_dir はapp.psgiが配置されているディレクトリが入っています。</p>

<p>がりっとエントリー操作用のメソッドも追加します</p>

<pre><code>sub add_entry {
    my $self = shift;
    my (  $body, $nickname ) = @_;
    $body = '' if ! defined $body;
    $nickname = 'anonymous' if ! defined $nickname;
    my $id = substr Digest::SHA::sha1_hex($$ . join("\0", @_) . rand(1000) ), 0, 16;
    $self-&gt;dbh-&gt;query(
        q{INSERT INTO entry (id,nickname,body,created_at) VALUES ( ?, ?, ?, DATETIME('now') )},
        $id, $nickname, $body
    );
    return $id;
}

sub entry_list {
    my $self = shift;
    my $offset = shift;
    $offset = 0 if defined $offset;
    my $rows = $self-&gt;dbh-&gt;select_all(
        q{SELECT * FROM entry ORDER BY created_at DESC LIMIT ?,11},
        $offset
    );
    my $next;
    $next = pop @$rows if @$rows &gt; 10;
    return $rows, $next;
}
</code></pre>

<p>dbh->query や dbh->select_all は DBIx::Sunnyが提供するショートカットメソッドです。</p>

<p>ここから Dispatcherの実装です。「/」にアクセスした際に実行されるコードは、スケルトンでは</p>

<pre><code>get '/' =&gt; [qw/set_title/] =&gt; sub {
    my ( $self, $c )  = @_;
    $c-&gt;render('index.tx', { greeting =&gt; "Hello" });
};
</code></pre>

<p>このように書かれています。これをエントリーのリストが表示されるようにしましょう</p>

<pre><code>get '/' =&gt; sub {
    my ( $self, $c )  = @_;
    my $result = $c-&gt;req-&gt;validator([
        'offset' =&gt; {
            default =&gt; 0,
            rule =&gt; [
                ['UINT','ivalid offset value'],
            ],
        },
    ]);
    $c-&gt;halt(403) if $result-&gt;has_error;
    my ($entries,$has_next) = $self-&gt;entry_list($result-&gt;valid('offset'));
    $c-&gt;render('index.tx', {
        offset =&gt; $result-&gt;valid('offset'),
        entries =&gt; $entries,
        has_next =&gt; $has_next,
    });
};
</code></pre>

<p>Dispatcherのメソッドには、2つの引数が渡されます。1つ目が KoPaste::Webのオブジェクト。2つ目がKossy::Connectionオブジェクトです。 KoPaste::Webオブジェクトはアプリケーション初期化時点からプロセスが死ぬまで有効なオブジェクトで、もちろんKoPaste::Webの他のメソッドの呼び出しに利用できます。Kossy::Connectionオブジェクトはリクエスト単位で生成されるオブジェクトとなります。</p>

<p>ここででてきたvalidatorはKossy内蔵のKossy::Validatorです。ページングする際のoffestについてバリデーションを定義しています。正の整数だけを受け取り、もしパラメータがないときには、0がデフォルトしています。</p>

<p>もしoffsetの値が正しくなければ、403 Forbiddenを返します。</p>

<pre><code>$c-&gt;halt(403) if $result-&gt;has_error;
</code></pre>

<p>そして、上で定義したentry_listメソッドを叩き、一覧を取得。テンプレートに各値を渡します。</p>

<p>もう一つエントリーのポストを受け付けるエンドポイントを作りましょう。</p>

<pre><code>post '/create' =&gt; sub {
    my ( $self, $c )  = @_;
    my $result = $c-&gt;req-&gt;validator([
        'body' =&gt; {
            rule =&gt; [
                ['NOT_NULL','empty body'],
            ],
        },
        'nickname' =&gt; {
            default =&gt; 'anonymous',
            rule =&gt; [
                ['NOT_NULL','empty nickname'],
            ],
        }
    ]);
    if ( $result-&gt;has_error ) {
        return $c-&gt;render_json({ error =&gt; 1, messages =&gt; $result-&gt;errors });
    }
    my $id = $self-&gt;add_entry(map {$result-&gt;valid($_)} qw/body nickname/);
    $c-&gt;render_json({ error =&gt; 0, location =&gt; $c-&gt;req-&gt;uri_for("/")-&gt;as_string });
};
</code></pre>

<p>POSTでデータを受け付け、JSONでレスポンスを返します。「/」と同じようにKossy::Validatorを使って入力値のチェックを行っています。JSONでレスポンスするには、$c->render_json が利用できますが、Amon2と同じ</p>

<ul>
<li>「GET リクエストである」かつ</li>
<li>「Cookie ヘッダを送信している」かつ</li>
<li>「/android/i にマッチする User-Agent ヘッダを付与している」かつ</li>
<li>「X-Requested-With ヘッダを付与していない」</li>
</ul>

<p>という条件に当てはまる場合、403エラーとなるので注意してください。</p>

<p>ここまででDispatcher側の変更はひとまず終了してテンプレートの編集に移ります。</p>

<p>テンプレートは、viewsディレクトリに配置し、Text::XslateのKolonシンタックスをサポートしています。index.txを開くと次のようになっています。</p>

<pre><code>: cascade base
: around page_header -&gt; {
&lt;h1&gt;&lt;: $c.stash.site_name :&gt;&lt;/h1&gt;
: }

: around content -&gt; {
&lt;h2&gt;&lt;: $greeting :&gt;&lt;/h2&gt;
: }
</code></pre>

<p>base.txをカスケードしています。base.txにHTMLの構造を書き、各テンプレートにはコンテンツ部分だけを記す事ができます。index.txを編集してエントリー一覧を表示します。一覧の下には投稿用のフォームも付けます</p>

<pre><code>: around content -&gt; {
: for $entries -&gt; $entry {
&lt;h2&gt;&lt;a href="&lt;: $c.req.uri_for('/'~$entry.id) :&gt;"&gt;&lt;: $c.req.uri_for('/'~$entry.id) :&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre class="prettyprint linenums:1"&gt;
&lt;: $entry.body :&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;: $entry.created_at :&gt; by &lt;: $entry.nickname :&gt;&lt;/p&gt;
: }

&lt;div class="pagination"&gt;
&lt;ul&gt;
: if $offset &gt; 0 {
&lt;li&gt;&lt;a href="&lt;: $c.req.uri_for('/',[offset =&gt; $offset-10 &gt;= 0 ? $offset - 10 : 0]) :&gt;"&gt;Prev&lt;/a&gt;&lt;/li&gt;
: }
: if $has_next {
&lt;li&gt;&lt;a href="&lt;: $c.req.uri_for('/',[offset =&gt; $offset+10]) :&gt;"&gt;Next&lt;/a&gt;&lt;/li&gt;
: }
&lt;/ul&gt;
&lt;/div&gt;

&lt;form id="create-form" method="post" action="&lt;: $c.req.uri_for('/create') :&gt;"&gt;
&lt;h2&gt;New Paste&lt;/h2&gt;

&lt;div class="alert-message error hide"&gt;
&lt;p&gt;System Error! &lt;em&gt;try again&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;fieldset&gt;
&lt;div class="clearfix"&gt;
&lt;label&gt;body&lt;/label&gt;
&lt;div class="input"&gt;
&lt;textarea class="span9" name="body" rows="10"&gt;&lt;/textarea&gt;
&lt;span class="help-block"&gt;fill your code&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="clearfix"&gt;
&lt;label&gt;nickname&lt;/label&gt;
&lt;div class="input"&gt;
&lt;input class="xlarge" name="nickname" /&gt;
&lt;span class="help-block"&gt;your name&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="actions"&gt;
&lt;input type="submit" class="btn primary" value="Submit" /&gt;
&lt;/div&gt;
&lt;/fieldset&gt;
&lt;/form&gt;
: }
</code></pre>

<p>最後に、投稿処理用のJavaScriptをbase.txに追加します。</p>

<pre><code>&lt;script type="text/javascript"&gt;
$(function(){
  $('#create-form').submit(function () {
    create_form = this;
    $.ajax({
      type: 'POST',
      url: create_form.action,
      data: $(create_form).serialize(),
      success: function(data) {
        $(create_form).find('.alert-message.error').hide();
        if ( data.error == 0 ) {
            location.href = data.location;
        }
        else {
          $(create_form).find('div.clearfix').removeClass('error');
          $.each(data.messages, function (param,message) {
            $(create_form).find('[name="'+param+'"]').
               parents('div.clearfix').first().addClass('error');
          });
        }
      },
      error: function() {
        $(create_form).find('.alert-message.error').show();
      },
      dataType: 'json'
    });
    return false;
  });
});
&lt;/script&gt;
</code></pre>

<p>スケルトンの状態でjQueryは既に読み込まれています。</p>

<p>ここまでできたら、再度アプリケーションを起動します</p>

<pre><code>$ plackup -r app.psgi
</code></pre>

<p>ブラウザで確認すると</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="kossy-sample.png" src="http://blog.nomadscafe.jp/2011/12/24/kossy-sample.png" width="619" height="713" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>のようにエントリーの投稿もできると思います。画面はさらに<a href="http://code.google.com/p/google-code-prettify/">google-code-prettify</a>も追加してエントリの整形も行っています。</p>

<p>このようにKossyを使うと、Webアプリケーションを素早く開発できます。Sinatra風のDispatcherのため、大規模の開発には向きませんが、管理画面や運用ツールなどに試していただけるといいかなと思います</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/12/kossy-dbixsunny-nopaste.html</feedburner:origLink></entry>

<entry>
    <title>レプリケーション作成を簡単にする mysql40dump という mysqldump の wrapper を作った話 </title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/MXqf4NP0-QE/-mysql40dump-mysqldump-wrapper.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.152</id>

    <published>2011-12-22T07:34:33Z</published>
    <updated>2011-12-22T07:48:59Z</updated>

    <summary>みなさん mysqldump は好きですか？ 自分はどっちでもありません。 My...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>みなさん mysqldump は好きですか？ 自分はどっちでもありません。</p>

<p>MySQLでよくあるMaster-Slave構成を作る手順は以下のようになると思います</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="mysql40dump-3.png" src="http://blog.nomadscafe.jp/2011/12/22/mysql40dump-3.png" width="590" height="348" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<ol>
<li>MasterからSlaveとなるサーバに一貫性を保った状態のコピーをし、そのデータのバイナリログのファイル・ポジションをメモ。</li>
<li>SLAVEでデータをリストアし、Masterのホスト名、レプリケーションに使うユーザ名・パスワードとメモしたバイナリログのポジションをCHANGE MASTER文に渡し、START SLAVE</li>
</ol>

<p>一貫性の取れたコピーを作成するためにmysqldumpや<a href="http://www.percona.com/software/percona-xtrabackup/">xtrabackup</a>、LVMなどでのスナップショットが利用できますが、もっとも簡単な方法がmysqldumpだと思います。</p>

<p>mysqldumpで一貫性のあるデータをとり、その際のバイナリログポジションを記録するには</p>

<pre><code>$ mysqldump --single-transaction --master-data
</code></pre>

<p>とします。single-transactionでバックアップをトランザクション中で行い、&#8212;master-data=2 でバイナリログのポジションをバックアップの先頭にコメントとして記録できます。(single-transactionでもInnoDB以外のテーブルがある場合は一貫性のあるデータがとれない可能性があります)</p>

<p>実際のmysqldumpが発行しているクエリは以下のようになってます。</p>

<pre><code>FLUSH LOCAL TABLES
FLUSH TABLES WITH READ LOCK
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
START TRANSACTION WITH CONSISTENT SNAPSHOT
SHOW MASTER STATUS
UNLOCK TABLES
DB選択
テーブルからデータの読み込み
</code></pre>

<p>(<a href="http://d.hatena.ne.jp/tmtms/20110713/mysqldump">@tmtms のメモ</a>より)</p>

<p>まずREAD LOCKをかけ、つぎにトランザクション開始し、バイナリログのポジションを確保。その後READ LOCKを解放し、(トランザクションはそのまま)データのダンプを行っています。</p>

<p>このようにmysqldumpで一貫性のあるデータコピーとバイナリログの位置を取得できます。</p>

<p><br />
<br />
<span style="font-size:200%;">が</span>
<br />
<br /></p>

<p>がががが、まぁよくある話で、MySQL 4.0のサーバに対して mysqldumpを実行すると</p>

<pre><code>FLUSH TABLES WITH READ LOCK
BEGIN
DB選択
テーブルからデータの読み込み
COMMIT;
SHOW MASTER STATUS
UNLOCK TABLES;
</code></pre>

<p>と、なり、なんと最初から最後までREAD LOCKされ、dumpが終了するまでデータを更新できなくなってしまいます。数十GBになるデータを扱っている場合これでは運用が難しい。。。</p>

<h2>Wrapper スクリプトの動作</h2>

<p>そこで考えたのが2つのプロセスを組み合わせて、READ LOCKとトランザクションを発行する次の仕組み。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://blog.nomadscafe.jp/2011/12/22/mysql40dump.014.png"><img alt="mysql40dump.014.png" src="http://blog.nomadscafe.jp/assets_c/2011/12/mysql40dump.014-thumb-640x480-116.png" width="640" height="480" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>mysqldumpをラップするperlスクリプトを起動すると、まずMySQLに対してREAD LOCKを行い全ての更新を止めます。そしてバイナリログの情報を取得。</p>

<p>次に、pipeを作成し、fork。forkした子プロセスでは標準出力をpipeに結びつけ、mysqldumpをsingle-transactionオプション付きでexec。single-transactionが有効なのでmysqldumpはトランザクションを開始してデータコピーを開始します。そのデータはpipeを通して親プロセスに送られます。</p>

<p>親プロセスでは、pipeからデータを読み込み、そのまま標準出力します。その際最初のCREATE TABLEを見つけたら、最初に行ったREAD LOCKを解放し、そのあとは mysqldumpが終了するまで動き続けます。</p>

<p>実際に最初のREAD LOCKからダンプを開始し、LOCKが解放されるまでは1秒も掛からないのでほぼ無停止だと言えるでしょう。これでMySQL 4.0でも一貫性のとれたデータダンプと、バイナリログのポジション取得が可能となります。</p>

<p>この仕組みを実装したのが <a href="https://github.com/kazeburo/mysql40dump/">mysql40dump</a> というスクリプトで、既に実際にサービスのデータベースの複製・バックアップに使っています。次に紹介する機能が便利なので、4.0だけではなくMySQL 5.1系でも動作確認しています。</p>

<h2>mysql40dump の追加機能</h2>

<p>まず1つ目がSHOW MASTER STATUSの代わりにSLAVE STATUSを実行する機能。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="mysql40dump-2.png" src="http://blog.nomadscafe.jp/2011/12/22/mysql40dump-2.png" width="522" height="353" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>のようにSLAVEからSLAVEを作るときに使えます。MySQL 5.5から実装された mysqldump &#8212;dump-slave 相当の機能ですね。</p>

<p>もう一つが自身のIPアドレスを調べ自動でCHANGE MASTER文を構築する機能と、START SLAVEまで実行する機能。これでほぼ面倒なことなくレプリケーションの開始まで自動化ができるようになりました。この自動化のおかげて3つ4つ同時に異なるデータベースのコピーを行っていても全く苦にならず捗ります。</p>

<p>あと、MySQL 4.0でのバッドノウハウとしてダンプデータの先頭に</p>

<pre><code>set FOREIGN_KEY_CHECKS=0
</code></pre>

<p>をいれます。これで何度泣いた事か。。</p>

<h2>使い方</h2>

<p>perlのスクリプトなのでインストールはcpanmでできます</p>

<pre><code>$ cpanm https://github.com/downloads/kazeburo/mysql40dump/mysql40dump-0.03.tar.gz
$ mysql40dump -h
</code></pre>

<h3>Master-Slave構成を取る場合</h3>

<p>Masterにて</p>

<pre><code>$ mysql40dump --master --repl --master-user user --master-password pass | gzip &gt; dump.sql.gz
</code></pre>

<p>ファイルをコピーして Slaveにて</p>

<pre><code>$ zcat dump.sql.gz | mysql
</code></pre>

<p>これでリストア後、レプリケーションの開始までやってくれます</p>

<h3>Slaveを追加する場合</h3>

<p>既存Slaveにて</p>

<pre><code>$ mysql40dump --slave --repl --master-password pass | gzip &gt; dump.sql.gz
</code></pre>

<p>ファイルをコピーして 新しいSlaveにて</p>

<pre><code>$ zcat dump.sql.gz | mysql
</code></pre>

<p>これでMasterからのレプリケーションが開始されます。</p>

<p>簡単ですね!</p>

<p>次の課題はxtrabackupのwrapperかな</p>

<p>合わせて読みたい</p>

<iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&bc1=000000&IS2=1&nou=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=nomadscafejp-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=ss_til&asins=4774142948" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>

<p><br /></p>

<p>図中のアイコンは、<a href="http://aws.amazon.com/architecture/icons/">AWS Simple Icons for Architecture Diagrams</a> を使いました</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/12/-mysql40dump-mysqldump-wrapper.html</feedburner:origLink></entry>

<entry>
    <title>Q4Mを簡単に導入する方法 - MySQL Casual Advent Calendar 2011</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/_BEc-jrg8pE/q4m---mysql-casual-advent-calendar-2011.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.151</id>

    <published>2011-12-04T06:46:46Z</published>
    <updated>2011-12-05T05:12:27Z</updated>

    <summary>xaicronとネタが被ったようだけど気にしない＞＜ livedoorでOper...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>xaicronと<a href="http://blog.livedoor.jp/xaicron/archives/53380670.html">ネタ</a>が被ったようだけど気にしない＞＜</p>

<p>livedoorでOperations EngineerやってるkazeburoだYo。最近livedoorからオープンソース化された3億ファイルを管理してるオブジェクトストレージ「<a href="http://stf-storage.github.com/">STF</a>」でも使ってるMessage Queueの<a href="http://q4m.github.com/">Q4M</a>のインストール方法を紹介するよ！　カジュアルだからインストールだけ！</p>

<p>知ってる人も多いと思うけどQ4Mはkazuhoさんによって開発されたMySQLのストレージエンジンとして実装されてるMessage Queue。livedoorではもちろん、mixiやDeNAをはじめソーシャルゲーム各社でも使われている。</p>

<p>Message Queueの説明や使い方はDIS_COMMENTでテーブルスペースフルの猫神様が書いてるので参考になるね！</p>

<blockquote>
  <p>Perl Hackers Hub 第10回　ジョブキューで後回し大作戦―TheSchwartz，Qudo，Q4M（1）
<a href="http://gihyo.jp/dev/serial/01/perl-hackers-hub/001001">http://gihyo.jp/dev/serial/01/perl-hackers-hub/001001</a></p>
</blockquote>

<p>このQ4M。MySQLのストレージエンジンとして実装されてるので、インストールにするにはもちろんMySQLが必要だ。しかしどのバージョンでも良い訳ではなく、MySQL 5.1系だけが対応となってる。最新の安定版<s>4.0</s>5.5には残念ながら対応してない。5.1を動かしていたとしても既にサービスで動いているMySQLに追加していれるもの勇気がいる。</p>

<p>個人的におすすめなのは「<a href="http://blog.nomadscafe.jp/2011/06/web-job-queue-worker.html">Webアプリケーションにおける Job Queue システムの構成例と Worker を作る際に気をつけること</a>」というエントリでも書いたけど、既存のデータベースとは別に導入する方法。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="jobqueue2.png" src="http://blog.nomadscafe.jp/2011/06/06/jobqueue2.png" width="375" height="317" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>上の図だと、brokerがQ4Mにあたる。</p>

<p>さて、ここまで決まったら、あとは環境をあまりいじらずにQ4Mを入れるだけ。最近うちの会社では(STFでも)次のスクリプトを使ってQ4Mを既存のMySQLとは別に入れてるyo。</p>

<pre><code>#!/bin/sh
set -e

MYVER=5.1.60
Q4MVER=0.9.5

CDIR=$(cd $(dirname $0) &amp;&amp; pwd)
cd /usr/local/src

if [ ! -f mysql-$MYVER.tar.gz ]; then
    wget http://downloads.mysql.com/archives/mysql-5.1/mysql-$MYVER.tar.gz
fi

if [ -d mysql-$MYVER ]; then
    rm -rf mysql-$MYVER
fi
tar zxf mysql-$MYVER.tar.gz
cd mysql-$MYVER
# /usr/local/q4m 以下に導入
./configure \
    --prefix=/usr/local/q4m \
    --with-mysqld-ldflags="-static" \
    --with-client-ldflags="-static" \
    --enable-assembler \
    --enable-thread-safe-client \
    --with-charset=utf8 \
    --with-zlib-dir=bundled \
    --with-big-tables \
    --with-mysqld-user=nobody \
    --with-pic \
    --with-extra-charsets=all \
    --with-readline \
    --without-debug \
    --enable-shared \
    --with-fast-mutexes \
    --with-comment="Q4M" \
    --with-server-suffix="-q4m" \
    --with-unix-socket-path="/tmp/mysql_q4m.sock" \
    --with-tcp-port=13306 \
    --with-plugins=none \
    --without-plugin-daemon_example \
    --without-plugin-ftexample \
    --without-plugin-archive \
    --without-plugin-blackhole \
    --without-plugin-example \
    --without-plugin-federated \
    --without-plugin-innobase \
    --without-plugin-innodb_plugin \
    --without-docs \
    --without-man
make
make install

mkdir -p /usr/local/q4m/etc
cp $CDIR/my.cnf /usr/local/q4m/etc
cp $CDIR/q4m.init /etc/init.d/q4m
chmod 755 /etc/init.d/q4m
chkconfig --add q4m

/usr/local/q4m/bin/mysql_install_db --defaults-file=/usr/local/q4m/etc/my.cnf
chmod 755 /usr/local/q4m/var
/etc/init.d/q4m start

cd /usr/local/src
if [ ! -f q4m-$Q4MVER.tar.gz ]; then
    wget http://q4m.kazuhooku.com/dist/q4m-$Q4MVER.tar.gz
fi
if [ -d q4m-$Q4MVER ]; then
    rm -rf q4m-$Q4MVER
fi
tar zxf q4m-$Q4MVER.tar.gz
cd q4m-$Q4MVER
CPPFLAGS="-I/usr/local/q4m/include/mysql" CFLAGS="-L/usr/local/q4m/lib/mysql" ./configure \
    --with-mysql=/usr/local/src/mysql-$MYVER \
    --prefix=/usr/local/q4m
make
mkdir -p /usr/local/q4m/lib/mysql/plugin
cp src/.libs/libqueue_engine.so /usr/local/q4m/lib/mysql/plugin/
cat support-files/install.sql | /usr/local/q4m/bin/mysql -S /tmp/mysql_q4m.sock
</code></pre>

<p>my.cnfやinitスクリプトなどソースはすべて<a href="https://github.com/kazeburo/mysetup">github</a>で公開中。使う時は</p>

<pre><code>$ git clone git://github.com/kazeburo/mysetup.git
$ cd mysetup/q4m
$ sudo sh ./setup.sh
</code></pre>

<p>するだけ！</p>

<p>これをと使うと、 <code>/usr/local/q4m</code> 以下にMySQLとQ4Mを入れて、mysqldのデーモンが起動する。データも <code>/usr/local/q4m</code> 以下に入る。ポートは <code>13306</code> がデフォルトだ。Q4M専用MySQLという位置付けなのでInnoDBは入らないのが注意点。</p>

<p>initスクリプトもインストールするので、</p>

<pre><code>$ sudo /etc/init.d/q4m start|stop|restart
</code></pre>

<p>もできる。簡単。</p>

<pre><code>$ /usr/local/q4m/bin/mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 446907
Server version: 5.1.58-q4m-log Q4M

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
    and you are welcome to modify and redistribute it under the GPL v2 license

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
</code></pre>

<p>ちなみにCentOSだけで確認しています(_ _)。Macの開発環境は<a href="http://blog.livedoor.jp/xaicron/archives/53380670.html">xaicronのスクリプト</a>を使えば簡単、サーバのセットアップは今回ば簡単。これでQ4Mを使わない理由はなくなったね！</p>

<p>蛇足。最近rpmつくるの面倒でこんなscript書いて済ましていることが多い。そういうネタの一つでした。githubでそのうちいくつか公開していくかもしれません。以上。</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/12/q4m---mysql-casual-advent-calendar-2011.html</feedburner:origLink></entry>

<entry>
    <title>GrowthForecastというグラフ表示ツールで捗る話</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/TuD4Us_0Dx4/growthforecast.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.150</id>

    <published>2011-12-01T09:12:42Z</published>
    <updated>2011-12-01T13:05:46Z</updated>

    <summary>Kansai.pmのLTでも紹介したんだけど、APIを叩く事でグラフを更新するツ...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>Kansai.pmのLTでも紹介したんだけど、APIを叩く事でグラフを更新するツールを書きました。話の発端としては「cloudforecastのグラフを外からAPIで更新したい」ということでしたが、cloudforecastではグラフの追加が重い処理になってしまうので、別のプロダクトとしています。</p>

<p>サーバの負荷などのメトリクスを収集し、グラフ化することで、システムに掛かっている負荷を把握し、パフォーマンスに影響がでるまえに対策をうったり、改善の結果を知る事ができますが、同じ事はシステムだけではなく提供しているサービスの動向を確認したり、サービスの改善の結果を知ることにも言えると思います。GrowthForecastは数値だけではくグラフでこのような変化を見やすくする為のツールとして利用することができます。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="growth1.png" src="http://blog.nomadscafe.jp/2011/12/01/growth1.png" width="487" height="566" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>↑画面はこんな感じ。</p>

<h2>API</h2>

<p>APIはむちゃくちゃ簡単で、</p>

<pre><code>http://example.com/api/:service_name/:section_name/:graph_name
</code></pre>

<p>というURLにPOSTでデータを送るだけです</p>

<p>もし、忍者取り合いっていうサービスのアイテムの中の手裏剣が売りたい数だったら</p>

<pre><code>POST http://example.com/api/ninjyatoriai/items/syuriken_no_ureta_kazu
</code></pre>

<p>となります。utf8でればURIに日本語も使えます。送るパラメータは</p>

<table border="1" style="width:90%; margin: 0px auto 10px">
<tr>
<th>パラメータ</th>
<th>説明</th>
<th>必須/オプション</th>
</tr>
<tr>
<td>number</td>
<td>グラフに与える数値</td>
<td>必須</td>
</tr>
<tr>
<td>mode</td>
<td>登録済みの数値を number の値で加算する時には mode=count とします。<br />
通常は number の数値で常に上書きます。</td>
<td>オプション</td>
</tr>
</table>

<p>この2つとなります。</p>

<p>LWP::UserAgent を使うと以下のように書けます。</p>

<pre><code>my $ua = LWP::UserAgent-&gt;new;
$ua-&gt;post('http://example.com/api/ninjyatoriai/items/syuriken_no_ureta_kazu', {
    number =&gt; 10,
});
</code></pre>

<p>送信したデータは一度SQLiteのDBに貯められ、5分毎にグラフ用のRRDデータを更新します。5分毎、30分毎、1時間毎など任意のタイミングでAPIを叩くとよいでしょう。</p>

<h2>グラフ</h2>

<p>データを投稿してから5分ぐらい待つとグラフが描かれます</p>

<p>以下は、2分毎に date +&#39;%M&#39; の結果をmode=countで送って描いたグラフ。上の２つは32時間と1週間のグラフです。modeがcountなので一方向に増えて行ってます。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://blog.nomadscafe.jp/2011/12/01/graph2.png"><img alt="graph2.png" src="http://blog.nomadscafe.jp/assets_c/2011/12/graph2-thumb-500x227-109.png" width="500" height="227" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>GrowthForecastははグラフデータを更新する際に、前回との差分も取っているので、2行目のような差分グラフも表示できます。</p>

<p>差分グラフの表示、非表示グラフの色、単位などはWeb上のUIから変更可能です。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="graph3.png" src="http://blog.nomadscafe.jp/2011/12/01/graph3.png" width="430" height="389" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<h2>複合グラフ</h2>

<p>もう一つ、GrowthForecastの機能で、複数のデータを１つのグラフにまとめて表示できる機能があります。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://blog.nomadscafe.jp/2011/12/01/graph4.png"><img alt="graph4.png" src="http://blog.nomadscafe.jp/assets_c/2011/12/graph4-thumb-500x159-112.png" width="500" height="159" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>これは先ほどのdateを送っているグフラの差分データの上に別のデータを3つ重ねています。</p>

<p>複合グラフの編集もWeb UIからプレビュー表示付きで出来ます。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://blog.nomadscafe.jp/2011/12/01/graph5.png"><img alt="graph5.png" src="http://blog.nomadscafe.jp/assets_c/2011/12/graph5-thumb-500x511-114.png" width="500" height="511" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>GrowthForecastの使い方として、エンジニアが手間をかけずにとりあえずあるサービスのデータを送るcronを設置しグラフ化、ディレクタや他のエンジニアがそれを確認しつつ、差分表示したり、グラフを重ねたりし、サービスが今どんな状態を知り、改善し、またその改善の結果を簡単に確認するというのがいいんじゃないかなと思います。弊社では既に導入されて使われています</p>

<p>GrowthForecastはYappo氏のアイディア+プロトタイプが元になってます。捗るツールの神ですね!</p>

<h2>インストール方法</h2>

<p>これまでRRDToolをインストールするのがなかなか困難でしたが、gfxがAlien::RRDToolを作ったのでだいぶ楽になりました。</p>

<pre><code>$ wget http://search.cpan.org/CPAN/authors/id/G/GF/GFUJI/Alien-RRDtool-0.0*_**.tar.gz
$ cpanm Alien-RRDtool-0.0*_**.tar.gz
</code></pre>

<p>これでインストールできます。もちろんextlibに入れる事も可能です。pkg-config、gettext、glib、xml2、pango、cairoあたりのライブラリもあわせて必要になります。</p>

<p>あとはGrowthForecast本体をgithubからcloneしてinstalldeps</p>

<pre><code>$ git clone git://github.com/kazeburo/GrowthForecast.git
$ cd GrowthForecast
$ cpanm --installdeps .
</code></pre>

<p>ここまでできたら、あとは起動</p>

<pre><code>$ perl ./growthforecast.pl --port 5125
</code></pre>

<p>5125番ポートでStarletが起動し、定期的にRRDをアップデートするworkerも動きます。データはすべて、GrowthForecast/data以下に保存されます。</p>

<p>簡単ですね!</p>

<h2>使ったソフトウェアなど</h2>

<p>UI</p>

<ul>
<li>jquery</li>
<li>bootstap</li>
</ul>

<p>サーバ側</p>

<ul>
<li>Plack</li>
<li>Starlet</li>
<li>Kossy</li>
<li>DBIx::Sunny</li>
<li>DBD::SQLite</li>
<li>Parallel::Prefork</li>
<li>Parallel::Scoreboard</li>
</ul>

<p>KossyもCPANにあげたので、いつかもうちょっと詳しく書くつもりのよてい</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/12/growthforecast.html</feedburner:origLink></entry>

<entry>
    <title> Kansai.pm #14 に参加して発表しました </title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/MwQYiPLfACU/kansaipm-14.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.149</id>

    <published>2011-11-26T13:12:42Z</published>
    <updated>2011-11-26T13:19:18Z</updated>

    <summary>帰りの新幹線で書いてます。京都は行楽シーズンのピークでホテルとることができずに日...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>帰りの新幹線で書いてます。京都は行楽シーズンのピークでホテルとることができずに日帰りです。</p>

<p><a href="http://atnd.org/events/17949">Kansai.pm #14</a> に参加して、発表を2つほどしてきました。JPAからの講師派遣プログラムの一環となります。</p>

<p>メインのプレゼンは「Web Operations and Perl」というタイトルで、主にlivedoor Blogのバックエンドとcloudforecastの話をしました。</p>

<div style="width:425px" id="__ss_10333012"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/kazeburo/web-operations-and-perl-kansaipm14" title="Web Operations and Perl kansai.pm#14" target="_blank">Web Operations and Perl kansai.pm#14</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10333012" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe> <div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/kazeburo" target="_blank">Masahiro Nagano</a> </div> </div>

<p>もう一つ、予定にはなかったのですがLTをさせて頂きました。資料は急遽行きの新幹線の中で作りました。</p>

<div style="width:425px" id="__ss_10338308"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/kazeburo/2-kansaipm14" title="グラフで捗る話#2 kansai.pm#14" target="_blank">グラフで捗る話#2 kansai.pm#14</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10338308" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe> <div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/kazeburo" target="_blank">Masahiro Nagano</a> </div> </div>

<p>GrowthForecastについては、また別のエントリーとして詳しく紹介したいと思います。</p>

<p><a href="https://twitter.com/#!/kentaro">kentaro</a>氏のAPNs周りの実装のトーク、<a href="https://twitter.com/#!/__papix">papix</a>氏のYAPC::Asiaに行ってきたアツい話、また<a href="https://twitter.com/#!/gardejo">gardejo</a>氏の汎用機で如何にPerlを使うかのLTなど面白く聞かせて頂きました。実はKansai.pmに参加するのは今回で2回目で、1回目は京都に住んでいる際に行った<a href="https://twitter.com/#!/lapis25">lapis25</a>氏のプレゼン中にもあった第六回だったりするのですが、その時と今回と共通して感じた事としてWebサービス以外の場所でもPerlが多く使われているんだなぁということがあります。普段Yokohama.pmに参加したり、社内で会話をしていると、ほぼ全てWebサービスに関連した話となってしまいますが、実際にはもっと広く、メインフレーム・汎用機上のプログラムを処理する為にPerlを使ったいたり、大学の研究で活用されているんだとPerlの裾の広さを感じた次第です。<br />
今回発表したWebサービスの裏側やcloudforecastの話が、参加して頂いた方のほんの少しでもお役に立つと幸いです。</p>

<p>Osaka.pmやKyoto.pmの話題がでていましたが、関西でWebアプリケーションや、システム運用、Perlの話ができる機会がもっと増えることで、東京ではなかなか表に出てきにくい、少し違うPerlの使い方、別の視点での発表が増えて行くといいんじゃないかなぁと思ってます。ペパボさんやmixiが関西に拠点をつくるようなので期待しています。イベントの際はまた声をかけてください。また行きます！　</p>

<p>参加して頂いた皆様++ 会場を貸して頂いたはてな++ JPA++</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/11/kansaipm-14.html</feedburner:origLink></entry>

<entry>
    <title>ISUCONのサンプルアプリケーションのフレームワークだったKossyを単独ディストリビューションにした </title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/Hg6oO5B2Zkg/isuconkossy.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.148</id>

    <published>2011-11-16T10:03:01Z</published>
    <updated>2011-11-16T10:06:43Z</updated>

    <summary>ISUCONのサンプルアプリケーションのフレームワークだったKossyを単独ディ...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p><a href="http://blog.nomadscafe.jp/2011/08/http-load-isucon.html">ISUCON</a>のサンプルアプリケーションのフレームワークだったKossyを単独ディストリビューションにして、いくつか機能追加した。ただしテストはないのでアルファクオリティ。</p>

<p><a href="https://github.com/kazeburo/Kossy">https://github.com/kazeburo/Kossy</a></p>

<p>Plack、Router::Simple、Text::Xslateがベースで、独自のvalidatorが付いている程度のそれほど特徴はないsinatra風フレームワークです。それでもツールや管理画面を作るのに楽だと思う。</p>

<p>スケルトンを作るスクリプトが付いたのでそれを使うサンプル。</p>

<pre><code>% kossy-setup MyApp
% cd MyApp
% plackup app.psgi
</code></pre>

<p>これだけでアプリケーションが起動。</p>

<p>生成されたファイルツリーは</p>

<pre><code>% tree
.
├── Makefile.PL
├── app.psgi
├── lib
│   ├── MyApp
│   │   └── Web.pm
│   └── MyApp.pm
├── public
│   ├── css
│   ├── images
│   └── js
├── t
│   └── 00_compile.t
└── views
    ├── base.tx
    └── index.tx
</code></pre>

<p>lib/MyApp/Web.pmがアプリケーションのクラス、public以下に静的ファイル。views以下にテンプレートを置きます。Web.pmの中身を見ると以下のようになっています。</p>

<pre><code>package MyApp::Web;

use strict;
use warnings;
use utf8;
use Kossy;

filter 'set_title' =&gt; sub {
    my $app = shift;
    sub {
        my ( $self, $c )  = @_;
        $c-&gt;stash-&gt;{site_name} = __PACKAGE__;
        $app-&gt;($self,$c);
    }
};

get '/' =&gt; [qw/set_title/] =&gt; sub {
    my ( $self, $c )  = @_;
    $c-&gt;render('index.tx', { greeting =&gt; "Hello!" });
};

get '/json' =&gt; sub {
    my ( $self, $c )  = @_;
    my $result = $c-&gt;req-&gt;validator([
        'q' =&gt; {
            default =&gt; 'Hello',
            rule =&gt; [
                [['CHOICE',qw/Hello Bye/],'Hello or Bye']
            ],
        }
    ]);
    $c-&gt;render_json({ greeting =&gt; $result-&gt;valid-&gt;get('q') });
};

1;
</code></pre>

<p>filter はアプリケーション内ミドルウェアのような機能です。Plack::Middleware同様、$appをラップして動作します。使うにはdispacherの第二引数に配列のリファレンスとして指定します。</p>

<p>dispacherはget(head)とpostがサポート。</p>

<pre><code>get 'url' =&gt; [フィルター指定] =&gt; code
</code></pre>

<p>という形式でアプリケーションを構築して行きます。codeにはMyAppのオブジェクトとKossy::Connectionのオブジェクトが渡されます。MyAppのオブジェクトはアプリケーションのプロセスが死ぬまで有効、Kossy::Connectionのオブジェクトはリクエスト単位になるので、その辺で使い分けができると思う。</p>

<p>その他のクラスやvalidatorの使い方はPodに書いてみたりしているので、興味があれば見て頂けたらと思います。Kossyはもうすこしアプリケーションを作ってみながら機能追加して行く予定です。</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/11/isuconkossy.html</feedburner:origLink></entry>

<entry>
    <title>cloudforecast に2つの機能追加をしました</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/LqmuSkBg4cY/cloudforecast-2-1.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.147</id>

    <published>2011-11-15T04:11:58Z</published>
    <updated>2011-11-15T04:19:38Z</updated>

    <summary>久しぶりにcloudforecastの本体に機能追加 グラフ作成時に複数のrrd...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>久しぶりにcloudforecastの本体に機能追加</p>

<h3>グラフ作成時に複数のrrdファイル利用</h3>

<p>一つ目は、グラフの定義中に他のrrdのデータを取り込みやすくする為の機能。</p>

<p>今までグラフ定義モジュールのグラフ設定中に</p>

<pre><code>&lt;%RRD%&gt;
</code></pre>

<p>と書くと、それを自動的に該当するrrdファイルのパスへ置換していましたが、これを拡張して</p>

<pre><code>&lt;%RRD_FOR サーバIP:リソース名:オプション %&gt;
</code></pre>

<p>とすることで他のサーバ、他のグラフのデータを楽に読み込めるようになりました。</p>

<p>この機能を利用したのが以下のグラフ。某サーバ群へのnginxのリクエスト数をstackして表示しています</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="cf_stack.png" src="http://blog.nomadscafe.jp/2011/11/15/cf_stack.png" width="497" height="193" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>ちなみにグラフ設定はこんな感じ</p>

<pre><code>DEF:cache1=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache2=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache3=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache4=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache5=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache6=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache7=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache8=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
DEF:cache9=&lt;%RRD_FOR 10.x.x.x:nginx:80:/nginx_status %&gt;:request:AVERAGE
AREA:cache1#003366:cache1
STACK:cache2#1a4775:cache2
STACK:cache3#315983:cache3
STACK:cache4#466a8f:cache4
STACK:cache5#59799a:cache5
STACK:cache6#6a86a4:cache6
STACK:cache7#7992ad:cache7
STACK:cache8#869db5:cache8
STACK:cache9#92a7bc:cache9
</code></pre>

<p>プラグイン（リソース定義モジュール）を作成する必要がありますが、これで合計値などのグラフ作成が可能となりました。</p>

<h3>rrdupdate時のtimestamp指定</h3>

<p>もう一つの機能追加はrrdupdateする際のtimestampの指定。</p>

<p>他のところで集計されたデータをcloudforecastに取り込む際に、そのデータが5分、10分前のものとなる可能性があります。いままでcloudforecastは収集されたデータを常に現在のデータとして扱っていましたが、timestampによっていつの時点のデータなのか指定することができます。</p>

<p>使うには、プラグイン（リソース定義モジュール）のfetcherからデータを戻す際に配列をもう一回配列でラップし、2番目の要素にtimestampを入れます</p>

<pre><code>fetcher {
    my $c = shift;
    my $res = $ua-&gt;get(..);
    ...
    return [[$in,$out],time-600];
};
</code></pre>

<p>上記の例では、保存するデータは600秒(10分)前のものとなります。timestampに使える形式は、<a href="http://oss.oetiker.ch/rrdtool/doc/rrdupdate.en.html">rrdupdateのドキュメント</a>を確認してください。</p>

<p>livedoorではこの2つの機能を使って、CDNと自社トラフィックのグラフをあわせて表示したりしています。</p>

<p><br />
<br /></p>

<p><a href="http://blog.nomadscafe.jp/2011/11/kansaipm.html">kansai.pm</a>でもcloudforecastのことを少し話す予定です〜</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/11/cloudforecast-2-1.html</feedburner:origLink></entry>

<entry>
    <title>WEB+DB PRESS Vol.65 Perl Hackers Hubに寄稿しました </title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/MB1NudsxnlU/webdb-press-vol65-perl-hackers-hub.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.146</id>

    <published>2011-11-01T15:54:46Z</published>
    <updated>2011-11-01T15:57:56Z</updated>

    <summary>ちょっと書くのが遅くなったけど、技術評論社さんのWEB+DB PRESS でやっ...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>ちょっと書くのが遅くなったけど、技術評論社さんのWEB+DB PRESS でやってるPerlリレー連載に記事をかきました。</p>

<iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&bc1=000000&IS2=1&nou=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=nomadscafejp-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=ss_til&asins=477414830X" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>

<p>内容は<a href="http://blog.nomadscafe.jp/2011/10/yapcasia-tokyo-2011.html">YAPC::Asia Tokyo 2011</a>や<a href="http://blog.nomadscafe.jp/2011/05/yokohamapm7.html">Yokohama.pm#7</a>でも喋ったログの話題。Logの考え方、Log系のモジュールの比較と<a href="https://metacpan.org/module/Log::Minimal">Log::Minimal</a>の紹介という内容になっています。読んで頂ければと思います。</p>

<p>あと、今回のWEB+DB PRESSの第一特集では、「WEBエンジニアが知るべき インフラの基礎知識」という記事がかかれています。内容は</p>

<ul>
<li>レイヤとハードウェア、ミドルウェアの整理</li>
<li>TCP/IP入門</li>
<li>サーバの負荷について、負荷の正体を突き止める指標とツール</li>
<li>サービス監視とリソース監視</li>
</ul>

<p>といった事柄が盛り込まれています。自分自身の復習に、またエンジニアに説明をする際に使えそうなネタ満載です。ぜひこちらも読んでもらえるといいと思います</p>

<p>あわせて読みたい</p>

<ul>
<li><a href="http://blog.nomadscafe.jp/2011/03/web.html">Webアプリケーションエンジニアに知っていて欲しいインフラの知識</a></li>
<li><a href="http://blog.nomadscafe.jp/2010/11/post-9.html">ログレベルの使い分け方/コミュニケーション手段としてのログ</a></li>
</ul>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/11/webdb-press-vol65-perl-hackers-hub.html</feedburner:origLink></entry>

<entry>
    <title>Kansai.pm に参加します！</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/nomadscafejp/~3/raIWr8zbeB4/kansaipm.html" />
    <id>tag:blog.nomadscafe.jp,2011://1.145</id>

    <published>2011-11-01T07:06:52Z</published>
    <updated>2011-11-01T07:07:28Z</updated>

    <summary>11/26 に行われる「Kansai.pm 第14回ミーティング in 京都」に...</summary>
    <author>
        <name>Masahiro Nagano</name>
        <uri>http://blog.nomadscafe.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://blog.nomadscafe.jp/">
        <![CDATA[<p>11/26 に行われる「Kansai.pm 第14回ミーティング in 京都」に参加しまっす。</p>

<p>atnd: <a href="http://atnd.org/events/17949">http://atnd.org/events/17949</a></p>

<p>今回はJPAの協賛付きです！</p>

<p>livedoor blogの運用やcloudforecastの話をする予定です。Perlを使ってWebアプリケーションの運用を楽にしたり、パフォーマンス改善に繋がるTipsを紹介できればと思います。</p>

<p>会場は京都のはてなさんのオフィスです。関西周辺のかた、よろしくおねがいします！ぜひ来てくださいませー。</p>
]]>
        

    </content>
<feedburner:origLink>http://blog.nomadscafe.jp/2011/11/kansaipm.html</feedburner:origLink></entry>

</feed>

