読者です 読者をやめる 読者になる 読者になる

Perl日記

PerlとかRubyとかPHPとかPythonとか

memcachedやってみた2

memcachedやってみた1 - Perl日記の続き。
じゃあPerlで接続してみる。
CPANからCache::Memcached::Fastをインストールして使う。

#!/usr/bin/perl
# test.pl
use strict;
use warnings;

package Memcached;
use base qw/Cache::Memcached::Fast/;
my $cache;
sub new {
  my $class = shift;
  $cache ||= $class->SUPER::new(
    {servers => ['127.0.0.1:11211']} # memcached接続情報
  );
  return $cache;
}

package main;
my $mem = Memcached->new();
my $key   = 'myid';
my $value = 'rightgo09';
$mem->set($key, $value);
print $mem->get($key), "\n";
% ./test.pl
rightgo09

できた。
また、set()メソッドにはオプションの第3引数で有効期限(秒)が設定できる。

my $mem = Memcached->new();
my $key    = 'myid';
my $value  = 'rightgo09';
my $expire = 10; # 10秒保存
$mem->set($key, $value, $expire);
print $mem->get($key), "\n";
sleep 5;
print $mem->get($key), "\n";
sleep 6;
print $mem->get($key), "\n";
% ./test.pl
rightgo09
rightgo09

OK。
次はどのくらい早くなったのか、mysqlと比較しようと思ったけれど、いろいろ設定いじりすぎて今動かないのでDBD::CSVで代用。
1〜10までの値をMD5_hexに変換して格納し、取得速度を比較。

#!/usr/bin/perl
# memcached_bench.pl
use strict;
use warnings;
use Benchmark qw/timethese cmpthese/;

package Memcached;
use base qw/Cache::Memcached::Fast/;
my $cache;
sub new {
  my $class = shift;
  $cache ||= $class->SUPER::new(
    {servers => ['127.0.0.1:11211']} # memcached接続情報
  );
  return $cache;
}

package main;
use List::Util qw/shuffle/;
use Digest::MD5 qw/md5_hex/;
use DBI;
my $dbh = DBI->connect("DBI:CSV:f_dir=testdb")
  or die "Cannot connect: " . $DBI::errstr;
$dbh->do("CREATE TABLE test_table (id INTEGER, hex CHAR(64))")
  or die "do: "      . $dbh->errstr();
my $sth = $dbh->prepare('INSERT INTO test_table VALUES (?, ?)')
  or die "prepare: " . $dbh->errstr();

my $mem = Memcached->new();

# Key-Value Store
my $max = 10;
for my $id (1 .. $max) {
  my $md5_hex = md5_hex($id);
  $sth->execute($id, $md5_hex) # DBD::CSV
    or die "execute: " . $dbh->errstr();

  $mem->set($id, $md5_hex); # Memcached
}

my $val_by_csv;
$sth = $dbh->prepare('SELECT hex FROM test_table WHERE id = ?')
  or die "prepare: " . $dbh->errstr();

my $val_by_memcached;
   
# Benchmark
cmpthese(
  timethese(
    10_000,
    {
      'DBD::CSV' => sub {
        for my $id (shuffle(1 .. $max)) {
          $sth->execute($id)
            or die "execute: "      . $dbh->errstr();
          $sth->bind_columns(\$val_by_csv)
            or die "bind_columns: " . $dbh->errstr();
          $sth->fetch()
            or die "fetch: "        . $dbh->errstr();
        }
      },
      'Memcached' => sub {
        for my $id (shuffle(1 .. $max)) {
          $val_by_memcached = $mem->get($id);
        }
      },
    },
  )
);
$dbh->disconnect();
__END__
% ./memcached_bench.pl
Benchmark: timing 10000 iterations of DBD::CSV, Memcached...
  DBD::CSV: 79 wallclock secs (75.81 usr +  2.91 sys = 78.72 CPU) @ 127.03/s (n=10000)
 Memcached: 14 wallclock secs ( 1.19 usr +  2.88 sys =  4.07 CPU) @ 2457.00/s (n=10000)
            Rate  DBD::CSV Memcached
DBD::CSV   127/s        --      -95%
Memcached 2457/s     1834%        --

うわはやい。
やっぱりCSVファイルからなんかじゃ比べものにならないな。
ちなみに使用マシンのスペックは、

最初は$maxを500にしてやったんだけど、DBD::CSVの方が30分経っても終わらなかった。
Memcachedだけにしてやったら48秒で終わった。


でもまあここまでならハッシュでもできる話ではある。
(メモリ上に残しておく、ということはできないけれど)
今度はこれをどう使えばいいか考えてみたい。
ミーハーだなあ僕。