Fastly で Director を使ったロードバランシング



#はじめに
この記事では Fastly でロードバランシングを行う際に必要な設定や注意すべき内容をまとめてみたいと思います。

Director については以下の Fastly のオフィシャルドキュメントにも説明がありますが、この記事ではもう少し詳しく網羅的に説明をしたいと思います。

https://docs.fastly.com/vcl/directors/
https://docs.fastly.com/api/config#api-section-director

まずロードバランシングを設定する上で理解しておく必要がある要素について説明します。

## backend（バックエンド）
バックエンドとはオリジンサーバーとも呼ばれます。Fastly がコンテンツを取得しに行くサーバーのことで Fastly のコントロールパネル（UI）を通じて設定します。ロードバランシングを行うためには複数のバックエンドを設定する必要があります。

正しく作成されると、VCL の最初の方に以下のようにバックエンドごとに  `backend <backend name>` というようなコードが出力されます。

```
backend F_Host_1 {
  　省略
}
backend F_Host_2 {
  　省略
}
```

各バックエンドへのリクエストに付与する Host ヘッダの値を変更したい場合は、バックエンド設定時に **Advanced Options** の **Override host** から設定して下さい。




##Director
Director は複数のバックエンド（オリジン）を束ねたグループで、複数のバックエンドでロードバランシングしたい場合に利用となります。

Director は Type という属性があり、ロードバランシグのロジックを指定することが出来ます。現在 Fastly で利用可能な Type は以下のものがあります。

**random**
Director に含まれるバックエンドから指定した割合でランダムにバックエンドを選択します

**fallback**
指定された順番にbackendに選択し、unhealthy と判断された場合は次に指定されているバックエンドに接続します。

**hash**
`req.digest`(cache key から sha256で計算したhash) に基づいてバックエンドを選択します。同じ URL へのリクエストは変更しない限り同じキャッシュキーを持つため、通常は URL ごとに同じバックエンドが選択されます。

**client**
`client.identity` （デフォルトでは client.ipから計算されるが変更も可能）に基づいてバックエンドが選択されます。同じクライアントに対しては同じバックエンドが選択されるので、sticky オプションが必要な場合に利用します。


## バックエンドの設定
Director を利用するためには最初に、Director に入れるためのバックエンドを複数設定する必要があります。
バックエンドの設定は UI の **Origins** - **Create Host** から追加します。

backend 作成時に **Auto load balance** で yes を選択すると、選択された backend を含む 以下のような random Type のDirector が自動的に生成されます。

```
director autodirector_ random {
   {
    .backend = F_Host_1;
    .weight  = 100;
   }{
    .backend = F_Host_2;
    .weight  = 100;
   }
}

```

ここでは weight で指定した重み付けでランダムに接続するバックエンドが選択されます。

なお、UI を通じて生成可能な Director の Type は random のみとなります。random 以外の Type でのロジックを選択したい場合は Snippet や Custom VCL を利用して後述の VCL を記載する必要があります。

また、一部の Type は API でも作成可能ですが VCL で設定するほうが手軽なので特別な理由がないのであれば VCL の利用をおすすめします。


# VCL を利用した Director の作成
random 以外の Type を選択したい場合は Snippet や Custom VCL を利用し、vcl_init に Director を定義するコードを、vcl_recv に使用する Director を指定するコードを追加します。

Director の定義は vcl_init で以下のように指定します。

```vcl:vcl_init
director <Director Name> <Type> {
  { .backend = <backend name 1>; }
  { .backend = <backend name 2>; }
  { .backend = <backend name 3>; }
}
```

定義した Director を backend として選択するには vcl_recv で以下のように記述します。

```vcl:vcl_recv
set req.backend = <Director Name>;
```

