実践!ヌーラボサービスでの CloudFront の障害対策

CDNが単一障害点にならないようにするために

ヌーラボでは 2010 年 Cacoo の商用サービスの開始に合わせて AWS における運用を開始しました。当時、運用環境として AWS を採択する決め手の一つになったのが CloudFront でした。その後も着々とエッジロケーションは増え、独自ドメインのサポートなど魅力的な機能も提供され、今ではヌーラボの全サービスの静的ファイルの配信で利用している、無くてはならないサービスとなっています。

その魅力の反面、CloudFront の障害は、アプリケーションそのものに問題がなくても、以下のような表示が崩れた画面が表示されて、ユーザが全くサービスを使えなくなるという、その影響が非常に大きいものです。また障害の原因が DNS やネットワークの経路における問題といった、私たちが直接解決しにくい領域にあることもしばしばです。

ただ、どんな事情であれ、障害が起きたときにはユーザの皆様からみてサービスが利用出来ないことに変わりはありません。サーバを冗長化するのと同様、CloudFront をサービスの単一障害点としないように、ヌーラボでは各サービスにあわせた対策をとってきました。おかげで、2014年11月27日の 9:00 過ぎから 2 時間近くに及んだ CloudFront の障害でも、幾つかのサービスで復旧作業を要したものの大きな影響をうけることなくサービスを継続できました。

CloudFront の障害は過去 5 年の運用の中でも年に 1,2 回は起こっていること、障害の影響範囲の大きさなどから、対策をとったほうが良い課題だと考えています。そういった対策の検討をする際に、本エントリの内容が参考になれば嬉しく思います。

なお、本エントリの CloudFront の運用についての前提条件は以下です。

  • CSS、JavaScript、Flash、画像などの静的リソースを配信
  • CloudFront のオリジンは S3
  • 全て SSL
  • 一度配備されたファイルは変更しない

対策方針〜基本はフォールバック〜

さて、対策方針そのものはシンプルで、一時的に CloudFront の利用をやめ、別のところから静的ファイルを配信するように切り替えを行う、というものになります。配信元の切り替え先としては、代替 CDN (別のサービス) や、S3 、EC2、その他と幾つかのアプローチがあります。こちらは一時的な切り替え先ですので、パフォーマンスなどどこまで許容できるかはサービスの特性などにあわせて考慮すればよいかと思います。

代替CDNの選び方

ヌーラボの幾つかのサービスでは代替 CDN として KeyCDN を利用しています。 KeyCDN を採択した理由としては主に以下の通りです。

  • S3 をバックエンドに出来る (静的ウェブサイトホスティングを利用する前提)
  • 日本にエッジがある
  • 従量課金で最低金額が安かった ($25 のクレジットで月額の最低金額はなし)
  • Cross-Origin Resource Sharing (CORS) をサポートしている  (理由については後述)

 まず、S3 をバックエンドにできると、CloudFront 向けに配備したものをそのまま代替 CDN 側で利用出来ます。つまり、

  • 通常時 : https://xxx.cloudfront.net/R20141127_1/css/all.css
  • 切替時: https://xxx.alternativecdn.net/R20141127_1/css/all.css

のように、配信元のドメインの部分だけをアプリケーション側で切り替えて返しさえすれば、リソースを配備し直す必要がありません。また日本のユーザが多くを占めるサービスがあるため日本にエッジがあることも大事な条件でした。これらの条件を満たすもので他に検討したのが、Fastly や CDN77 でしたが、調査時点ではどちらも月額での最低利用料金があったため、代替 CDN としては少しコストがかかる感が否めず、最終的に KeyCDN となりました。

サービスによって重視したい条件は変わると思いますので、こういった比較サイト も参考にしていただければと思います。

切り替え方法

次に配信元の切り替え方法ですが、ヌーラボでは大きく分けて以下の2つの方式を採用しています。

  1. DNS による切り替え方式
  2. アプリケーションによる切り替え方式

前者は配信元を DNS によってアプリケーションは全く変更せずに切り替えるアプローチで、後者はアプリケーションで配信元のリソースの URL を切り替える方式です。具体的な方法と、その特徴などを詳細にみていきましょう。

1.DNS による切り替え方式

