aws memo

AWS関連の備忘録 (※本ブログの内容は個人的見解であり、所属組織及び企業の意見を代弁するものではありません。1年以上古いエントリは疑ってかかってください)

ElastiCache: AutoDiscovery をPHPで使う

ElastiCacheAutoDiscovery機能が付き、phpクライアントも出た。(Cache Engine 1.4.14以降で有効)

ちょうど1年前に、このような記事(Amazon ElastiCache の分散方法 )を書いたが、この際は、ElastiCacheの複数ノードを扱うには、Mamcached::addServers() で全ノードのEndpointをハードコードする必要があった。(もしくは、ElastiCache APIDescribeCacheClusters等を使ってEndpointを取得してServerListを設定する)

AutoDiscoveryのメリット

システムの負荷に応じてElastiCacheのノード増減を運用時に行う際、ハードコードが入り込むのは運用上避けたいがそのための仕組みを作りこむ負荷が必要だった。AutoDiscovery対応のMemcachedクライアントモジュール(AWSが配賦しているMemcachedモジュールの拡張版)を使えば、ここが楽になる。

具体的には、実際の各Endpointではなく、Configuration EndpointだけをMemcached::addServer()に指定すると、内部的には実際の全EndpointがaddServerされる。ServerListは定期的にチェックしているため、ノード増減にも追従する。

Configuration Endpointを実際のEndpointに変換してServerListに入れるだけなので、consistent hashingを行うlibketamaを組み合わせても問題なく動作する。

AutoDiscoveryの仕組み

概要はこちらに。

How Auto Discovery Works - Amazon ElastiCache

 

Adding Auto Discovery To Your Client Library - Amazon ElastiCache に、自前のアプリやクライアントライブラリに組み込む方法が書いてある。その中に、Configuration Endpointにアクセスした際のレスポンスフォーマットについても説明がある。

 

 PHPでのAutoDiscovery 導入

Amazon Linuxへの導入手順はここ(Appendix: Installing the Amazon ElastiCache Cluster Client for PHP - Amazon ElastiCache)を参考にして以下のとおり。peclで標準のmemcachedモジュールを入れるのではなく、AWS提供のAutodiscovery対応版memcachedモジュールを入れる。ついでにlibketamaも入れておく。

$ sudo yum install gcc-c+ gcc make subversion php-devel php php-pear
$ sudo pecl install https://s3.amazonaws.com/elasticache-downloads/ClusterClient/PHP/latest-64bit
$ echo "extension=amazon-elasticache-cluster-client.so" | sudo tee -a /etc/php.d/memcached.ini
$ svn co svn://svn.audioscrobbler.net/misc/ketama/
$ cd ketama/libketama
$ make
$ sudo make install 
$ sudo ldconfig

 動作確認

実際に使ってみる。使い方はこちら(Using the Amazon ElastiCache Cluster Client for PHP)を参考に。

<?php
# set specific endpoint for auto discovery
$server_endpoint = "hoge.mayg1j.cfg.apne1.cache.amazonaws.com";
$server_port = 11211;

# connect and store record
$stime = time();
$dynamic_client = new Memcached();
$dynamic_client->setOption(Memcached::OPT_CLIENT_MODE, Memcached::DYNAMIC_CLIENT_MODE);
$dynamic_client->addServer($server_endpoint, $server_port);
  $dynamic_client->set('key1', 'value', 600); 
  $dynamic_client->set('key2', 'value', 600); 
  $dynamic_client->set('key3', 'value', 600); 
  $dynamic_client->set('key4', 'value', 600); 
  $dynamic_client->set('key5', 'value', 600); 
  $dynamic_client->set('key6', 'value', 600); 
$ptime = time() - $stime;
echo $ptime;

# verify serverlist
$sl = $dynamic_client->getServerList();
print_r($sl);
?>

 ここでは、Configuration Endpointとしてhoge.mayg1j.cfg.apne1.cache.amazonaws.comを指定したが、その実体は以下の図のようになっている。そして、Memcached::setOptionで、CLIENT_MODEをDYNAMIC_CLIENT_MODE に指定しておくのがポイント。

f:id:understeer:20130104060937p:plain

このとき、サンプルコード末尾の Memcached::getServerList()が返す値は、以下のように実体のEndpointが戻ってきている。

Array
(
    [0] => Array
        (
            [host] => hoge.mayg1j.0001.apne1.cache.amazonaws.com
            [port] => 11211
        )

    [1] => Array
        (
            [host] => hoge.mayg1j.0002.apne1.cache.amazonaws.com
            [port] => 11211
        )

    [2] => Array
        (
            [host] => hoge.mayg1j.0002.apne1.cache.amazonaws.com
            [port] => 11211
        )
---snip---
    [5] => Array
        (
            [host] => hoge.mayg1j.0006.apne1.cache.amazonaws.com
            [port] => 11211
        )
)

また、各endpointにtelnet で接続して直接getすることで、libketamaによる分散が行われていることも確認できる。

$ telnet hoge.mayg1j.0001.apne1.cache.amazonaws.com 11211
Trying 10.0.1.186...
Connected to hoge.mayg1j.0001.apne1.cache.amazonaws.com.
Escape character is '^]'.
get key1
VALUE key1 0 5
value
END
quit