まめ畑

ゆるゆると書いていきます

AWS ElastiCache と twemproxyを使ってみた

このエントリの最後の方で書いてあるtwemproxyの変更ですが、pull requestを出して、本体にマージされました。2012/12/31時点でまだリリースバージョンが切られていないので、githubからcloneしてビルドして下さい。


先日のAWSの発表で、VPCにもElastiCacheがやって来ました。 (http://aws.amazon.com/jp/about-aws/whats-new/2012/12/20/amazon-elasticache-announces-support-for-amazon-vpc-1/)

さらに、オートディスカバリ機能も少し前に発表されています。
オートディスカバリを使えば、Configuration Endpointに対して config get cluster コマンドを発行することで、そのClusterで有効なnodeの接続情報リストが返却されるので、クライアントが対応していれば、nodeの増減にアプリケーションの設定を書き換えることなく対応することが可能になります。


しかし、既存のクライアントを置き換えられない場合や、複数のmemcachedやredisの接続管理どうしようという場合は、Twitter製のmemcached / redisのproxyである、twemproxyを使うと便利です。
https://github.com/twitter/twemproxy

こちらは、簡単な設定で、複数のmemcached/redisへのアクセスをproxyしてくれ、nodeがダウンした場合も切り離してくれます。また、複数のhashアルゴリズムが用意されており、keyによってnodeにデータを分散してくれます。その他にもpipelineなどの機能も実装されています。nodeの状態も管理用ポートに接続するだけでjsonで取得出来るので監視も楽です。他には、1つの設定に複数のバックエンドグループをかけるので、複数のcache clusterをまとめて管理することが可能です。しかし、サポートしているコマンドは以下の表にまとまっている通りです。サポートされていないコマンドを発行すると、切断されます。
https://github.com/twitter/twemproxy/blob/master/notes/redis.md


先日、v0.2.2がリリースされ、このバージョンから、hash tagと呼ばれる機能がサポートされました。コレを使うことで、key中にhash tagで設定した文字で囲まれた物を振り分けに使ってくれます。例えば、"{}" を指定した場合は、recipe:{user_id}:name , recipe:{user_id}:count の様に同じuser_idだが、他の文字によって別のnodeに振り分けられてしまうことを防ぐことが出来ます。


このtwemproxyをElasticCacheのnodeの前に設置することで、アプリケーションからは1つの接続先に接続するだけで、データを複数ノードに分散配置することが可能になります。また、このproxy自体をELBの配下に入れることで冗長化も出来ますし、twemproxy自体は現状でconfigのreloadにはプロセス再起動が必要なので、ELB配下に入れることで切り離しつつ作業が可能になります。使用前には用途に応じて検証をおすすめします。ELBのヘルスチェックもproxy配下にnodeが1台でも存在するかどうかを管理ポートからデータを取得してそれに応じてELBにレスポンスを返すスクリプトを動かして置くと便利です。


しかし、twemproxyを使う場合に少し困った点があり、nodeの指定を設定ファイルにipアドレスではなくドメインで書く場合、長いドメインだと最後が切られてしまって名前解決が出来ないという状態になります。
ドメイン名でも指定出来る仕様です(servers: A list of server address, port and weight (name:port:weight or ip:port:weight) for this server pool.)
IPを使えばいいではないかとおもいますが、ElasticCacheのnodeに割り振られたドメインに紐づくIPアドレスは変わる可能性があるため、いつの間にか接続が出来ないという事になる可能性があります。
ちなみに、ドメイン名は「hoge-cache-.9xxxxx.0001.apne1.cache.amazonaws.com」 こんな感じになっています。


長いドメインが切られる理由は、
https://github.com/twitter/twemproxy/blob/master/src/nc_util.c#L461
https://github.com/twitter/twemproxy/blob/master/src/nc_util.h#L40

ここで、NC_INET6_ADDRSTRLEN−1の長さ(44)を元に文字数の制限がかかっており、この長さを超えるドメイン名は途中で切れてしまっていました。

ここで、固定長にして、長さを制限する意味があまり無いように思えたので、一旦
https://github.com/cookpad/twemproxy/compare/835ae01e62%E2%80%A69c6b29ac22
の様に修正して負荷試験を行なっていますが今のところ特段問題は出ていません。


性能ですが、詳しくはまた後で書こうと思いますが、1台のmemcachedに直接setする場合と、twemproxy経由で2台のElasticCache node (small)に入れる場合では、

入れている場合 10,000 key /sec
入れていない場合 15,000key /sec

程でした。

twemproxyはm1.largeのインスタンスで動作させています。
今後はもう少し並列度を上げて、複数のnodeClusterを設定した状態で、hashアルゴリズム別にパフォーマンスを計測する予定です。ELBも挟んだり。

https://github.com/cookpad/twemproxyで、気づいたものは、pull requestを送ろうと思います。