memcachedについて,書籍を読んで勉強したので使用方法をまとめておく。
memcachedとは
memcachedは,分散メモリキャッシュシステムを構築することができるソフトウェアの一つ。データベースの読み出し結果などをメモリに保存し、次に同じデータが参照されたときにメモリから即座に返すことができる。複数のコンピュータにまたがる巨大な分散キャッシュシステムを構築でき、台数を増やすことで性能を向上させることができるため、大規模なWebサービスなどでよく用いられる。
memcachedの特徴と用途
memcachedは,メモリ上で動作するキー・バリュー型の揮発性データベースである。揮発性なので,memcached自身が停止したり,memcachedが動作しているハードの電源が切れたりすると,memcachedに保存されているデータは消失してしまう。そのため,消えてしまっては困るようなデータを保存することはできない。memcachedはメモリ上にデータを格納するので,非常に高速にデータの書き込み・読み込みを行うことができる。
以上に挙げた特徴から分かるように,memcachedはキャッシュを行うような場面において,その真価を発揮する。memcachedの具体的な用途としては,MySQLやPostgreSQLのようなRDBと組み合わせて,キャッシュ用のデータベースとして使用することで,RDBにかかる負荷を抑えることができる。
コンシステント・ハッシングによる負荷分散
memcachedは,コンシステント・ハッシング(Consistent Hashing)と呼ばれるアルゴリズムによってデータ分割・割り当て(負荷分散)を行う。
このアルゴリズムでは,分散型システムを構成する各ノード(memcached)が,論理的にリング(輪)を形作るように配置される。
以下がコンシステント・ハッシングの図である。
図では,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 memcached
sudo 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 telnet
sudo find / -name telnet
#インストールされていなければ,telnetをインストールする
sudo yum install -y telnet
telnetからmemcachedに接続し,データの書き込み・読み込みを行う。
#telnetでmemcachedに接続する memcachedはデフォルトでは,11211番ポートをリッスンしている
telnet localhost 11211
#データの保存
#set key,flag,expires,byte[改行]
#value
set foo 0 100 3
bar
#データの読み出し
get foo
いろいろ操作を行ってみる。
#データの保存
set counter 0 0 1
1
#加算(increment)
#+1
incr counter 1
#減算(decrement)
#-1
decr counter 1
#データの保存
set test 0 0 4
test
#データの先頭へ追加
prepend test 0 0 3
bow
#データの末尾へ追加
append test 0 0 5
wanko
#データの削除
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[改行]
#value
set hoge 0 1500 10
1111111111
STORED
#数値の1111111111とcas id(6)を取得できる
gets foo
VALUE hoge 0 10 6
1111111111
END
#cas idを渡して,新しい値に書き換える
cas foo 0 1500 10 6
2222222222
STORED
上記では,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