ElastiCacheはMemcachedとRedisのどっちを選ぶ?

こんにちは(U・ω・U)
AWS事業部の深澤です。

AWSにはElastiCacheと呼ばれるマネージド型のキャッシュストアサービスがあります。利用を始めようと色々調査すると「RedisとMemcached、どっち使ったらいいの?」というのは結構悩みがちなポイントかと思います。今回は2つの特徴を比べてみて、どちらのサービスを使うか一緒に考えてみましょう!

可用性

ElastiCacheでは最小の構成単位を「ノード」と呼びます。EC2で言うところのインスタンスに相当するものです。このノードを組み合わせた集合体をクラスターと呼びます。ノードに直接接続してしまうと、もしそのノードに問題が発生した場合には新しいノードのアドレス(エンドポイント)をアプリケーション側で書き換えなくてはなりませんし、サービスの成長と共に負荷が上がってくるとノードの台数を増やして負荷やメモリ(キャッシュ)を分散したりといった要件も出てきます。クラスター構成を組んでおいて、常にアプリケーションはエンドポイントを見ておくようにすればノードの増減によってアプリケーションに変更を行う必要がありません。よって、運用を行う上でこのクラスター機能という観点は非常に大事になってくるのです。

Memcached

Memcachedのクラスターは単純にノードを追加したり減らしたりして負荷を分散することができます(水平スケーリング、スケールアウト/イン)。クラスター全体での負荷やメモリ使用量をノードを増やして分散することができるのです。しかし、この仕組みは自動検出と呼ばれる機能に依存しています。クライアントアプリケーション側で定期的にノードの状態をチェックし、その情報を元にノードにアクセスしに行っています。

それでは、Redisはどうでしょうか。

Redis

Memcachedと比較し複雑な構成になっているように見えますね。Redisクラスターにはいくつか種類がありますが、Memcachedクラスターの違いはクラスターのエンドポイントを持っていることです。先ほどのMemcachedはノードの状態をポーリングしてノードにアクセスしにいく形でしたが、Redisの場合はクラスターがエンドポイントを持っており、アプリケーション側でポーリングする必要がありません。それでは、上記画像を左から順番に見ていきましょう。

レプリケーションなしRedisクラスター

こちらは先ほどのMemcachedクラスターの構成と似ており、ノードの数を加減することで負荷の分散が可能です。レプリケーションなしと言うのはシャードがないと言うことです。シャードについては次で説明します。

Redisクラスターモード無効、シャード有効

シャードと言う単語が出てきました。これはプライマリと呼ばれるノードからレプリカのノードに対してデータを書き込む(レプリケーションする)グループの名前です。1つのプライマリノードに最大5つまでのレプリカノードを登録できます。クラスターモードが無効なのでスケールイン/アウトは行えないのですが常にデータのバックアップをレプリカノードで取っておいて、もしプライマリノードで故障が発生した場合にはレプリカノードが昇格してプライマリノードになります。そして新たなレプリカノードが追加されます。これにより障害に対して可用性を担保しているのです。

Redisクラスターモード有効、シャード有効

これは上記のクラスターモードとシャードを両方有効にしたものです。スケールイン/アウトも行える上に障害に対して高い可用性を担保することができます。

所感

ここは可用性の観点から様々な構成が取れるRedisの方が優れているといえるでしょう。Memcachedではそもそもレプリケーションをサポートしていないのでシャード構成が取れないのです。

2019年11月5日追記:
こちらですが、Memcachedでもシャードはできるのではというご指摘をいただきました。確かにMemcachedはサーバサイドでレプリケーションをサポートしていないのは事実ですが、シャードはクライアントアプリ側で行うことが可能です。最終的な結論として可用性の観点ではRedisが優っているという結論に間違いはございませんが、「Memcachedではシャードができない」というのは誤りです。申し訳ございませんでした。

単一ノードの性能

