インフラストラクチャー部 星野(@con_mame)です。 クックパッドでは、AWSを活用してサービスを行っています。 現在クックパッドでは、各種キャッシュにMemcachedやRedisを使用しています。
しかし、用途の多様化やアクセス数の増加などでこれらのサーバのインスタンス数が増加し管理コストが増加してきています。
特にRedisサーバのインスタンス数が増加しており、AWSのサービスの中でもキャッシュのサービスを提供しているElastiCache for Redisへの置換えを検討しています。
ElastiCache for Redisは、一部管理系のコマンドがrenameされており使用出来ませんが、通常のRedisと同じ物で、現在Version 2.6.13と2.8.6が使用出来ます。 SlaveにあたるものはReplication Groupという形で指定でき、Replication Group1つに付き1つEndpoint URLが発行され、このEndpointにクライアントから接続することで現在Masterになっているノードに接続することが出来ます。(ReplicationでもこのEndpointのアドレスが使用されています)
SlaveになっているノードはPromoteを行なうことで、Masterへと昇格し、他のノードは自動的に新MasterのSlaveになります。
Promoteは
からBackupを選択して
に名前を入れれば完了です。
クラスタ作成時は
からBackup Windowを指定することで自動実行が可能です。
こちらは、最低でも1時間は設定しないといけません。
Snapshot実行時のMONITORの出力は
$ aws elasticache modify-replication-group --replication-group-id レプリケーショングループID --primary-cluster-id PromoteするノードのID --apply-immediatelyこれを実行すると、Replicationのつなぎ替えが完了します。 注意点は、masterの障害時自動でPromoteしないということと、Promoteを行ってSlaveをつなぎ替えが発生した際に、保存してあるデータ量が多い場合Master nodeの性能が劣化、もしくは接続が失敗するという事象が確認出来ました。 これは、ElastiCacheだから発生するというものでは無く、Redisを使用している場合は起こりうる問題です。弊社では保存するデータ量を少なくするなどして回避しています。 また、Replication Group内のSlaveにはそれぞれ、1つずつEndpointが割り当てられread onlyになるのですが、アプリケーション側ではhaproxy・twemproxyやミドルウェアの機能などを使用し、Slaveの振り分けを行なう必要があります。 弊社では、SlaveはELBにMasterはHeartbeatによるENIの移動を行なうことでFailoverを行っていますが、他にはRedis Sentinelを使用したFailoverもあります。 ElastiCache自体に、自動Promoteや、Slave共通の1つのEndpointがあり、よきに負荷分散してくれると嬉しいところです。(ElastiCacheはELBにはぶら下げられません) 社内では以前からパフォーマンス測定などは行なっていましたが、先日バックアップとリストアを自動で行う機能がリリースされたので、 試用してみた感想や注意点をまとめておきます。 ドキュメント: http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/Welcome.html
SnapShot
リリース時から、Redisのdbファイルをインポートし移行を簡単に行える機能はありましたが、今回は障害時などにRecoveryを簡単に行えるように、バックアップ・リストア機能が実装されました。 自動・手動でsnapshotを取得することが出来ます。(cache.t1.microではバックアップ機能は使えません) snapshotを作成する場合は、ドキュメントにも記載がありますが、BGSAVEが発行されるため、データ容量によっては性能劣化が発生する可能性があります。 何回かベンチマークを行いましたが、データサイズが大きい場合に若干の性能劣化が発生しました。 ユースケースに応じて事前にパフォーマンステストを行なう事を推薦します。もしくは、サービスで使用されていない、Slave nodeでスナップショットを取得するといいかと思います。 このへんも、自前でRedisを運用しているのとさほど変わりません。 また、高頻度でデータ更新・セットを行いましたが、BGSAVEが発行されたタイミングのデータがきちんと保存され、リカバリ可能でした。 CLIでは$ aws elasticache create-snapshot --cache-cluster-id hogecahce --snapshot-name hogesnapshotを実行し、 Management Consoleでは
![ss_1](http://cookpadtech.files.wordpress.com/2014/05/ss_1.png?w=480)
![ss_2](http://cookpadtech.files.wordpress.com/2014/05/ss_2.png?w=480)
![ss_3](http://cookpadtech.files.wordpress.com/2014/05/ss_3.png?w=480)
1399427528.007150 [0 127.0.0.1:34471] "set" "ElastiCacheMasterReplicationTimestamp" "2014-05-07T01:52:08.006Z" 1399427529.003567 [0 127.0.0.1:34471] "bgsave" 1399427529.022860 [0 127.0.0.1:34472] "ping"こんな感じで、ただbgsaveが打たれているだけでした。 SnapShotの時間は、cache.m1.mediumで1GB程のデータのSnapShotが完了するまで、約10-15分ほどかかりました。 このへんは自前運用しているRedisだと1−2分で完了するので、時間がかかっている印象です。 加えて、本当にSnapShot時に大量のアクセスがある場合、データ破損が起こらないこと 確認をしています。 バックアップからのリストアは、新クラスタを作ると同義なので、
$ aws elasticache create-cache-cluster --cache-cluster-id newcluster --snapshot-name hogesnapshot --cache-node-type cache.m1.mediumこれでOKです。(Redis Versionは変更出来ません) ここも1点気をつける点があって、SnapShotで保持される情報はデータの内容とSnapShot取得を行ったnodeタイプであり、Security GroupやReplication Groupは引き継がれません。 そのため、何か障害が発生して、SnapShotから復帰させる場合は一旦別名で1つMaster nodeを作成し、Replication Groupなどを作成、Security Groupの適用を行います。 このへんも、SnapShotのメタデータに含められていると速やかに復旧が出来ると思っています。もしくは、スクリプトを書いて自動化ですね。 1番大きいのが、Endpoint URLが新しいものになるので、アプリケーションの設定などを変える必要があることです。この辺りも、既存のEndpointにSwapしてくれる機能があると更に便利だと思っています。 これの回避方法としては、Route53などDNSにCNAMEで別名を付けておき、Endpointを設定するとDNSレコードの変更で一応は対応出来ますが、スマートではないです。 また、RedisはBGSAVEなどで子プロセスをforkする場合にメモリを確保するのですが、これはRedisのmaxmemoryには含まれないため、場合によってはswapなどが発生し、パフォーマンスの大幅な劣化が発生します。 ElastiCacheではこれを防ぐために、reserved-memory というParameter Groupの値があり、ElastiCache for Redisはここで指定されたメモリは使用しません。 ここはユースケースに応じて適切に設定しておくといいかと思います。デフォルトでは制限無しです。