DBIx::SkinnyでCacheを取ってみたり
業務でSkinnyとmemcacheとShardDBを使ってるんですが兎にも角にもキャッシュやジョブキューで非同期処理などパフォーマンス重視の開発するのが大好きな人たちと仕事してるんですが、DBからとってくきた情報をハッシュ化しておいてからmemcacheに突っ込んで、それを取り出してオブジェクト化するっていう処理を書いたんですが、、、
そんなに速くなるのかいな
と思いました。
でベンチマークを書いてみました。
ちなみに言語はPerlで、O/RマッパーはDBIx::Skinnyです。テストで使用するのはSQLiteにしました。
比較対象
- メモリ上に保存してあるハッシュからDBIx::SkinnyのRowオブジェクトを生成
- memcacheに保存してあるハッシュをとりだしてDBIx::SkinnyのRowオブジェクトを生成
- DBにアクセスしてDBIx::SkinnyのRowオブジェクトを生成
予想
速さは上述の順番になる
ベンチ
#!/usr/bin/env perl use strict; use warnings; use FindBin qw($Bin); use Path::Class qw/dir file/; use Data::Dumper; use Devel::Size qw(size total_size); use lib dir($Bin, '..', 'lib')->stringify; use lib dir($Bin, '..', 'extlib')->stringify; use Shaq::Api::Skinny; use Shaq::Api::Memcached; use Benchmark qw(:all); my $config = { memcache => { namespace => 'eg_', }, skinny => { master => { db_class => 'Proj::DB', connect_info => ['dbi:SQLite:dbname=db/skinny.db'], query_log_path => './logs/skinny_master_query.log', # log_mode => 1, }, slave => { db_class => 'Proj::DB', connect_info => ['dbi:SQLite:dbname=db/skinny.db'], query_log_path => './logs/skinny_slave_query.log', # log_mode => 1, }, } }; my $memcache = Shaq::Api::Memcached->new( $config->{memcache} ); my $skinny = Shaq::Api::Skinny->new( $config->{skinny} ); my $db = $skinny->master_db; # 実験用テーブルを作成 $db->do(q{drop table if exists users}); $db->do(q{ create table users ( id INTEGER PRIMARY KEY AUTOINCREMENT, rid VARCHAR(10) NOT NULL, name TEXT NOT NULL, birth_on DATE, created_at DATETIME, updated_at DATETIME ) }); # INSERT INTO user (name), VALUES ('nekokak'); # を実行して中身のデータを確認 my $row = $db->create('users',{name => 'nekokak'}); print $row->id, "\n"; # print 1 print $row->rid, "\n"; # print 1 print $row->name, "\n"; # print 'nekokak' print $row->created_at, "\n"; print $row->created_at->ymd, "\n"; # datetime object warn size $row; ### skinnyはこうやってオブジェクトからハッシュにできる ### この状態だとmemcacheに保存できる warn Dumper my $hashref = $row->get_columns; $memcache->set( 'key' => $hashref ); warn Dumper $memcache->get('key'); cmpthese timethese 10_000, { 'hash to row' => sub { my $row = $db->data2itr( 'users',[$hashref])->first; }, 'row from db' => sub { my $row = $db->single('users',{id=>1}); }, 'make hash form memcache to row object' => sub { my $hash = $memcache->get( 'key' ); my $row = $db->data2itr('users',[$hash])->first; }, };
キタナイデスネスイマセン
結果
:!perl bench/skinny_cache.pl users at /home/okamura/p5/Shaq/bench/../extlib/Proj/DB.pm line 7. 1 idAF4AdWfD nekokak 2010-02-04T22:09:55 2010-02-04 298 at bench/skinny_cache.pl line 61. $VAR1 = { 'created_at' => '2010-02-04 22:09:55', 'updated_at' => '2010-02-04 22:09:55', 'name' => 'nekokak', 'rid' => 'idAF4AdWfD', 'id' => 1 }; $VAR1 = { 'created_at' => '2010-02-04 22:09:55', 'updated_at' => '2010-02-04 22:09:55', 'name' => 'nekokak', 'id' => 1, 'rid' => 'idAF4AdWfD' }; Benchmark: timing 10000 iterations of hash to row, make hash form memcache to row object, row from db... hash to row: 11 wallclock secs ( 1.88 usr + 8.14 sys = 10.02 CPU) @ 998.00/s (n=10000) make hash form memcache to row object: 10 wallclock secs ( 2.08 usr + 4.44 sys = 6.52 CPU) @ 1533.74/s (n=10000) row from db: 15 wallclock secs ( 0.17 usr + 15.03 sys = 15.20 CPU) @ 657.89/s (n=10000) Rate row from db hash to row make hash form memcache to row object row from db 658/s -- -34% -57% hash to row 998/s 52% -- -35% make hash form memcache to row object 1534/s 133% 54% --
ふむー。予想と違う。どこかで何かを勘違いしているのかな、DBから取り出す処理が一番時間がかかるのは物理的にファイルアクセスするから磁気テープに向かってハードディスクのアームがえっちらほっちらしてるから、つーのはわかるんですが、メモリ上に保存してある(と僕は思っている)ハッシュからオブジェクトをつくるより、memcacheからデータ取り出したほうが高速に動いているのはなぜだろう?
ソースコードの置き場所
http://github.com/okamuuu/Shaq/blob/master/bench/skinny_cache.pl