Backlog で採択しているのがこの方式です。まず CloudFront の 独自 SSL  オプションを使い、アプリケーションからは静的リソースとして独自ドメインの URL  ( 例: https://assets.backlog.jp/R20141119_1/script/common-libs.js ) を返します。そして Route53 にて  assets.backlog.jp の解決先として CloudFront のディストリビューションの Alias を設定しておきます。CNAME で指定しても良いのですが、名前解決のコストが発生するため、Route53 を利用する場合は Alias で設定しておくとよいでしょう。

また障害発生時の切り替えのために、アプリケーションの配備時に静的リソースを EC2 からも配信できるようにしておく必要があります。Backlog ではリバースプロキシとして利用している nginx から静的リソースを返せるようにしてあり、その前段に ELB があります。Backlog では SSL が必要なこともあり、S3 ではなく ELB を利用しています。

そして CloudFront に問題が発生した場合には、この assets.backlog.jp の解決先を ELB に切り替えて EC2 インスタンスからの配信に切り替えます。全体像は以下の図のようになります。

こちらで紹介されているように、Route53 を利用していれば、ヘルスチェックを利用して自動的に切り替えることも可能です。

この方式のメリットは何よりアプリケーションに全く変更を加えずに切り替えを行うことが出来る点です。最近ではウェブだけでなく、モバイルアプリを提供しているサービスが多いかと思いますが、そのどちらからも CloudFront のリソースを利用している場合には特にそのメリットを享受できるでしょう。デメリットは、クライアント側で名前解決の結果がキャッシュされた場合に障害が起こっているリソースを見に行き続ける可能性がある点です。

2.アプリケーションによる切り替え方式

2つ目はアプリケーションが返す静的リソースの URL を明示的に切り替える方法です。Backlog 以外のサービスでは全てこちらです。障害の対策をはじめた時はまだ CloudFront の独自 SSL オプションに SNI のサポートがなく比較的高価だったことや、配信元を複数から選択したかったこと、柔軟な切り替えを行いたかったことが主な理由です。

Typetalk や Nulab Account では基本的に CDN の設定を外出しにしてあり、設定ファイルの内容を書き換えてアプリケーションを再起動するだけで配信元を切り替えれるようにしています。この方式では先の DNS による切り替えと同様、サービス全体で配信元を切り替えるようになっています。

Cacoo ではさらに一歩進んだ形でアプリケーション切り替えを実装しています。Cacoo は全世界の広い地域にユーザがいる事と描画エディタが Flash ファイルでサイズが大きいことから、CloudFront 障害時にも CDN の利用は必須です。また、利用地域が分散されているため特定のネットワークのみで発生するような問題をそもそも検知出来ない可能性があることや、検知出来たとしても特定環境のみの問題のために、全体の CDN を切り替えることで多くのユーザが逆に不便になる可能性もありました。そういった背景から、Cacoo では

  • クライアント側から CloudFront へ定期的にヘルスチェック
  • 問題があった場合、そのクライアントからのリクエストのみ代替 CDN に切り替える

というアプローチを取ることにしました。

まず下準備としてヘルスチェック用にテキストファイルを用意して S3 に配備します。このファイルは XHR にてアクセスされるため CORS を有効にしてクロスドメインでのリクエストを許可するようにしておきます。やや複雑に見えるかもしれませんが、当初 img タグによる画像の読み込みでの判別を試みたところ、ブラウザの読み込みの中断などと障害との判別が難しかったため、Ajax によるヘルスチェックに切り替えたという経緯があります。

処理の大まかな流れは以下のようになります。

  1. ページのロード後に配信元 A のヘルスチェックを実行
  2. 所定回数のリトライ後も失敗した場合は配信元を B にしてヘルスチェック
  3. 成功した場合、配信元 B を表す値を Cookie にセットしてブラウザをリロード
  4. サーバ側では Cookie 値に基づいて配信元 B を静的リソースの URL として HTML を表示

ヘルスチェックは以下の図のように優先する順番 ( CloudFront > KeyCDN > S3  ) にて行います。S3 までチェックしても問題がある場合は最終的には EC2 から配信します。

他にも以下のような実装上の工夫をしています。

  • CDN のフォールバックが発生した場合、一定期間はヘルスチェックをしない
  • リカバリを検知した場合は配信元を切り替える Cookie を削除する
  • 明示的な障害の場合は優先する配信元の順序を変えて ( 例: KeyCDN > CloudFront > S3  )、フォールバックが起こらないようにできる
こちらの切り替え方式のメリットは、柔軟に切り替え先を切り替えること、作り込み次第では Cacoo でやっているようにユーザ毎に配信元を切り替えることができます。また明示的に URL を変更しますので DNS 方式のような名前解決のキャッシュのような問題が発生しえません。ただし反面、ある程度アプリケーション側の作り込みにコストがかかり、Route53 を利用した場合ほどの手軽さで自動的切り替えを実現するのは難しいというデメリットがあります。

まとめ

これらの方式の特徴、メリット・デメリットは以下のようになります。

  特徴 メリット デメリット
DNS による切り替え方式

配信元の名前解決を切り替え

障害時発生時にアプリケーション側の対応は不要

アプリケーションの変更が不要

Route53 を利用すれば自動切り替えも手軽に実現可能

サービス全体での切り替えしか出来ない

名前解決の結果がキャッシュされていると問題を解決できない 

アプリケーションによる切り替え方式

アプリケーションで配信元の URL を切り替え

障害発生時の振る舞いは作りこみ次第

・複数の代替 CDN の利用

・ユーザ毎に配信元を変える

など柔軟な切り替えが可能

 

作り込みのコストが高い

どちらも各々特徴がありますが、Route53 を使っている場合には自動切り替えも簡単に実現できますので、まずは DNS による切り替えを試す価値は高いと思います。その後、サービスの特性にあわせてアプリケーションによる切り替えを検討すると良いと思います。


ヌーラボではサービスを支えるインフラエンジニアを絶賛募集中です!

ヌーラボではこういったサービス運用におけるインフラ面の課題を、開発チームと一丸となって解決するインフラエンジニアを募集しております!ヌーラボのサービスをインフラ面からより良くしていくことに興味がありましたら、是非ご応募お待ちしております。詳細はこちらの採用情報のページから!

 

カバーイメージ : Do not fear failure by Tomasz Stasiuk

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる