T

memcached(repcached)のデータをバックアップ

memcachedの評価中に、対障害性を高める方法についてあれこれ考えていたのだが、あまりいい案が浮かばなった。

とりあえずストレージの冗長化であればrepcachedでなんとかなる。でも、memcachedのストレージがいっぱいになったらアクセスの古いデータから順に捨てられるので、予想を超える事態になったときにそれを検知してなんとかDBにでも保存しておく方法はないものかと考えたのだが、なかなかスマートな解決方法がない。

たとえば、セッション情報をmemcachedに保存しているとする。期限が設定されていたら、少なくともその間はデータを保持したい。でも、データ量が予想を上回ると上記のロジックで古いセッションが破棄されてしまう。よほどケチった予想をしていない限りは実害はほとんどないのかもしれないが、保障されているセッションの期限が守れない可能性があるのは変わりない。

そこで、現在memcachedのストレージ上に保存されているデータを定期的にDBにバックアップできないかと考えた。でも、よく考えたら、セッションのユニークIDをキーにしてデータを保存している場合、現在どんなIDが保存されているのかを知る方法がどこにもない。RDBMSだと取得先テーブル名はたいていわかるので、条件を書けばいくらでもデータを取得できるが、そもそも前提となる条件がユニークIDであるセッションのような情報だと難しい。

RDBMS風にいえばこんな感じ。
  table      |  data                                        |
----------+----------------------------------+
  yagi       | I still consider myself rather likable |
----------+----------------------------------+
  soey      | Size don't matter                     |
----------+----------------------------------+
  chobee   | Baseball games are like snowflakes |
----------+----------------------------------+

そこで、memcached上にシーケンステーブルのようなものを用意してみた。セッションの期限は24時間だから


$myname = 'yagi';
$mydata = 'I still consider myself rather likable.';

$today = date("Y-m-d", time());
$new_id = $today . '_' . $memcached->increment($today);

$memcache->set($new_id, $myname);
$memcache->set($myname, $mydata);

これで、RDBMS風にいえば

sequence_name | last_value | increment_by |
----------------+-----------+--------------+
2009-02-06       |            1  |                 1 |

id                  | myname |
--------------+---------+
2009-02-06_1 |       yagi |

myname | mydata                                      |
---------+----------------------------------+
   yagi    | I still consider myself rather likable |

みたいなテーブルが出来たことになる。そこで、


$yesterday = date("Y-m-d", mktime(0, 0, 0, date("m"), date("d") - 1, date("Y")));
$max = $memcache->get($yesterday);
$i = 0;
$data = array();
while($max >= $i){
    $save = $memcache->get($yesterday . '_' . $i);
    if($save){//件数が多すぎたら配列に入れられないけどまあいい
        $data[$save] = $memcache->get($save);
    }
    $i++;
}

という感じでバックアップは取れる。特にセッション情報があまり変わらないアフィリエイトのID保存のような目的に使われる場合は、成果発生時のチェックにmemcachedから読み込んだデータとDBのデータを使えばまあ確実になる。

でも、動くことは動くが1件につき2つのデータが必要になり、効率は悪い。

もっとうまい方法があれば教えてほしいと思うのであった。

Posted by on 2月 6, 2009 in PHP, PostgreSQL

コメントを残す