2020-04-12に更新

NowのエッジキャッシュでCloud Storage節約サーバー作成

ZeitのNowは標準でCDNがついています。それを利用してCloud Storageで公開している画像をキャッシュさせて料金を抑えるためのサーバーアプリケーションを作成しました。改造すればS3用としても使えると思います。GitHubでソースや使い方も公開しています。

ちなみに、実運用ではまだちょっとしか試していないため現時点では実際に料金がどうなるかは未検証です。 ずっと試していますが恐らく節約にはなっていると思います。

一応テストした限りでは下記のようにキャッシュはされているようです。(HITになっている)

具体的にどういうことか

Cloud StorageはGCPのサービスのうちの一つで、ファイルを保存することができます。また、設定により画像などをそのまま公開してWebページ用に利用することもできます。

ただ、表示するための通信量などにより課金されるため、無料枠はあるのですがちょっとアクセスが多くなる時などはオーバーすることもあります。そういった時に、他のサーバーなどで画像をキャッシュしておいてそこから配信を行えばCloud Storage側の通信がなくなるため、料金を節約することができます。

なぜNowを使うのか

適当なクラウドを使うと結局そこの通信量がかかったりするため、CDNのエッジキャッシュで配信するのが一番効率的なのではないかと思います。ZeitのNowだと無料ですしデプロイも非常に簡単ですのでそこで可動できるようなCloud Storage Proxyサーバーを作ってみました。

しかもどうもデフォルトでCDN配信を行ってくれるようで、画像の拡張子で適切なヘッダを送信しておけば勝手にエッジキャッシュを行ってくれるようです。元々は独自ドメインを設定してCloudflareでCDN配信しようと思っていたため、手間が省けて助かりました。

また、メインのアプリケーションと分離しての作成になるため、どのサービスにも使い回すことができます。

元々メインアプリケーションに組み込んで作ろうと思っていたのですが、下記の記事を見て非常に作成が簡単にできそうだったので一気に作りました。

Now でクラウドの複雑さから解放されよう、今すぐに - Qiita

使い方

Nowにデプロイしたら、下記のようなURLにアクセスします。

 https://{{ nowのデプロイホスト名 }}/{{ Cloud Storage上のファイルパス }}

プロジェクトIDやバケット等は事前に環境変数で指定しておきます。ここにアクセスすると同じパスのCloud Storage上のファイルを取得し、そのままブラウザに表示します。CDNキャッシュ可能な拡張子やレスポンスヘッダのため、キャッシュ状態がHITになり、以後はCDN上から配信されるため、Cloud Storageへのアクセスが減ります。(多分エリアやタイミングによってキャッシュ状態が変わる可能性があるので完全ではなさそうな気がします)

ソース

メイン処理だけ見ると下記のようになります。

module.exports = async (req, res) => {
  const contentType = getContentType(req.url)
  const path = req.url.substr(1)
  const file = bucket.file(path)
  const image = await getRawData(file)

  res.writeHead(200, {
    'Cache-Control': 'public, max-age=315360000',
    Expires: new Date(Date.now() + 315360000000).toUTCString(),
    'Content-Type': getContentType(path),
    'Content-Length': image.length
  })
  res.end(image)
}

GitHubで公開していますのでご興味があれば遊んでみてください。改造すれば色々な使い方ができると思います。

dala00/cloud-storage-proxy

追記)
ちなみに元々上記でやっていたようにGCPのjsonファイルを直接アップする方法ではなく、Nowの方で連携できるやり方があるのでそちらに対応しておきました。詳しくは下記参照です。

Google Cloud - Integrations - ZEIT

Zeit Nowの具体的なTips集 - Qiita

試験運用中

この記事の最初の画像もNowからの配信のものです。URLも下記のようになっています。

[https://crieit.now.sh/upload_images/bd7e316e8d8673d87a278823386ae3245c8cfe20b742c.png](https://crieit.now.sh/upload_images/bd7e316e8d8673d87a278823386ae3245c8cfe20b742c.png)

懸念点

最初にも書きましたが、料金については運用して検証していますが、実際どれほど節約になっているかは細かく計算はしていません。通信量は減ると思いますが、オブジェクトの取得オペレーションが無料枠を超えてしまう場合もあると思いますのでその場合は別途料金が発生してくる可能性があります。

ですので、もし柔軟なカスタマイズが可能であればバズっている記事や人気の記事だけその画像を使うように置き換えると良いかもしれません。とはいえ、多分ちょっとした個人開発レベルであれば大丈夫ではないかと思いますが…。

あまりに通信量が多くなると今度はNow側も無料ではいけなくなる可能性もあります。(…が、サーバーはともかく、CDNの通信量も関係あるんでしょうか?)このあたり詳しい事が完全に理解できているわけではないので色々試してみる必要はあるかもしれません。とにかく、むちゃくちゃ大規模なサービスで無料にしちゃおう、みたいなことは難しい可能性があります。

なんにしろ引き続き検証していきます。

追記)
一応バズったりした時に200円くらい行ったりしたのが大体常時50円以下になったような気がするような気もします。

あとCDN関連でいうと他にもこんな遊びもしています。

Crieitの記事詳細ページが日本の技術系投稿サービスで最速になった

ツイッターでシェア
みんなに共有、忘れないようにメモ

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, React, Flutter, Vue.js, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント