Redis + Sentinel で自動フェイルオーバ in Amazon VPC を試してみた

お久しぶりです。
最後にブログを更新したのがInternal ELBが登場して勢いで書いた6月11日。。。更新してなさすぎですね。

そこで今回試してみたのは、Redis + Sentinelの自動フェイルオーバをAWS VPC環境で実現するというものです。

元々は「 RedisをKeepalivedでフェイルオーバーする構成案 - 酒日記 はてな支店 」を参考にして構築しようと考えていたのですが、VPC(というかAWS)の環境ではbroadcastやmulticastが使用できないので、VRRPが使えず断念。そこで少し途方にくれつつ考えたのが、Sentinelを使う方法。

Redisについては特に説明は必要ないと思いますので、Sentinelについて簡単に。

  • 監視: masterやslaveが期待通り動いているかどうかを定期的に監視
  • 通知: 指定したログレベルのものが発生した時に、管理者やプログラムに通知を行う
  • 自動フェイルオーバ: master障害時にslaveをmasterへと昇格させる。redisを使っているアプリケーションに新しいmasterのIPアドレスを通知する

詳細はこちら( Redis Sentinel Documentation – Redis )を参照していただければと。

構成

構成としては、以下のような感じです。すべてCentOS6.3(ちょっとだけカスタムAMI)を使っています。

  • web(application)サーバ2台
  • Redis + Sentinelサーバ2台

f:id:matetsu:20121228110332p:plain
※ #ヤマン さんによる「 VPCでアベイラビリティゾーン越しにプライベートIPを共有する(Source/Descチェック外し) - c9日記 -カタヤマンがプログラマチックに今日もコードアシスト 」のような構成です。

webサーバは特に言及することはなく、Redisに接続するためのIPとしてVIPである 172.16.0.10 を使うようにするくらいです。
Redisサーバでは、以下のような設定をします。

  • 両機のループバックインターフェイスに予めIPエイリアスとして 172.16.0.10/32 を設定
  • インスタンスのSource/Dest Checkをdisableにしておく←これ重要(masterにするスクリプトでもdisableにするようにしてるけど)

VPCのroute tableの設定はmaster/slaveの設定をするときにスクリプトを使って一気にやってしまうので、先に設定しておく必要はない。

Redisの設定(初期設定)

master/slaveの関係を作る前のRedis初期設定は以下のようにしています。

slaveof no one
masterauth [pass]
requireauth [pass]

くらいしか変えていません。

Sentinelの設定はこちら。まだ特に関しの設定はせずに、起動するだけになっています。

この状態で、まずはサービスを起動します。

# service redis start
# service sentinel start

Master/Slaveの設定

続いて、redis01をmaster、redis02をslaveとして設定します。

基本的には単純にredis-cliからslaveofコマンドを実行するだけなのですが、requireauthを設定しているので、パスワードを入れるのが面倒だったので、以下の様なpythonスクリプトにしています。

また、masterノードのVIP(ループバックに設定したやつ)にwebサーバからのアクセスを向かせるために、VPCのroute tableを設定するためのスクリプトも準備しておきます。ACCESS_KEYやSECRET_ACCESS_KEY,routetable_idは自分の環境にあわせてください。

このスクリプトでは、自分自身のインスタンスIDにVIPへのアクセスをルーティングするようにしています。

このスクリプトと、実行ノードをmasterにするスクリプト(redis-to-master.sh)、指定したmasterノードのslaveにするスクリプト(redis-to-slave.sh)を組み合わせて、master/slave構成を取るようにする。


redis-to-master.shとredis-to-slave.shの中で、sentinelが監視するクラスタの情報を登録するためにsentinel.confを変更する処理も入っています。この処理は、以下のテンプレートのmasterノード情報をsedを使って置換しているだけです。

以下のように実行して少し待てば設定完了です。

[redis01]# redis-to-master.sh
[redis02]# redis-to-slave.sh redis01

フェイルオーバを試す

ここからが本題です。
フェイルオーバはSentinelが自動で行なってくれて、masterが切り替わったことをアプリケーションに伝えてくれるとのことですが、VIPを使ってVIPの向き先を変更することで対応しています。

sentinelの設定で指定している client-reconfig-script で指定しているスクリプト redis-failover.sh では failover endが渡された時に route-table を書き換えてVIPを自身のインスタンスIDに向けるようにしています。こうすることで、webサーバ側では特に接続先を変えなくてもそのままの設定で接続できます。もちろん、failover endが渡ってきているので、自動フェイルオーバが完了して、もともとslaveだったノードがmasterとして稼働します。

