DBIx::Skinny::Schema::Loader 0.16 released
YAPC楽しいけど、自分の無力さにめげそうになるよねー、ということで少しでも抵抗しようと思って講堂前で書きました。
make_schema_atにignore_rulesオプションを渡してやることで、schema出力の対象から除外するテーブルを指定出来るようになりました。
my $schema = make_schema_at( 'MyApp::DB::Schema', { ignore_rules => [ qr/rs$/, qr/^no/ ], }, [ $dsn, $username, $password ] ),
のように、正規表現リテラルをArrayRefに入れて指定します。
月毎のテーブルを作ってログを記録しているようなDBを扱う時にあるとちょっと便利かも知れません。
DBIx::Skinny::Schema::Loader 0.15 released
今まで、Loaderのprimary keyに関する動作は
- DB上でpkが指定されていればそれを使う
- idというカラムがあればpkとみなす
- いずれにも合致しなければエラー
というロジックだったのですが、いずれにも合致しない、つまりpkが無い場合は未定義のまま動作するように変更しました。
初期のDBIx::Skinnyではprimary keyが存在しないテーブルを扱うことを想定していなかったため、Loader側でそのようなschemaを吐かないようにチェックしていました。
今では、というかかなり前から本体側でそういったケースもフォローしているので、Loader側も今更ながら追従したという流れです。
Test::More 0.95_01以降ではsubtest毎にdone_testingって書かなくてもOK
昨日Twitterにふらっと投げたらreply付いたので、せっかくだからブログに書いておく。
何気なくTest::MoreのPodを読んでいると、
This adds an implicit done_testing() to the end of your subtest. The following two subtests are equivalent:
http://search.cpan.org/~mschwern/Test-Simple-0.96/lib/Test/More.pm
subtest 'subtest with implicit done_testing()', sub { ok 1, 'subtests with an implicit done testing should work'; ok 1, '... and support more than one test'; ok 1, '... no matter how many tests are run'; }; subtest 'subtest with explicit done_testing()', sub { ok 1, 'subtests with an explicit done testing should work'; ok 1, '... and support more than one test'; ok 1, '... no matter how many tests are run'; done_testing(); };
なんて記述を見つけて、done_testing書かないと怒られるやんと思ってたら、0.95_1のChangelogに記述が。
New Features
http://cpansearch.perl.org/src/MSCHWERN/Test-Simple-0.96/Changes
* subtests without a 'plan' or 'no_plan' have an implicit 'done_testing()' added to them.
ということで、書かなくてもよくなっていたようです。
どうせなら$setupとか$teardownにcoderefを突っ込んでおけば勝手に呼んでくれたりすればもっと便利だと思うのですが、それはTest::Class使えよってことになるかも知れない。
skip-name-resolveでMySQLへの接続がどの程度速くなるのか試してみた
を見て、実際のところどの程度性能に影響があるのか気になったのでベンチを取ってみた。
ベンチマークスクリプトはhttp://gist.github.com/594839で、connect -> disconnectを1000回繰り返すのにかかった時間を計測。
■計測結果
環境の詳細は後述するとして、まずは結果から。手動で何回か実行して、結果のボリュームゾーンを感覚的に抽出。
環境 | 実行時間(秒) |
---|---|
skip-name-resolve | 1.73 〜 1.74 |
hosts | 1.75 〜 1.76 |
DNS | 2.26 〜 2.29 |
/etc/my.cnfでskip-name-resolveを有効にした場合、確かに速くて、DNSで名前解決するよりも0.5秒ぐらい速くなる。1回あたり0.5msecをどう見るかはケースバイケースだが、DB接続だけでこれだけ変わるのであれば採用したいなと思った。
ただ、hostsで名前解決が出来る場合はほとんど誤差程度の違いしか見られなかった。繰り返しテストすると確かにskip-name-resolve使用時の方が速い傾向が出るが、必ず毎回そうなるわけではなく、hostsの方が速いこともあった。
MySQL公式の「6.5.6. MySQLの DNS の使用」によれば、
オペレーティングシステムがスレッドセーフの gethostbyaddr_r()とgethostbyname_r()の呼び出しをサポートしている場合、スレッドではこれを使用してホスト名の解決が実行される。
とあるが、この呼び出しを省略することによるパフォーマンス向上はそれほど大きくはない印象です。
どちらかと言えば、hostsとDNSでこれぐらい差が付くんだなーということの方が印象的なテストになった。DNSはdnscache(djbdns)を使っているが、これがbindだったりunboundだった場合にどうなるかは調べていない。
内部で多数の通信が必要なアプリケーションでは、多少面倒でもhostsで名前解決するような運用にした方が有利なのかな。あと、クライアントでのDBサーバの名前解決はhostsに書いてるんだけど、これをDNS参照すると0.3秒ぐらい遅くなった。
skip-name-resolveを有効にすると、「localhost」も名前として使えなくなるらしいので注意が必要。MySQLはlocalhostはソケットで、127.0.0.1はTCPで接続しているようなので、そこを厳密にしたい場合は使えないと思われます(以前、mysqld_multiで接続をうまく使い分けてくれなくて、localhostと127.0.0.1が同じ物だという前提に基づいたアプリが問題だったことがある)。このへんはあまり興味ないので全く調べてない。
■実施環境
DB server
OS | CentOS5.5 |
---|---|
CPU | Xeon X3330 (4core 2.66GHz) (C2Q相当) |
memory | DDR2 8GB |
MySQL | 5.1.49 + InnoDB plugin |
memo | clientとは別の物理サーバ |
network
- 100Mの古い安物ハブ
- GbEなら改善されるかも
■まとめ
- DNSで名前解決するならskip-name-resolveは検討の価値あり
- hostsだと誤差程度の差なので、skip-name-resolveその物はそんなに速さに貢献しない
- hostsとDNSの差が思った以上にあるので、積極的にhostsに書いていきたい
- 個人的にはhostsをPuppetで配布するアプローチで必要十分な感がある
(追記)ベンチマークスクリプトをDBサーバで実行したら、0.41〜0.48秒ぐらいでした。名前解決はhostsでプライベートIPを指定。ネットワークの差か、CPUの差か。多分CPUの差だと思うけど、機材が足りなくて検証出来ません。
(追記2)DBサーバからプライベートIPをDNSで名前解決させたら0.74〜0.78秒ぐらい。hostsの方が速いけど、最初のテスト環境よりも差は小さい。DNSサーバを高スペックな物にすれば更に差は縮まるような気がしてきました。まぁでも、この差が気になる環境だと内部のトラフィックを減らすためにhosts書くメリットが大きいんじゃないかな。
ASUS P7F-MでデュアルコアCPUを使用する場合はECCメモリが必須
ASUS P7F-Mという、MicroATXで内蔵VGA搭載、INTEL NIC2ポート(と別口1つで合計3ポート)搭載でSocket 1156の「省スペースサーバ自作しろってことですね分かります」的なマザーがあるんですが、これが意外と厄介だったのでメモ。
(ECCメモリはxeon3400シリーズ使用時のみ使用可)
(xeon L3406使用時はRDIMMは使用できません)
なんて注意書きがありますが、実際に購入する際にはメモリにもっと気を遣う必要があります。
asus.comにあるCPU Support Listを見ると、i3, i5, i7, Xeon L or X 3400番台と広くサポートしていますが、注目は「QVL」のタグにある内容。そもそもQVLってのが何なのか分からないのだけど、開いてみると「Qualified Vendor List」とのこと。業界じゃ常識なんだろうか。
で、ここに上がってるAVL(これも何だか分からないがApproved Vendor Listらしい)をダウンロードしてきて確認。何故かRARアーカイブで提供されているファイルを展開して中のPDFを見ると、対応しているCPUとメモリの対応表が。要約すると、
i3, i5, Xeon L3406とかデュアルコアCPUはnon-ECCメモリ対応してねーよ。あとRDIMMも知らねー
と書いてあります。4コアのi5, i7やXeon X3400番台ならnon-ECCもサポートしているらしいですが、2コアのCPUだとECCメモリを差さないとBIOSすら起動しません。これ、もっとちゃんとアナウンスしておくべきだと思うんだけどな。もしかして常識なんでしょうか。
「DDR3も安くなってきたし、i3使ってお得なサーバ組めるんじゃね?」とか考えてると足下をすくわれたりするのでご注意を。
Path::AttrRouterのControllerをextendsする時はBEGINで(って書いたけどやっぱり '-extends' で)
Path::AttrRouterを使うのに、
package MyController; use Any::Moose; extends 'Path::AttrRouter::Controller'; sub index :Path Args(0) { } 1;
みたいに書くと「Error while loading app.psgi: Invalid CODE attributes:」とか怒られてどうすればいいんだろう。
と思って#perl-casualで聞いてみたら、JPAの牧さんがあっさり「それBEGIN {}でできるよ」と解決してくれました。
package MyController; use Any::Moose; BEGIN { extends 'Path::AttrRouter::Controller' }
のように、extendsをBEGINでくくってやれば無問題。use baseはコンパイル時に評価されるけど、extendsは実行時なのでこれが必要らしいです。
catamooseが出た時にBEGINでどうこうって話が出て他のはこれだったのか。2010年にもなって引っかかってすいません。
ちょっと記述としては冗長だなと思うけど、
これがRoleとの関連で不採用になったりと、いろいろと経緯があったようです。
そんな疑問があっさり解決したり、関連トピックがいろいろ聞ける#perl-casualマジお勧め。
こういうショボい質問も皆が優しく教えてくれるので、Perl使ってる人はirc.freenode.netに今すぐアクセスした方がいいですよ。
(追記)Path::AttrRouterについては
package MyController; use Any::Moose; use Path::AttrRouter::Controller '-extends';
って書けばBEGINとか使わなくてもいいそうです。typester++
ソースはちゃんと読んで理解しないとダメってことすね。
Moose, Mouse, Class::Accessor::Fastのアクセサでベンチマーク取ってみた
「馬鹿にできないアクセサのオーバーヘッド - Craftworks Tech Blog - Branch」にもあるように、Mooseのアクセサによるオーバーヘッドは無視するにはちょっと大きいという印象があります。
じゃあ、Mouseだったらどうなんだろうとか、自分が使うサーバのスペックも随分上がったしとか、そういう経緯で改めてベンチを取ってみました。コードは@Craftworksさんの物にMouseを足しただけ。以下に貼り付けておきます。
で、こいつをXeon X3330@2.66GHzで走らせた結果が以下(cmp_these部分のみ)。
Rate moose_ro moose_rw caf_rw mouse_ro mouse_rw mouse_direct moose_direct caf_direct moose_ro 297030/s -- -8% -28% -66% -68% -82% -83% -89% moose_rw 322581/s 9% -- -22% -63% -66% -81% -82% -88% caf_rw 410959/s 38% 27% -- -53% -56% -75% -77% -85% mouse_ro 882353/s 197% 174% 115% -- -6% -47% -50% -68% mouse_rw 937500/s 216% 191% 128% 6% -- -44% -47% -66% mouse_direct 1666667/s 461% 417% 306% 89% 78% -- -6% -39% moose_direct 1764706/s 494% 447% 329% 100% 88% 6% -- -35% caf_direct 2727273/s 818% 745% 564% 209% 191% 64% 55% --
Mouse速すぎワロタ。Class::Accessor::Fastに対して2倍以上という好成績。そもそも一番遅いMooseでも秒間30万回ぐらい呼べているので、そんなに気にすることは無いかなという印象ですね。
なお、MOUSE_PUREPERL=1で実行するとこんな感じ。
Rate mouse_ro moose_ro moose_rw mouse_rw caf_rw moose_direct mouse_direct caf_direct mouse_ro 297030/s -- -7% -13% -14% -29% -82% -83% -89% moose_ro 319149/s 7% -- -6% -7% -23% -81% -82% -88% moose_rw 340909/s 15% 7% -- -1% -18% -80% -81% -87% mouse_rw 344828/s 16% 8% 1% -- -17% -79% -80% -87% caf_rw 416667/s 40% 31% 22% 21% -- -75% -76% -85% moose_direct 1666667/s 461% 422% 389% 383% 300% -- -6% -39% mouse_direct 1764706/s 494% 453% 418% 412% 324% 6% -- -35% caf_direct 2727273/s 818% 755% 700% 691% 555% 64% 55% --
XS化による効果の程が分かるというものですね。@__gfx__++