FastlyでLoad BalancingしつつオリジンごとにHostヘッダを書き換える

現在この方法は必要なくなりました。
下記のように backend 毎に設定できる override host 設定を使うことが推奨されています。

https://docs.fastly.com/ja/guides/specifying-an-override-host#%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%B3%E3%83%AC%E3%83%99%E3%83%AB%E3%81%A7%E3%83%9B%E3%82%B9%E3%83%88%E3%82%92%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%A9%E3%82%A4%E3%83%89%E3%81%99%E3%82%8B

---

### 先に結論
`director`を使って`set req.backend = autodirector_;`のような処理を入れた場合、各サブルーチンから`req.backend`の変数を参照することが出来ません。理由としては、最終的にbackendが決定されるのが`vcl_miss`を通りオリジンにリクエストを発行する直前であるため、例え`vcl_miss`の内部であっても変数の値を知ることができません。
これにより、例えばオリジンに2つのS3バケットが設定されており、それぞれのS3バケットにアクセスする際にHostヘッダを書き換えたい場合、実際に`set req.backend = autodirector_;`によってどちらのbackendが選択されたか知ることが出来ないため、適切なHostヘッダを設定できません。

回避策として`randombool()`を使って類似の振る舞いを実現するのが本記事のゴールです。

# FastlyでLoad Balancingを使う
Fastlyで複数オリジンに対してLBさせるには二通りの方法があります。

- GUIから設定できる`Auto load balance`を使う
- カスタムVCLを使って自分で`director`を定義する

[参考]
[Fastly Load balancing](https://www.fastly.com/products/load-balancing/)
[Load-balancing configuration](https://docs.fastly.com/guides/performance-tuning/load-balancing-configuration)

## GUIからAuto Load Balanceを使う
下記の画像はGUI(Origins->Hosts->CREATE HOST)からAuto load balanceを有効にする際の設定画面です。

- GUIからAuto load balanceを設定する場合、オプション項目としてWeight(重み付け)のみ設定できます。

![スクリーンショット 2017-08-22 22.37.11.png](https://qiita-image-store.s3.amazonaws.com/0/19942/e4df091e-2013-cd35-a6c3-aaea755fd168.png)

### 生成される関連VCLコード

```VCL
director autodirector_ random {   
   {
    .backend = F_server2;
    .weight  = 100;
   }{
    .backend = F_server1;
    .weight  = 100;
   }
}

sub vcl_recv {
#--FASTLY RECV BEGIN
    # (中略)

    set req.backend = autodirector_;

    # (中略)
}
```

## カスタムVCLを使って自分で`director`を定義する
- ↑↑に書いたVCLコードを参考に、カスタムVCLに直接`director`の設定を書いてしまえばOKです。  
Tipsとしては、directorの振る舞いとして上記の`random`以外に`round-robin, hash, client`の計4種類が[利用できます](https://docs.fastly.com/api/config#director)。<font color="Red">GUIからは変更できません。</font>
- directorを書いたら、前項の例のように任意の場所で必要な条件を設定して`set req.backend = autodirector_;`のようにbackendを決定するコードを書いてください。
- カスタムVCLにdirectorを直接書く場合、GUIからAuto load balanceを有効にする必要はありませんが、利用するオリジンは事前にGUIから設定してください。`Show VCL`ボタンを押して表示されたVCLからbackend名を見つけて正しく設定してください。（前項の例で示すところの`F_server1`部分）

## Load Balancingしつつreq.http.hostを書き換えたい
- ごく稀なユースケースだとは思いますが、ロードバランスしつつそれぞれのオリジンにアクセスする時にHostヘッダを変更する必要がある場合、一見すると下記のようなコードで動作するように見えますが、期待する動作にはなりません。理由は本記事の先頭に書いた通りです。

```
director autodirector_ random {   
   {
    .backend = F_server2;
    .weight  = 100;
   }{
    .backend = F_server1;
    .weight  = 100;
   }
}

sub vcl_recv {
#--FASTLY RECV BEGIN
    # (中略)

    set req.backend = autodirector_;

    if (req.backend == F_server1) {
        set req.http.host = "server1.example.com";
    }else if (req.backend == F_server2) {
        set req.http.host = "server2.example.com";
    }

    # (中略)
}
```
つまり、残念ながらdirectorを使ったロードバランスではこれを実現することができません。

### 回避策としての`randombool()`
- FastlyではVCLの中で[randombool()](https://docs.fastly.com/guides/vcl/randomness-related-vcl-features#random-decisions)を使うことができます。  
これを代用することでdirectorを使ったロードバランス同様の振る舞いを表現してみます。

```
sub vcl_recv {
#--FASTLY RECV BEGIN
    # (中略)

    if (randombool(1, 4)) {
        set req.backend = F_server1;
        set req.http.host = "server1.example.com";
    }else{
        set req.backend = F_server2;
        set req.http.host = "server2.example.com";
    }

    # (中略)
}
```

上記の例では、1/4のリクエストがtrueとなるので、リクエストのうち25%は`F_server1`、残りは`F_server2`へ振り分けられることになります。
このようにrandomboolを使うことでdirectorでweightを設定した時と同様の振る舞いが実現できました。
またrandomboolの他にシード値を与えることができる[randombool_seeded()](https://docs.fastly.com/guides/vcl/randomness-related-vcl-features#random-decisions)も利用することができます。
`randombool_seeded()`を応用することでcookieレスなA/Bテストなども実現可能です。

- [[Blog] A/B testing at the edge](https://www.fastly.com/blog/ab-testing-edge/)
- [[SlideShare] A/B testing at the edge](https://www.slideshare.net/Fastly/ab-testing-at-the-edge)