nakamura244 blog

所属団体とは関係なく、個人的なblog

頻繁にdeployしながらCDN(CloudFront)化のキャッシュclear,lifecycleの付き合い方

静的コンテンツ(CSS,Image,JS)をCDNから配信するとサイトの表示スピードが格段にあがるよってゆう話はかなり今更感ですが、それは前提として1日何回もデプロイを繰り返すサービスを考慮するとCDNのキャッシュとライフサイクルにどううまく付き合うかが結構課題になってきたりします。

そんな課題にどうやって対処したかをまとめておこうと思います

全体説明

f:id:tsuyoshi_nakamura:20160926142134p:plain

  • 静的コンテンツ(CSS,Image,JS)はすべてS3に格納
    • S3を通常のバケットとして設定
  • 以前は直接S3のURLを参照してコンテンツを配信していたが、パフォーマンス的にNGなので今はCloudFrontから配信している
  • 静的コンテンツ以外はELBにアプリケーションサーバ群が存在、その先にDB等がある。storage系は今回省略

抱えていた・想定された課題

  1. CDN(CloudFront)からコンテンツを配信した場合、キャッシュの更新が全世界のエッジロケーションに行き渡るまで最大20分程度かかってしまう
    • 即時反映させないとサービス運用上厳しい時があって困った 😩
  2. 静的ファイルのrevision管理(ハッシュプレフィックス)を行ってもリリースのたびに過去のゴミファイルが増えて続けてしまう
    • S3のアクセスログからアクセスが無くなったタイミングでdeleteする運用すれば良いかもしれんが面倒すぎる 😰
  3. 通常のリリース中に表示の不具合等が起こってた
    • リリースは①〜③で順にELBからサービスアウト、ソースの更新、サービスイン。④で静的コンテンツ(S3)に世代管理もしていなく、アクセスを受けているディレクトリにゴリっとデータをSync
    • リリース時間中は新旧のソースが入り混じる状態でアクセスを受けてレスポンスしている為に表示の不具合が発生....なんどもデプロイすると問題が表面化してくる😱
    • 詳細
      1. ソースがまだ古い旧アプリサーバがレスポンスを返す時は旧versionのhtmlを
      2. ソースが更新された新アプリサーバがレスポンスを返す時は新versionのhtmlを
      3. 静的コンテンツはあるタイミングでゴリっと変わる
      4. 2のhtmlでSync前の静的コンテンツを呼び出してレンダリングした場合、表示が壊れる... 😰
    • BlueGreenDeployment的な思考が必要...だ

取り組んだ内容

  • S3に配置するファイルをリリースをする度に世代管理した。リリースをする度にyyyyより下層ディレクトリが増えていく
    • 時間軸を世代管理に利用したのはCDNのキャッシュを考慮した為
      • 毎度新しいstatic fileのpathにする事で一回目のアクセスで必ずoriginサーバからキャッシュにのり、最新のデータが配信できる
      • AWS S3のライフサイクル設定(ルールターゲット)で引っ掛けて不要ファイルがdeleteしやすい
        • 何度もデプロイを繰り返す上で数日前のversionのstatic fileとかはもはやゴミ
└── bucket_name
    └── revision
        └── yyyy
            └── mm
                └── dd
                    └── His
                        ├── css
                        ├── image
                        └── js

  * yyyyはリリースをした年
  * mmはリリースをした月
  * ddはリリースをした日
  * Hisはリリースをした時間(secまで)
  • リリーススクリプトからリリース時にアプリケージョンサーバが参照する静的コンテンツを指定できるようにした。課題3のクリア😀
    • Shell職人気味だけど
    • アプリケーションは必ず上記で指定された静的コンテンツを参照するようにした
    • リリース時間中でもアプリケーションと静的コンテンツのversionがずれる事なく参照できるようなったので表示不具合は無くなった😬
    • これで1日なんども安心してデプロイできるようになった😆
    • リリースの度に新しく世代管理された静的コンテンツを参照する為、必ず新しいURL参照になるのでCDNのキャッシュクリアを気にする事なく即時反映を実現できた。課題1のクリア🙂
  • ライフサイクル設定でリリース日から前月のコンテンツをdeleteした docs.aws.amazon.com
    • 無駄なゴミファイルを削除が実現できた。一ヶ月前のリリースのバージョンの静的ファイルは確実に要らないと断言できたので。課題2のクリア😀

ついでに改善した点

  • キャッシュの有効時間設定をheaderオプションを使って設定した docs.aws.amazon.com
    • CloudFrontの管理画面でも設定できるけどユーザのブラウザキャッシュも有効に活用したいのでheaderオプションを活用

最後

  • AWSのライフサイクル設定はもっと早いサイクルでも全く問題ないと思った
  • S3自体でもバージョニング機能が存在するけど結論、オペミスによるファイルの復活させるレベルの使い方になると理解した docs.aws.amazon.com
  • これで安心して何度もデプロイしてリリースするまでの改善スピードをあげていける
  • 今回はgitにcommitしてあるCSS,Image,JSが対象とした話
    • Imageだとユーザがアップロードするものもある。更新されるタイミングが異なるので今回とはまた別の話
  • 各static fileの名前をハッシュプレフィックスをつけておくとS3上のI/Oが良くなってリリース時間が短縮できるっぽい docs.aws.amazon.com