また、SentinelがWarning以上のステータスを検知した場合に通知するためには notification-script に通知スクリプトを指定する。

これで、フェイルオーバが起きたことを検知することもできる(もちろん監視も忘れずに)。
フェイルオーバが起きた時には、以下のようなログが出力される。上のnotification-scriptだと、5通のメールが来ることになる。。。これも「+hoge」となっているEvent Typeを見て分岐したりもできるので、もう少し改良の余地はあるかと思います。

[23304] 15 Jan 19:59:06.858 # +sdown master mymaster MASTER_IP 6379
[23304] 15 Jan 19:59:06.859 # +odown master mymaster MASTER_IP 6379 #quorum 1/1
[23304] 15 Jan 19:59:17.395 # +failover-detected master mymaster MASTER_IP 6379
[23304] 15 Jan 19:59:17.495 # +failover-end master mymaster MASTER_IP 6379
[23304] 15 Jan 19:59:17.495 # +switch-master mymaster MASTER_IP 6379 SLAVE_IP 6379

masterが切り替わったあとも、webサーバからはVIPでそのままアクセスできることも確認できた。まだまだ検証しないといけないこともあるけれど、それなりに簡単にフェイルオーバの仕組みを構築することができました。

Sentinelについては、簡単に動かしてみた程度なので、もう少し詳しく調べてみたいなと思っています。


年末に勢いで3分の2くらい書いたところで放置してしまっていましたが、このまま眠らせておくのもアレですし、とりあえずアウトプットしておこうとようやく書き上げました。不備などありましたらご指摘ください。gistも(ほぼ)初めて使って見ました。
今年はちゃんとブログにアウトプットしていきたい!

VPCのInternal ELBを早速試してみた

待ちに待ったあいつが来ましたよ!この時をどれほど待ったことか。(まだ1年も触ってないのにw)

VPCでPrivate IPでアクセスできるELBが来ちゃいましたよ!
外からはアクセスさせたくないけど、内部的なアクセスを負荷分散させたい時には欲しかったですよね。

というわけで、早速。

ELBを作る


EC2のメニューから「Load Balncers」を選択
f:id:matetsu:20120611212813p:plain

右上ペインから「Create Load Balancer」を選択
f:id:matetsu:20120611213131p:plain

いつもの通り、必要項目を入力 (薄く見えちゃってますね、ヤツが)
f:id:matetsu:20120611213454p:plain

Create LB InsideをEC2ではなくvpc-hogehoge(設置するVPC ID)にすると。。。

チェックできます!
f:id:matetsu:20120611213845p:plain

あとは適当に項目を埋めていき
確認画面で、Schemeが「internal」になっていることを、十二分に確認したら
f:id:matetsu:20120611214511p:plain

「Create」ボタンを押しましょう。

確認する

ELBの一覧画面で、先程作ったLBを見てみると、
f:id:matetsu:20120611214850p:plain
DNS nameに「internal」なんてついちゃって、wktkしますね。

さっそくVPC内のインスタンスから確認してみましょう
f:id:matetsu:20120611220920p:plain
ちゃんとPrivate IPになってますね!

さすが

いやはや、AmazonさんマジAmazon。すごいですね、このスピードでの機能リリース。

今回のリリースでいろいろと捗る人たちがどれだけいるんだろうっていうくらい、素晴らしくそしてうれしいリリース!本当に待ってました!
internet向けのELBだとACLやらSGの穴を開けるのがアレだったり、内部で制御しなきゃいけない部分が多かったりと苦労もありますが、Internal ELB、ステキ過ぎますね。

