YAPC::Asiaの前にDBIx::DSN::Resolverってのを書いてリリースしていますが、実際のWebアプリケーションで使うにはキャッシュやDNSRR対応などアプリケーション側でコードを書く必要があって面倒なので、簡単に使えるようラッパーとなるモジュールを書いてリリースしました。
https://metacpan.org/module/DBIx::DSN::Resolver::Cached
DBIx::DSN::Resolver::Cached を使うことでDNSに掛かる負荷を押さえつつ簡単に負荷分散もできます。
use 5.10.0;
use DBIx::DSN::Resolver::Cached;
sub connect_db {
state $r = DBIx::DSN::Resolver::Cached->new(
ttl => 30,
negative_ttl => 10
);
$resolver->resolv('dbi:mysql:database=mytbl;host=mixi.jp');
}
say connect_db() for 1..10;
ホスト名解決の結果をキャッシュしつつ、複数のIPが返って来た時はラウンドロビンで使うIPアドレスを選ぶので、上のサンプルを実行すると
dbi:mysql:database=mytbl;host=110.44.x.198
dbi:mysql:database=mytbl;host=110.44.x.199
dbi:mysql:database=mytbl;host=114.31.x.33
dbi:mysql:database=mytbl;host=110.44.x.196
dbi:mysql:database=mytbl;host=110.44.x.197
dbi:mysql:database=mytbl;host=114.31.x.34
dbi:mysql:database=mytbl;host=110.44.x.200
dbi:mysql:database=mytbl;host=114.31.x.32
dbi:mysql:database=mytbl;host=110.44.x.198
dbi:mysql:database=mytbl;host=110.44.x.199
のようになります。名前解決の問い合わせを1度しかしていないのはstraceなどを使うと確認できます。
DBIx::DSN::Resolver::Cached はデフォルトで、Cache::Memory::Simple を使っていますが、これを差し替える事も可能です。
state $r = DBIx::DSN::Resolver::Cached->new(
cache => Cache::Memcahced::Fast->new(..),
);
このようにすればmemcachedも使えます。
ちなみに、mobageはMyDNSを使ってDNSベースの負荷分散を実現しているようですが、弊社ではMySQLバックエンドなPowerDNSが使えるようになっています
Weighted RoundRobinや負荷分散先のサーバが落ちた時の処理などはこのモジュールではサポートしていません。もっと細かくやりたい場合は DBIx::DSN::Resolver で resolver を弄ったほうが捗ると思います。