memcachedの使い方

memcachedについて,書籍を読んで勉強したので使用方法をまとめておく。

memcachedとは

memcachedは,分散メモリキャッシュシステムを構築することができるソフトウェアの一つ。データベースの読み出し結果などをメモリに保存し、次に同じデータが参照されたときにメモリから即座に返すことができる。複数のコンピュータにまたがる巨大な分散キャッシュシステムを構築でき、台数を増やすことで性能を向上させることができるため、大規模なWebサービスなどでよく用いられる。

memcachedの特徴と用途

memcachedは,メモリ上で動作するキー・バリュー型の揮発性データベースである。揮発性なので,memcached自身が停止したり,memcachedが動作しているハードの電源が切れたりすると,memcachedに保存されているデータは消失してしまう。そのため,消えてしまっては困るようなデータを保存することはできない。memcachedはメモリ上にデータを格納するので,非常に高速にデータの書き込み・読み込みを行うことができる。
以上に挙げた特徴から分かるように,memcachedはキャッシュを行うような場面において,その真価を発揮する。memcachedの具体的な用途としては,MySQLやPostgreSQLのようなRDBと組み合わせて,キャッシュ用のデータベースとして使用することで,RDBにかかる負荷を抑えることができる。

コンシステント・ハッシングによる負荷分散

memcachedは,コンシステント・ハッシング(Consistent Hashing)と呼ばれるアルゴリズムによってデータ分割・割り当て(負荷分散)を行う。
このアルゴリズムでは,分散型システムを構成する各ノード(memcached)が,論理的にリング(輪)を形作るように配置される。

以下がコンシステント・ハッシングの図である。

ca537cc7e9a6382858712081366bac651

図では,4つのノード(memcached)を均等に分散配置している。データのキーの値はハッシュ関数によって求められ,ハッシュ関数を使った演算は,不規則な発番(整理番号の付与)を行う方法として広く利用されている。このようにキーの値として,ハッシュ値を得ることによってキーの値が特定の値に偏ることなく,広く均等に拡散するようになる。
そして,その整理番号に従って,リングの各スペースにキーを割り当てる。キーが割り当てられたスペースを時計回りで進み,そこで最初に配置されているノードにデータを書き込む。コンシステント・ハッシングはこのようなルールのアルゴリズムである。

CAS操作によるアトミック性の実現

memcachedにおいて,アトミック性(原子性)を実現するにはCAS操作を行う必要がある。アトミック性とは,トランザクションに含まれるタスクが全て実行されるか、あるいは全く実行されないことを保証する性質をいう。このような性質は,MySQLやPostgreSQLのようなRDBでは標準的に対応しているが,memcachedにおいては,CAS操作と呼ばれる処理を行わなければ,対応することができない。
アトミック性(原子性)が保障されない場合,どのようなことが起こり得るか,簡単な例を示す。
以下の例では,「プロセス1」と「プロセス2」の2つのプロセスが1つのカウンタに対して数値を足している。

プロセス1 現在のカウンタの値を取得する …… カウンタの値:0
プロセス1 カウンタの値を1増やす ……………… カウンタの値:1
プロセス2 現在のカウンタの値を取得する …… カウンタの値:0
プロセス1 カウンタの値を保存する …………… カウンタの値:1
プロセス2 カウンタの値を1増やす …………… カウンタの値:1
プロセス2 カウンタの値を保存する …………… カウンタの値:1

上記の例では,本来はカウンタの値が2になることを期待しているが,最終的にカウンタの値は1になってしまっている。CAS操作を行わない場合はこのようなことが起こり得る。

memcachedの使い方

今回はtelnetからの使用方法と,PHP言語からの使用方法の2つを説明する。
初めに,yumコマンドやapt-getなどのコマンドを使って,memcachedをインストールし,memcachedを起動する。

#memcachedがインストールされているか確認するwhich memcachedsudo find / -name memcached#インストールされていなければ,memcachedをインストールするsudo yum install -y memcached#memcachedのリッスンするポートの変更やメモリの割り当てなどを変更することもできるsudo vi /etc/sysconfig/memcached#memcachedを起動するsudo service memcached start#memcachedが起動したことを確認するps aux | grep memcached#memcachedが自動起動するように設定するsudo chkconfig memcached on

telnetからmemcachedを使ってみる

telnetからmemcachedを使う方法を説明する。まずはyumやapt-getなどのコマンドを用いてtelnetのインストールを行う。

#telnetがインストールされているかを確認するwhich telnetsudo find / -name telnet#インストールされていなければ,telnetをインストールするsudo yum install -y telnet

telnetからmemcachedに接続し,データの書き込み・読み込みを行う。

#telnetでmemcachedに接続する memcachedはデフォルトでは,11211番ポートをリッスンしているtelnet localhost 11211#データの保存 #set key,flag,expires,byte[改行]#valueset foo 0 100 3bar#データの読み出しget foo