今日はこのリリースを聞いて、業務を忘れて触り始めてしまいました!(ぉぃぉぃ

CloudWatchからAWSの費用を視覚化してみた(の補足的情報だけ)

お久しぶりのエントリは、「Estimated Charge with CloudWatchを試してみました « サーバーワークス エンジニアブログ」こちらの記事をパクリ参考にさせていただきました。

詳しくは、サーバーワークスさんのブログエントリを参照してもらえば問題ないのですが、ちょっとはまったところがあるのでその点について触れておきます。

ハマったポイント

口座番号は整数で。

元記事やgistのソースでは、

ACCOUNT_NUMBER = 'YOUR_ACCOUNT_NUMBER'

のように示されているので、口座番号(Account Number)を文字列として定義してしまっていましたが、それではうまく動かずかなりハマりました。口座番号は整数で以下のように書きましょう。

ACCOUNT_NUMBER = 123456789012
dimentionsのLinkedAccountはConsolidated Billingを利用しており、かつ個別のアカウントの金額を取得したい場合のみ

こちらもハマった点。個人用アカウントは特に別アカウントがあるわけではなく、Consolidated Billing (複数アカウントの一括請求)を使っていないので、そもそも 「LinkedAccount」というdimentionは存在しないようだ。さらには、Consolidated Billingを使っている場合でも、全アカウントのトータルコストを取得したい場合には、LinkedAccountを指定してはいけない。

Consolidated Billingを使用していない、または、Consolidated Billingを使っていて合算した費用が知りたい場合

下のように、dimentionsには{"Currency"=>"USD"}のみを指定する。

data = acw.get_metric_statistics(options={:dimentions => {"Currency"=>"USD"},
                                          :measure_name => "EstimatedCharges",
                                          :namespace => "AWS/Billing",
                                          :start_time => starttime,
                                          :end_time => endtime,
                                          :period => 86400})
Consolidated Billingを利用していて、個別アカウントの費用が知りたい場合

こちらは、サーバーワークスさんの例の通り、LinkedAccountを指定する。

data = acw.get_metric_statistics(options={:dimentions => {"LinkedAccount"=>ACCOUNT_NUMBER, "Currency"=>"USD"},
                                          :measure_name => "EstimatedCharges",
                                          :namespace => "AWS/Billing",
                                          :start_time => starttime,
                                          :end_time => endtime,
                                          :period => 86400})

グラフを重ねる

元記事の方で使われているグラフライブラリのGruffは簡単にグラフを重ねられるので、トータル(LinkedAccount指定なし)と個別アカウント1と個別アカウント2をまとめてグラフ化なんてことも楽チン。

それぞれの金額遷移のリストを取得しておいて、以下のようにするだけ。

total_charge_list = 取得処理やらソート処理
acc1_charge_list = 取得処理やらソート処理
acc2_charge_list = 取得処理やらソート処理

graph_file = "#{Time.now.strftime('%Y-%m-%d')}-charge_graph.png"
g = Gruff::Line.new
g.title = "AWS Cost"
g.marker_font_size = 15
g.data("Total", total_charge_list)
g.data("account1", acc1_charge_list)
g.data("account2", acc2_charge_list)
g.labels = {0 => '5days ago', 1 => '4days ago', 2 => '3days ago', 3 => '2days ago', 4 => 'yesterday'}
g.write(graph_file)

これで、3つの線グラフを重ねたpngファイルが作成されます。簡単ですね。

最後に

参考にさせていただいたサーバーワークスさん、本当にありがとうございました!これで色々はかどります。

あと言いたいこととして、PythonのAWS APIライブラリのbotoは非常に素晴らしいのですが、CloudWatch周りだけはいかんせん弱い。というか、EC2用の機能の一部としてしか提供されていないので、EC2インスタンスに関する値しか取得できないのです。どうか、boto.ec.cloudwatchのような形ではなく、boto.cloudwatchのような感じで、全namespaceを扱えるようにしていただけると更にはかどって仕方なくなります。

CloudWatch周りの何かをするときだけPHPSDKを使ったり、今回はRubySDK(というよりはRightScaleのライブラリ)を使っているので、全く統一感がなくてよろしくないなあと思いつつも色々手を出してみているのが現状です。

それでは、botoがCloudWatchのすべてのnamespaceを扱えるようになることを祈りながら、今日はこのへんで。

※間違いなどありましたら、ご指摘ください。

第1回 アマゾン ウェブ サービス(AWS)オープンセミナー@VOYAGE GROUP に参加してきました (2012/03/21)

最近めっきりブログを書かなくなってきていますが、とりあえず生きています。
ただ、ちょっと業務に追われてブログに書けるネタが無かったくらいです(´;ω;`)

先日、2012年3月21日に開催された、「第1回 アマゾン ウェブ サービス(AWS)オープンセミナー@VOYAGE GROUP」に参加してきたので、そのレポート的なものを。
ustされてたんだから、書いても大丈夫だよね?

開始時刻を間違えていて遅刻したので途中からです。
間違いなどありましたら、ご指摘ください。

事例とデモで学ぶはじめてのAWS -アマゾンクラウドの最新動向-

AWSの大谷 ( @shot6 ) さんによる発表。(多分)初めて大谷さんの実物を大谷さんとして認識して見たのが、この時。

事例: Amazon ECサイト

  • 負荷に応じて1台単位で増減。
  • OracleのテープバックアップをやめてS3へ
    • リストア時間が大幅に減少!

事例: netflix

  • ビジネスアジリティを優先事項と考えてAWSを採用
    • DCを利用していると、サービスの成長にDCの成長が追いつかない
  • 映像のマスターテープのデータはS3に
    • そこから各種デバイス向けのencodingはEC2で

AWSの意義

改善 + 革新

質疑応答

  • EMRのデータをS3に上げるときは50MBからいのチャンクにしたほうが早い(アップロードは)。
  • 解析は大きなデータのほうがいい。

実例で学ぶAWS -オーディエンスデータプラットフォームcosmiを例に-

主催のadingoの中の人、岩川さんによる発表

  • AMI + AutoScale + EMRをメインに利用
  • ApacheのログをEMRで解析
  • AutoScaleはcpu使用率で
    • 懇親会で @shot6 さんが言っていたが、AutoScaleは増やすときは2項目のORで、減らすときは2項目のANDでと言っていた(酒により記憶が濁されていなければ)
  • EMRの解析結果はMongoに格納
  • 計算方法の変更があった場合は台数増やして遡って再計算させる
  • Mongoのデータは専用のEC2インスタンスからELBを介して参照

クックパッドはAWSで動いてます

クックパッドの成田 ( @mirakui ) さんのよる発表。
画像配信、サイト高速化を担当しているとのこと。

AWSへの移行

  • バレンタイン対策(一番少ない時の倍くらいのアクセス)
  • 当時インフラエンジニアが二人
    • 今は五人
  • 3倍ルール(3倍は耐えられる様にしておく)
  • 物理ハードの面倒だけで、他にやりたいことができない。
  • 今は物理サーバはない!
  • リソースあたりのコストは増
  • 箇条投資がなくなったので、結果あまり変わらず
  • 物理作業からの開放
  • ビジネススピードアップ

構成

利用方法

  • Base AMI + puppetで構築
  • tofu(自作)でサムネイル作成
    • 画像はすべてS3に
      • 何がすごいって、S3がスゲー!
  • R53(・∀・)イイ!!

質疑

  • Q: RDSじゃないのは?
    • A: 以前はTritonを使っていたから自前ビルドのMySQLが必要だった。
  • Q: Cloud FrontではなくAkamaiなのはなぜ?
    • A: その時はAKAMAIのが早かったし、ずっと使っていてノウハウがあったから。価格としても、性能の割には安い。
  • Q: R53がなぜいい?
  • MySQLスナップはどれくらいの頻度?取る時にはサービスはどうしてる?
    • A: 一日均等に4回。スナップを取る専用のスレーブがあって、スナップ取得時にはデーモンを止めて、レプリケーションも止める。
  • Q: ネットワークまわりのトラブルはある?
    • A: これまでは特にない。インスタンスがいきなり死ぬほうが多い。結構頻繁に。DBマスタに起きたこともあるけど、マルチマスタ構成にしたりしているから、長時間の停止はない。

 

HerokuはAWSで動いてます

Herokuエバンジェリストの相澤さんによる発表。
話したいことがたくさんあったらしいが、ustされていたため口を閉ざしてしまわれた。残念。

Herokuの構成

  • Routing Mesh (erlangで作ってある)
  • psmgr (プロセス単位で増減させる)
    • ダイノスという単位でプロセスを管理している
  • Add-on
    • アドオン対応すれば、tofuをHerokuで使えるようになるし、お金も入って来るようになるYO!

サポート

Herokuは基本英語での対応だが、ayuminさんに連絡すれば、日本語で対応してくださるとのこと。

質疑

  • Q: 東京リージョンは?
    • A: テクニカルには動かせるが、様々な政治的理由がある。あとはどれだけ使ってもらえるか。お金を払ってくれるユーザさんの声が鍵。

感想

コンサル的にSWXさんに協力いただいたりもしたけど、自分のとこでやっているNameタグとホスト名のひもづけ+内部DNSによる管理をクックパッドさんでもやっていることを知って、なんだか嬉しくなったw Base AMI+puppetってところも、うちはChefだけど近いし。あとは、監視周りをどうやって柔軟にしていくかがポイントかな。
※わけあって自分の所属企業は伏せています

VPC周りの近々来るであろうお話も大谷さんに聞けたのはすごく良い収穫。

やっぱり、AWSはどうやってサービスを組み合わせるかと、自分たちで自動化した柔軟な運用をできるかが大事なんだよな。