LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログ

Varnish から Fastly CDN に移行した際のハマりポイントとその修正方法

こんにちは、インフラエンジニアの小林です。

現在LCLでは、EC2構成のシステムをECSに移行するプロジェクトが進行中です。

その際に EC2 内に入っていた Varnish を SaaS である Fastly に移行しましたが、その際に手こずったポイントをご紹介します。

Varnish と Fastly CDN とは?

Varnish と Fastly CDN はどちらもCDN(Content Delivery Network)ですが、Varnish はサーバ上で動作するオープンソースのソフトウェアであり、Fastly はSaaS 型の CDN です。

なお、Varnish とそのライフサイクルをご存じない方は、以前私が書いたこちらの記事を参照いただけると、本記事の理解がより深まるかもしれません。

https://blog.kasei-san.com/entry/2019/01/24/000222blog.kasei-san.com

弊社の一部の web システムでは、1台のEC2上に Varnish -> Nginx -> Unicorn という構成をつくり、アプリケーションに到達する前のリクエストをキャッシュしていました。

しかし、そのようなの構成では以下のような運用上の課題がありました。

  • 複数サーバを運用する場合に、同一内容のキャッシュが保持されてしまい効率が悪い。
  • キャッシュサーバを自前で運用するため、運用コストが高い。
  • 大量アクセス時に Varnish がボトルネックになることがある。

そのため、システムをECSに移行するにあたって CDN を Fastly CDN に移行いたしました。

Fastly CDN は、Fastly が提供する SaaS 型の CDN で、以下のような特徴があります。

  • 世界中にエッジサーバがあり、ユーザーに最も近いサーバーからキャッシュされたコンテンツが提供されるため、アクセス速度が早い。
  • Varnishをベースにしているため、Varnishと同一の VCL ファイルが使用可能。
  • SaaSであるため、運用コストが最低限。

Amazon CloudFront など他に CDN を提供するサービスはありますが、コストや移植容易性を鑑み Fastly を採用しました。

Varnish から Fastly CDN へ VCL への移行方法

カスタムVCLを使用するのが効率が良いです。カスタムVCLでは、複数の VCL ファイルを Fastly にアップロード使用できます。

docs.fastly.com

カスタムVCLは Terraform でも以下のように簡単に記述できます。

  vcl {
    name    = "main"
    content = file("${path.module}/vcl/main.vcl")
    main    = true
  }

  vcl {
    name    = "mobile_detect.vcl"
    content = file("${path.module}/vcl/mobile_detect.vcl")
  }

  vcl {
    name    = "idou.vcl"
    content = file("${path.module}/vcl/idou.vcl")
  }

main: true の VCL が main となり、他のVCLは main から読み込まれる構成となります。上記の例では、既存のファイル構成をそのまま Fastly に持ち込みたかったため、3つのファイルに分けてアップロードしています。

Varnish の VCL と Fastly CDN の VCL の違い

Fastly CDN は Varnish からフォークしており、同一の設定ファイル(Varnish Configuration Language)を使用できます。

しかし、Fastly CDN の VCL は Varnish 2.1 系から派生しており、LCLで使用してした Varhish は 4.1.1 であったため、いくつか修正が必要となりました。

ただ、基本的にはアップロードしたカスタムVCLのコンパイルエラーのメッセージを元に修正していけば、問題ありませんでした。

以下に、コンパイル時に発生したエラーと、その修正方法を紹介いたします。

pipe is disabled

Fastly の VCL では、return (pipe); は使用できません。弊システムの場合、return (pass); でも問題ない内容でしたので、return (pass); に変更しました。

Fastly マクロを入れないと、Fastlyの独自の実装や、動的スニペットが無視される

Fastly の VCL では、各ライフサイクルのサブルーチンに独自のマクロを追記する必要があります。(例えば、sub vcl_recv の次の行に #FASTLY recv など。) これらのマクロにより、コンパイル時にFastlyの独自の実装が VCL 内に追加されます。

意図的にそうする必要が無い限りは、マクロを入れておかないと想定外の挙動をしてしまうため、注意が必要です。

Fastly マクロについては、以下のドキュメントにも書かれていますので、ご参照ください。

www.fastly.com

vcl_hash は独自実装すると、#FASTLY hash のデフォルトの挙動が消える

おなじく、Fastly マクロ関係の問題です。

VCL では vcl_hash というサブルーチンで、キャッシュのキーを設定できます。これにより、例えば、機種の判別を hash に追加することで、同一URLでもPCとスマホで異なる内容のキャッシュを保持することができます。

vcl_hash は、独自実装しない場合、以下のようなコードが Fastlyマクロから展開されます。

sub vcl_hash {
#--FASTLY HASH BEGIN
  #if unspecified fall back to normal
  {
    set req.hash += req.url;
    set req.hash += req.http.host;
    set req.hash += req.vcl.generation;
    return (hash);
  }
#--FASTLY HASH END
}

しかし、 vcl_hash を独自実装した場合、上記のコードは消えてしまうためreq.urlreq.http.host を hash に加えたい場合は、それぞれ自前で実装する必要があります。

set req.hash += req.url;
set req.hash += req.http.host;

マクロ展開時のコメントに、その旨書かれているのですが、見落としてしまいかなりハマりました……

vcl_hash の戻り値は、return (lookup); ではなく return(hash);

こちらは、VCLのバージョン違いによる問題です。 vcl_hash の戻り値は return(hash); にする必要があります。

www.fastly.com

vcl_backend_response は、vcl_fetch に修正する

こちらも、VCLのバージョン違いによる問題です。

Varnish 4.0 でサブルーチン vcl_fetchvcl_backend_response にリネームされました。そのため、Fastlyでは vcl_fetch に戻す必要があります。

varnish-cache.org

beresp.uncacheable は使えないので、beresp.cacheable に変更

同じく beresp.uncacheable は Varnish 4.0 で実装されたため set beresp.uncacheable = true; のかわりに set beresp.cacheable = false; を使う必要があります。

varnish-cache.org

std.duration も使えないので、代わりに parse_time_delta を使う

std.duration は、文字列を秒に変換する処理です。以下のような形で、キャッシュ時間を動的に変更するために使用していました。

  if (bereq.http.X-set-ttl) {
    set beresp.ttl = std.duration(bereq.http.X-set-ttl,beresp.ttl);
    unset bereq.http.X-set-ttl;
  }

こちらも(おそらく)バージョン違いのため、使用することができず、代わりに parse_time_delta を使用しました。

  if (bereq.http.X-set-ttl) {
    set beresp.ttl = parse_time_delta(bereq.http.X-set-ttl);
    unset bereq.http.X-set-ttl;
  }

www.fastly.com

まとめ

今回の記事では、Varnish から Fastly CDN への移行時に直面したいくつかの課題とその解決策について紹介しました。VCLのバージョン差異やFastly特有の仕様に対応するための修正が必要でしたが、全体としては大きな変更なく移行を進めることができました。

Fastly CDNも、Varnishもドキュメントが充実しているため、困ったことが合った場合は、ドキュメントに当たればすぐに解決することができました。やはり、公式のドキュメントは重要ですね……。

本記事が皆様の Fastly 移行へのご一助になれば幸いです。