いろいろ操作を行ってみる。

#データの保存set counter 0 0 11#加算(increment)#+1incr counter 1#減算(decrement)#-1decr counter 1#データの保存set test 0 0 4test#データの先頭へ追加prepend test 0 0 3bow#データの末尾へ追加append test 0 0 5wanko#データの削除delete test#memcached上のすべてのデータを削除flush_all
名前 説明 注意点
flag データを圧縮するかどうかの指定。0:非圧縮,1:圧縮
expires データをいつまで保持するかをUNIXタイムスタンプもしくは現在からの秒数で指定する 現在からの秒数は30日(60*60*24*30=2592000)を超えることはできない。0を指定すると有効期限無し(半永久的に保持)になる。
byte valueとして保存するデータのバイト数を指定する

PHPからmemcachedを使ってみる

PHPからmemcachedを使う方法を説明する。今回はApacheとPHPが既にインストールされているという前提で話を進める。

まずは,PECLのmemcachedライブラリをインストールする。

 #PHPからmemcachedを使うためのライブラリをインストールする sudo yum install -y php-pecl-memcached

続いて,memcachedにデータを書き込むPHPプログラムと,memcachedからデータを読み込むPHPプログラムを作成する。

<?php//memcachedにデータを書き込むPHPプログラム$m = new Memcached();$m->addServer('localhost', 11211);// キー,バリュー,有効期限(秒)$m->set('key', 'wanko', 60);
<?php//memcachedからデータを読み込むプログラム$m = new Memcached();$m->addServer('localhost', 11211);if ($val = $m->get('key')) {    echo $val;}

上記のプログラムでは,keyというキーに対して,wankoというバリューを格納し,1分間だけmemcachedが情報を保持している。

CAS操作の実践

CAS操作では,getsとcasという2つのコマンドを使ってデータの不整合を発生させないようにする。getsはデータを読み出すコマンド,casはデータを保存するコマンドである。まず,getsコマンドを使うとデータだけでなく,cas idと呼ばれる値も取得できる。cas idはそのデータを識別する一意の値であり,データが更新されると必ず変更される。そしてデータの保存時にはcasコマンドに対して保存するデータと一緒にcas idを渡す。このとき,casコマンドに渡されたcas idと,現在のデータを表すcas idが一致したときのみ保存が行われる。cas idが一致しない場合には,getsコマンドで取得してからデータが変更されているということであり,データの保存は失敗する。このように,保存時にそのデータが別のプロセスによって変更されていないかを確認することで,データの不整合が発生しないようにしている。

telnetからCAS操作を行ってみる

telnetでCAS操作を行うと,以下のようになる。

#データの保存#set key,flag,expires,byte[改行] #valueset hoge 0 1500 101111111111STORED#数値の1111111111とcas id(6)を取得できるgets fooVALUE hoge 0 10 61111111111END#cas idを渡して,新しい値に書き換えるcas foo 0 1500 10 62222222222STORED

上記では,4~6行目にてデータの格納を行い,9~12行目でデータの取得とcas idの取得を行っている。更に15~17行目でkey, flag, expires, byte, cas idを渡し,値を書き換えている。

PHPからCAS操作を行ってみる

PHPでCAS操作を行うと以下のようになる。

<?php$m = new Memcached();$m->addServer('localhost', 11211);//memcachedからデータを取得//キー,コールバック関数名,CASトークンを格納する変数$data = $m->get('key', null, $cas);//get()で,キーが見つからなかった場合は新たにキーとデータを追加するif ($m->getResultCode() == Memcached::RES_NOTFOUND) {    //キー,バリュー,有効期限(秒)    $m->add('key', 'value', 60);} else {    //get()で,キーが見つかった場合は,CASトークンを使ってデータを更新する    //CASトークン,キー,バリュー,有効期限(秒)    $m->cas($cas, 'key', 'value', 60);}

これはこちらのページにあったコードを,自分なりに読みやすく書き換えたものである。動作確認済みなので,このままコピペして試すことができる。Memcached::get()はコールバック関数の実行が行えたりと,少し変わった使い方もできるのでこちらのページを参考にして使い方を確認すると良いだろう。

参考
書籍 NoSQLデータベース ファーストガイド
書籍 NOSQLの基礎知識 ビッグデータを活かすデータベース技術
memcachedとは 【 memory cache daemon 】 – 意味/解説/説明/定義 : IT用語辞典
ACID (コンピュータ科学) – Wikipedia
[CentOS] memcachedをインストールして、PHPから使用する | HAPPY*TRAP
PHP: Memcached::cas – Manual
PHP: Memcached::get – Manual
PHP: Memcached::add – Manual
PHP: Read-through キャッシュコールバック – Manual

投稿者 SmokyDog

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です