#### backend の無効化
VCL を利用して Director を指定する場合、UI で生成されたバックエンド選択のロジックを無視して Director の指定を行うことになります。そのため、UI で生成されたバックエンドの指定を無効化するためにすべてのバックエンド設定に `!req.url` の Condition を追加して下さい。この Condition は常に False になるので、UI で生成されたバックエンドの指定を無効化することが出来ます。




それでは各 Type の Director の定義について確認してみます。

## random Type の Director
Director は vcl_init で定義しますので、Snippet を利用する場合は vcl_init を選択します。 random Director は以下のように定義します。

```vcl:vcl_init
director my_director random {
   .quorum = 75%;
   .retries = 5;
   {
    .backend = F_Host_1;
    .weight  = 100;
   }{
    .backend = F_Host_2;
    .weight  = 100;
   }
}
```

各 backend には `.weight` を指定します。ここに指定した割合に基づいて backend への割り振りの割合が決定されます。

random Director のオプションパラメーターには以下のようなものがあります。

 - quorum | Integer
Director が正常に動作していると判断されるために、Director 内で正常に動作しているノードの割合をパーセンテージで指定します。デフォルトは75で0から100の間の整数値で指定します。

 - retries | Integer
選択した backend が unhealthy だった場合に選択をリトライする数を指定します。指定がない場合は Director の中に含まれる backend の数となります。



## fallback Type の Director

指定された順番にbackendに選択し、unhealthy と判断された場合は次に指定されているバックエンドに接続します。fallback Director は vcl_init に以下のように定義します。

```vcl:vcl_init
director my_director fallback {
  { .backend = F_Host_0; }
  { .backend = F_Host_1; }
  { .backend = F_Host_2; }
}
```

この場合、通常は F_Host_0 が選択されますが、F_Host_0 が unhealthy と判断された場合は F_Host_1 が選択されます。F_Host_1 も unhealthy と判断された場合は F_Host_2 が選択されます。


## hash Type の Director

hash Director では `req.digest` (cache key から sha256で計算したhash) に基づいてバックエンドを選択します。各バックエンドに割り振る割合は `.weight` で指定します。

hash Director は vcl_init で以下のように定義します。

```vcl:vcl_init
director my_director hash {
  { .backend = F_Host_0; .weight = 10; }
  { .backend = F_Host_1; .weight = 10; }
  { .backend = F_Host_2; .weight = 10; }
}
```


Director に`.quorum`、`retries` オプションを指定することも可能です。
ただし、同じキャッシュキーを持つリクエストには同じバックエンドが選択されるため `retries` オプションは指定しても通常意味はありません。


## client Type の Director

client Director はセッションの Sticky Option が必要な場合に利用されます。接続されるバックエンドは `client.identity` に基づいて決定されます。各バックエンドに割り振る割合は `.weight` で指定します。

デフォルトでは `client.identity` は `client.ip` が適用されているため、同じIPからのアクセスは同じバックエンドに到達します。client Director は vcl_init に以下のように定義します。

```vcl:vcl_init
director my_director client {
  { .backend = F_Host_0; .weight = 10; }
  { .backend = F_Host_1; .weight = 10; }
  { .backend = F_Host_2; .weight = 10; }
}
```

Director に`.quorum`、`.retries` オプションを指定することも可能です。
ただし、同じ`client.identity`を持つリクエストには同じバックエンドが選択されるため `retries` オプションは指定しても通常意味はありません。


`client.identity` は上書きが可能です。`client.ip` 以外の条件で接続するバックエンドを固定したい場合は vcl_recv 内のバックエンドを選択するコードの前で上書きします。 例えばリクエスト Cookie に含まれる Session 情報を基に接続するバックエンドを制御したい場合、以下のようなコードとなります。

```vcl:vcl_recv
set client.identity = req.http.Cookie:Session;
set req.backend = my_director;
```

---

以上が Director でのロードバランシングの利用方法になります。Shielding を使っていたり、Failover を組み合わせたい場合はもう少し複雑なコードが必要になりますが、基本的な設定は以上で実現することが出来ます。