ElastiCache: AutoDiscovery をPHPで使う
ElastiCacheに AutoDiscovery機能が付き、phpクライアントも出た。(Cache Engine 1.4.14以降で有効)
ちょうど1年前に、このような記事(Amazon ElastiCache の分散方法 )を書いたが、この際は、ElastiCacheの複数ノードを扱うには、Mamcached::addServers() で全ノードのEndpointをハードコードする必要があった。(もしくは、ElastiCache APIのDescribeCacheClusters等を使って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 に指定しておくのがポイント。
このとき、サンプルコード末尾の 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