集合体(クラスタ)としてみた場合は可用性の観点でRedisの方がどうやら性能が良さそうでした。ではそもそも単一ノードとしてのパフォーマンスはどうなんでしょうか。

Memcached

Memcachedはマルチスレッドで動作するので、CPUのコア数を上げれば上げるほど単一ホストとしての性能は上がっていきます。

Redis

Redisはシングルスレッドで動作するので、CPUのコア数を上げてもMemcachedほどはパフォーマンスの向上を期待することはできません。

所感

やはりここはマルチスレッドで動作するMemcachedの勝ちといえるでしょう。

機能性

どちらもキャッシュを行うものということはわかりますが、実際にはどのような機能があるのか気になりますよね。実際にどんなことができるのかを比較してみましょう!

Memcached

Memcachedはシンプルなデータ(string)のみしか格納できません。よって、それ以外のデータを保存する場合にはアプリケーション側で格納できる型に変更する必要があります。また、扱えるコマンドも必要最低限しかなく、ほとんどデータの追加、削除以外は使わないと考えてよいでしょう(一応、データの変更や追記も可能です)。

Redis

RedisではString に加えて、List、Set、Sorted Set、Hash、Bit Array、HyperLogLog と豊富なデータ型を扱えます。さらに正規表現を用いたキーの曖昧検索を行えたり、トランザクションを用いてデータを更新できたりとget/set以外にも豊富な機能があります。

所感

正直、キャッシュなので使い方によってはget/setだけで十分な気がしますが、ないよりはあった方がいいという観点からRedisの方が優れていると思います。

バックアップ

ElastiCacheはマネージドサービスなので、バックアップを取得したい際にどのような挙動になるのかきになるところです。

Memcached

こちらはAWSでバックアップをサポートしていません。どうしてもバックアップを取得したい場合には専用のクライアントツールにて行うしかなさそうです。
https://github.com/memcached/memcached

Redis

クラスターごとスナップショットを取ることができます。取得したスナップショットはS3に保存され、このスナップショットを用いて復元が行えます。注意点としては、バックアップの際、アプリケーション領域とは別のメモリ領域が必要になるので、十分な空き容量がないとバックアップに失敗するケースもあります。このアプリケーション領域以外のメモリ領域を予約メモリと呼びますが、この予約メモリはAWSのドキュメントでRedisバージョン2.8.22より前の場合は、50 (50 パーセント) に設定し、Redisバージョン2.8.22以降の場合は 25 (25 パーセント) に設定することが推奨されています。
https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/red-ug/BestPractices.BGSAVE.html

所感

キャッシュはそもそもTTLの付与を前提で保存する揮発性のあるデータですし、メモリに保存するというその特性上からもバックアップが必要になるようなデータの保存はしない方が良いというのが大前提ではありますが、サポートされていないよりはサポートされていた方が万が一の際に安心です。ここはRedisの方が優れていますね。ちなみにTTLについてはAWS公式ドキュメントのキャッシュ戦略でも触れられています。
Memcached
Redis

全体を通してみて

いかがでしたでしょうか?少しは皆さんの参考になれたら幸いですm(_ _)m

ここからは完全に僕の主観でお話をしますが、クラスター構成とシャード構成が取れるというところでRedisなのかなと個人的には思います。確かに単一ノードであればMemcachedの方がパフォーマンスを発揮するのかもしれませんが、キャッシュはよっぽど尖った使い方をしない限り、その特性上単一ノードの性能がボトルネックになる可能性は低いと考えて良いです(シンプルにkey/valueのデータを保存して取り出すだけなので一般的には他のところがボトルネックになります)。それよりも、アプリケーションに機能を追加して色んな型のデータをキャッシュしたくなったりとか、セッション情報を保存しておいて障害時にセッションが飛んでしまうリスクなどを考えたら、シャーディングでマルチAZ構成が取れるRedisの方がElastiCache的に優れていると考えます。

以上、せっかく調査する機会があったので皆さんのお役に立てたらと考えた深澤(@shun_quartet)でした!
ではまた!