Fastly VCL 入門2 - Programming the edge 

###はじめに

[前回の記事](https://qiita.com/AtsushiFukuda/items/db26ce0f75998e7e4385)では VCL の基本的な書き方を説明しました。続いてこの記事では、実際に具体的な処理をいくつかテストしていきたいと思います。

ところで Altitude という サンフランシスコやロンドン、ニューヨークで年に一度開催されている Fastly のカスタマーイベントがあるのですが、そこで Fastly のエンジニアである Andrew Betts が前回の記事で紹介した Fiddle を使ったセッションを行いました。その内容が VCL で具体的な処理を書いていく手順を理解するためにとても良い内容なので、この記事ではその内容を紹介したいと思います。

ちなみに Andrew が Fiddle ツールを作った本人です。セッションの内容は Vimeo でも公開されているので、英語ですが以下のリンクから視聴可能です。

[**Altitude Lon 2018: Programming the edge workshop | Andrew Betts, Fastly**](https://vimeo.com/273991567)


---

### 1. Basic - Fiddle の基本的な使い方

この記事で紹介するサンプルは [Fiddle : https://fiddle.fastlydemo.net/](https://fiddle.fastlydemo.net/) を利用します。

**Fiddle に記載したコードは特にアクセス制限などがかかるわけではないので、誰からでもアクセスされる可能性があります。パスワードや機密情報など、外部に漏れて困る内容はコードに含めないように注意して下さい。**



前回の記事でも紹介しましたが、ツールの基本的な使い方は以下の通りです。

1. Origin Servers の下にコンテンツを取得するオリジンサーバーを指定（デフォルトのままでも大丈夫です)
2. Custom VCL と記載されている箇所の各サブルーチンの下のテキストフィールドにVCLのコードを記入
3. 右側のSend a request の下のフィールドにテストしたいリクエストのパスを記入
4. 右側のRunボタンをクリック

RUN ボタンをクリックすると、入力内容を反映した新しい設定が作成され、実際にリクエストを送信してその結果を表示します。結果は通常10秒以内に表示されます。

リクエストパスを入力するフィールドの下にある Headers や Options などから、リクエストに付与するヘッダーを追加したり、リクエスト実施前に対象の URL に対する PURGE を実行することも出来ます。

なお、ページにデフォルトで表示されているオリジンサーバー `https://httpbin.org` は Fastly とは関係のないサービスですが、リクエスト内容に応じて指定してレスポンスヘッダーなどを返してくれる便利なサービスです。
たとえばオリジンサーバーからXXXというレスポンスヘッダーが返却された場合の処理を試してみたい、などといった場合に手軽にテストをすることが出来ます。

レスポンスヘッダーを追加したい場合は、以下のようにパスを`/response-headers`とし、クエリストリングでレスポンスに含めてほしいヘッダー名と値を指定します。レスポンスヘッダーは複数指定することも可能です。
`http://httpbin.org/response-headers?header1=abc&header2=def`




それでは、実際に Fiddle のを試してみます。ここでは以下の手順を実施して下さい。

1. [Fiddle](https://fiddle.fastlydemo.net/)を新しいタブで開く 
2. 左側の Origin Servers の下のフィールドに `https://example.com` と入力
3. 右側の Send a request の下のフィールドに `/` を入力
4. Run をクリック

結果画面が表示され、Resultとして以下のような内容が表示されます。

**Request to Fastly**: Fiddle から Fastly に送られたリクエスト
**RECV**: リクエストを受けたFastlyサーバーのvcl_resvの処理
**MISS**: キャッシュにヒットしなかったのでvcl_missの処理
**Request to Origin**: Fastly サーバーから指定したオリジンサーバーへのリクエスト
**Response from Origi**n: オリジンサーバーからのレスポンスの内容
**FETCH**: レスポンスをうけてvcl_fetch の処理
**DELIVER**: Fastly サーバーからクライアントにレスポンスを配信
**Response from Fastly**: レスポンスヘッダーの内容
**Response body**: レスポンスボディの内容
**Insight**: 結果に対する設定の推奨内容

![image.png](https://qiita-image-store.s3.amazonaws.com/0/128569/b143abf1-8ebc-8cf4-5590-ed5572ab2ac3.png)


何も変更せずにもう一度 RUN をクリックすると RECV の次に MISS ではなく HIT が表示されます。これは最初のリクエストした結果が Fastly サーバーにキャッシュされたため、2回目のリクエストにはキャッシュから返信されたことを意味します。


---

### 2. GeoIP headeres - 11分12秒から

通常 Fastly はエンドユーザーからリクエストを受けると、オリジンサーバーにそのままリクエストをフォワードします。
これを Fastly を使ってエンドユーザーの地域情報をリクエストに付与してオリジンにフォワードする設定を作成してみます。
オリジンサーバーは追加された情報をコンテンツを出し分けたりするために利用することが出来るようになります。

<img width="740" alt="Programming_the_edge_workshop_-_Google_Slides.png" src="https://qiita-image-store.s3.amazonaws.com/0/128569/d91b7cd2-3b3f-22bb-b93a-c806c8de96a0.png">

それでは以下の手順を行って下さい。

1. fiddle.fastlydemo.net をブラウザの新しいタブで開く
2. “Click to set title” と書かれているタイトルフィールドに GeoIP headers (ex 2) など任意のタイトルを入力
3. “Custom VCL” の下の RECV に、以下のコードを入力　(REV フィールドが開いていない場合はクリックしてフィールドを開いて下さい）:

```
set req.http.client-geo-continent = client.geo.continent_code;
set req.http.client-geo-country = client.geo.country_code;
set req.http.client-geo-city = client.geo.city;
set req.http.edge-geo-datacenter = server.datacenter;
set req.http.client-source-network = client.as.number;
```
🎓 Fiddle ではコードの自動補完機能があります。入力中にコードが補完され、エラーがある場合はエラーも表示されます。

　4. Run をクリック
表示された結果はどうなっていたでしょうか？ VCL で追加したヘッダーがハイライトされて表示されていることを確認して下さい。

以下のリンクから正しい結果を確認できます。比較して同じになっているか比較してみて下さい。
https://fiddle.fastlydemo.net/fiddle/7a6cbc28

なお、オリジンサーバーが Fastly が追加したアクセス元の地域情報に応じてコンテンツを出し分ける場合、コンテンツを出し分けていることを Fastly サーバーに通知する必要があります。これはVary ヘッダーを利用することで実現できます。Fiddle でデフォルトのオリジンに設定されている リクエストする Path を`/response-headers?vary=client-geo-country` と指定することで、 Httpbin サーバーから指定した内容の Vary ヘッダーを返却させることが出来ます。

---


### 3. RUM のログ収集 - 16分30秒から

Fastly ではログを収集して指定したエンドポイントに送信することが出来ます。このログはリアルタイムに送信され、人気があるコンテンツを見つけるためや、障害の分析、サーバーサイドでのアクセス解析ツールなどで利用することが出来ます。

また、Real User Monitoring（RUM) として知られるクライアントサイドでのパフォーマンスや行動分析では、何らかの方法でユーザーから送られてくる情報を収集する必要があります。通常はページのロードが終了すると、"ビーコン リクエスト(beacon request)" と呼ばれるリクエストをブラウザやクライアントアプリケーションが送信し、サーバー側でデータとして収集します。

データの性格上、このビーコンリクエストの数は膨大になりがちです。これらのリクエストがオリジンサーバーに送られ、スケーリングに悩まされないように、Fastly を使ってこれらのデータを効率的に収集してみましょう。

Fastly を利用することで、 オリジンサーバーに変わって Fastly がクライアントにレスポンスを返却するので、オリジンへのリクエストを発生させずに必要なデータだけを収集することが出来ます。

![Programming_the_edge_workshop_-_Google_Slides.jpg](https://qiita-image-store.s3.amazonaws.com/0/128569/572f3bae-c536-cdf4-dba9-c86a3d0b5439.jpeg)

1. fiddle.fastlydemo.net をブラウザの新しいタブで開く
2. “Click to set title” と書かれているタイトルフィールドに RUM Logging (ex 3) など任意のタイトルを入力
3. “Custom VCL” の下の RECV に、以下のコードを入力　(REV フィールドが開いていない場合はクリックしてフィールドを開いて下さい）:

```
if (req.url ~ "^/log/?") {
  error 601;
}
```
このコードでは、リクエストが`/log/?`だった場合にステータスコードを 601 にセットして vcl_error の処理を送ります。
　4. ERROR に、以下のコードを入力:

```
if (obj.status == 601) {
  log "syslog " req.service_id " logger_name :: " req.url.qs;
  set obj.status = 204;
  set obj.response = "No content";
  return (deliver);
}
```
上のステップから vcl_error に来たリクエストを `obj.status` で拾って、クライアントに返却するレスポンスを生成します。こうすることでオリジン側にリクエストを送ることなくログだけを処理することが可能になります。
また、ログには `req.url.qs` が設定されているので、クエリストリングの内容がログとして送信されます。

　5. Run をクリック
Step 3で入力した条件に合致しないため入力したコードは実行されません。

　6. Send Request の下のフィールドにリクエストパスとして以下を入力
　`/log?field1=foo&field2=bar&field3=42`
　7. Run をクリック
ERROR の下にログとして送信された内容が表示されます。
![Fiddle_-_Fastly.jpg](https://qiita-image-store.s3.amazonaws.com/0/128569/2f90db7b-8355-0192-4c88-955ff070d6da.jpeg)

🎓 実際のサービスでは ERROR コードの中の logger_name に、実際に設定したログエンドポイントの名前を指定する必要があります。ログのエンドポイントは Amazon S3 や Google Cloud Storage のようのストレージサービスや、 logentries, papertrail といったサービスを指定することが可能です。
Fiddle ツールではログは実際には送信されずに結果フィールドに表示されます。

　8. ERROR のコードを以下に置き換え:
単にユーザーから送信された情報をログとして送るだけでなく、Fastlyで情報を追加することも出来ます。

```
if (obj.status == 601) {
  set req.url = querystring.add(req.url, "city", client.geo.city);
  set req.url = querystring.add(req.url, "dc", server.datacenter);
  log "syslog " req.service_id " logger_name :: " req.url.qs;
  set obj.status = 204;
  set obj.response = "No content";
  return (deliver);
}
```

上記のコードではクエリストリングを追加する `querystring.add` 関数を使って情報を追加しています。

実行結果が、以下のリンクと同じになっているか確認してみて下さい。
https://fiddle.fastlydemo.net/fiddle/e7571809

---

### 4. リダイレクト - 27分20秒から
Fastly でよく使われる機能に Redirect があります。リダイレクトをエンドユーザーに近い Edge で返却することはパフォーマンスの面でもオリジンの負荷軽減の面でも意味があります。

リダイレクトのリストを Edge Dictionary という機能を使うことで、大量のリダイレクトを簡単に管理することが出来ます。

![Programming_the_edge_workshop_-_Google_Slides.jpg](https://qiita-image-store.s3.amazonaws.com/0/128569/75a7425c-0ac9-24bf-8283-156121dddb28.jpeg)

1. fiddle.fastlydemo.net をブラウザの新しいタブで開く
2. “Click to set title” と書かれているタイトルフィールドに Redirects (ex 4) など任意のタイトルを入力
3. “Custom VCL” の下の INIT に、以下のコードを入力:

```
table redirects {
  "/source1": "/dest1",
  "/source2": "/dest2"
}
```

ℹ️ ここで指定した Edge Dictionary の内容は、実際の本番環境では API を通じて Edge Dictionary を作成、削除、変更することができます。API で作成した Edge Dictionary も上記と同じフォーマットで VCL 上に表示されます。


　４．RECV に以下のコードを入力:

```
if (table.lookup(redirects, req.url)) {
  error 601;
}
```

リクエストされたパス `req.url` が、Edge Dictionary のredirects テーブルに含まれるかをチェックし、一致するレコードがある場合はステータスコードを 601 にして error に処理を飛ばす。

　５．ERROR に以下のコードを入力:

```
if (obj.status == 601) {
  set obj.status = 301;
  set obj.http.Location = "https://" req.http.host table.lookup(redirects, req.url);
  set obj.response = "Moved permanently";
  return (deliver);
}
```

ステータスコードが 601 の場合、req.url をキーにして redirects テーブルから取得した パスをリダイレクト先に設定した 301 レスポンスを作成。

　６．Run をクリック
リクエストしたパスが Edge Dictionary に設定されたレコードと一致しないのでリダイレクトは発生せずに普通に処理が行われる。
　７．リクエストパスを以下に変更:
`/source1`
　８．Run をクリック
リダイレクトレスポンスが返却され、オリジンへのリクエストは発生しなければ成功です。


以下のリンクと結果が同じになっていればテストは成功です。
https://fiddle.fastlydemo.net/fiddle/2a1bc94b


---

Andrew のプレゼンテーションのビデオでは、この後 A/B テスト と Shielding の実装方法を説明しているのですが、ここで説明すると長くなってしまうので今回の記事はここまでにしたいと思います。
興味のある人はビデオをみて是非チャレンジしてみて下さい。

また、Fastly の VCL を利用した様々な処理のサンプルが [Soulitions library](https://www.fastly.com/demos)で確認することが出来ます。是非このページも見てみて下さい。