[Oracle Cloud] Load Balancer で Session Persistence をやってみた

# はじめに

Oracle Cloud Infrastructure(以下OCI) で提供している Load Balancer には、Session Persistence と呼ばれるバインド機能があります。
Session Persistence を使うことによって、Load Balancer にアクセスしてきたユーザーのリクエストを、前回アクセスしたバックエンドサーバーにバインドすることが可能です。
AWS の ELB でいうと、スティッキーセッションと似た機能となっています。

概要

- 初めてアクセスしてきた client に、特定の値を持つ cookie を設定
- 2回目以降のアクセスを行った時に、特定の値を持つ cookie を確認して、前回アクセスしたバックエンドサーバーへリクエストをバインドする



アプリケーションの構成によっては、前回アクセスしたサーバと同一なものへアクセスし続けることが必要になります。
例を挙げると、セッション管理をローカルで行う、ファイルをローカルに生成している、といったことが考えられます。

モダンなアプリケーションの構成では、こういったローカル管理はやめてステートレスにしていくことが望ましいですが、様々な理由からアプリケーションの変更が出来ない事も多いです。
このような時に、Session Persistence 機能を使うことで、便利に負荷分散していくことが可能です。


![1574436977651.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/d6d86403-73a9-04d5-afa4-4458ba13dce2.png)




# 前提作業

## OCI環境

以下の環境をすでに OCI で作成済みです。

- Compute Instance 2台
  - CentOS7
- Load Balancer



## バックエンドサーバーで Cookie のログ出力

Session Persistence の機能自体を使用するには、特別な設定は バックエンドサーバーには不要です。
今回は、バックエンドサーバー側でどのような Cookie を受信したか確認したいので、Golang で Webサーバーを構成して、Cookie の内容を標準出力へ出力するプログラムを書きます。



Golang install は以下の記事を参考に適当に導入します
https://qiita.com/sugimount/items/1e677f1beab747959b81



Cookie の内容を標準出力へ出力するプログラムは、Github で公開しています
https://github.com/Sugi275/sample-go-cookie



ソースコードは以下の通りです。

```go
package main

import (
	"fmt"
	"log"
	"net/http"
)

// cookieの設定+標準出力へプリント
func setCookies(w http.ResponseWriter, r *http.Request) {
	cookie := &http.Cookie{
		Name:  "hoge",
		Value: "bar",
	}
	http.SetCookie(w, cookie)

	fmt.Fprintf(w, "Hello Cookie!")

	cookies := r.Cookies()

	fmt.Println("start")
	fmt.Println(cookies)
	fmt.Println("end")
}

// メイン
func main() {
	http.HandleFunc("/", setCookies)

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
```



Golang をインストール済みの Linux 環境で、以下のように簡単に実行することができます。
OCI 上に作成した、Compute Instance 2台で以下のコマンドを実行します。

```
cd ~
git clone https://github.com/Sugi275/sample-go-cookie.git
cd ~/sample-go-cookie
./sample-go-cookie
```



上記を実行すると、8080番ポートで Webサーバーが立ち上がります。ブラウザを使用して、Compute Instance の Public IP にアクセスを行うと、以下のWebページが表示されます。
Chrome のデベロッパーツールで Cookies を表示すると、Golang 上で SetCookie した内容が確認できます。

![1574437644282.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/c962a87a-b036-d594-60c5-9707a65c72ec.png)




Goのプログラム上で、Cookie の内容を標準出力へ出力した結果は、以下の内容が表示されています。

```
[opc@web01 sample-go-cookie]$ ./sample-go-cookie 
start 
[hoge=bar]
end
```



# Session Persistence の設定

前提作業で構成した、OCI Load Balancer の詳細画面へ移動します。

![1574438102958.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/63ad63fd-3548-3d83-b804-8e6be2b6ccdf.png)




Backend Sets の Edit を選択します。

![1574438169793.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/5e28b98b-a5a3-6713-f0b0-dc237f091701.png)




`ENABLE LOAD BALANCER COOKIE PERSISTENCE` を選択して、Save Changes を押します。

選択肢の説明をします。

- DISABLE SESSION PERSISTENCE : Session Persistence を無効にする
- ENABLE APPLICATION COOKIE PERSISTENCE : バックエンドサーバー側で、Cookie を作成するオプション。細かな制御を行いたい場合はこちらを選択する
- ENABLE LOAD BALANCER COOKIE PERSISTENCE : Load Balancer 側で、Cookie を作成するオプション。基本的にはこちらを使用すると思う。Cookie NAME や、Cookie の有効期間などを指定することが可能

![1574438303304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/83dac719-516f-5185-ac6c-b369d0a69c09.png)



# Session Persistence 動作確認

## アクセス確認

Load Balancer を経由して、バックエンドサーバーにアクセスして、Chrome の Developper Tools を確認します。
Session Persistence 時に、`COOKIE NAME` を空白にしたので、Default の `X-Oracle-BMC-LBS-Route` というName の Cookie が生成されています。Value は Load Balancer 側で生成されたランダムの値が入っています。
このランダムの値を使用して、どこのサーバーにバインドするべきかを管理されている動きになります。

![1574438754889.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/ceed5183-8158-2352-a4e8-62bb27ba1bdb.png)



Golang 側の標準出力を見ると、以下のような出力となっています。こちらの結果でも、`X-Oracle-BMC-LBS-Route` の Cookie を確認することが出来ます。
Web01 バックエンドサーバー側でも正しく、Load Balancer で自動付与された Cookie を確認することが出来ます。

```
[opc@web01 sample-go-cookie]$ ./sample-go-cookie  
start 
[X-Oracle-BMC-LBS-Route=cfc5eecb841cac84444ddf07c6db58e9b8ac77fc hoge=bar]
end
```



Cookie が Expire しない限り、何度アクセスしても前回アクセスしたバックエンドサーバーへバインドされます。



## Cookie 削除して確認

Cookie を削除して、アクセス先のサーバーや、Cookie の値が変更することを確認します。



Chrome で、以下の黄色い箇所をクリックします

![1574439866321.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/74d5827c-c623-8ffc-8d61-2cf514294abb.png)


Cookie を選択します

![1574439889016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/d19ba4f7-2f4a-88a6-e732-2583c4a80603.png)


削除して、完了を押します。

![1574439970582.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/0856f838-35e1-8781-1352-875c3f1c7b2c.png)



再度 Chrome からアクセスします。Value の値が先ほどと変わっています。

![1574440114664.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/abf74bcd-2a9b-8294-2e62-7f3d632e0a9e.png)



バックエンドサーバー側の標準出力を見ると、先ほどまでWeb01 でしたが、Web02 側に切り替わりました。

```
[opc@web02 sample-go-cookie]$ ./sample-go-cookie
start 
[X-Oracle-BMC-LBS-Route=bd28576df4f98e0ed1f460613b3a1a6a1f93a09b hoge=bar]
end
```



## フェールオーバー動作確認

今は Web02 側でバインドされています。では、このときに、Web02側に障害がおこるとどうなるのでしょうか。
答えは、正常に動作しているWeb01 側にフェールオーバーします。この時に、Cookie も再度作成されます。

では、Web02 で動作している Golang を停止して、再度アクセスを行います。
以下の表示結果のように、Value がまた変わっています。

![1574440298221.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/a5d32eb0-dc5b-d052-aa50-55fd35f7872a.png)



バックエンドサーバー側を確認すると、Web01 側で以下のログが表示されています。

```
[opc@web01 sample-go-cookie]$ ./sample-go-cookie
start 
[X-Oracle-BMC-LBS-Route=bd28576df4f98e0ed1f460613b3a1a6a1f93a09b hoge=bar]
end
```





# 参考URL

https://docs.cloud.oracle.com/iaas/Content/Balance/Reference/sessionpersistence.htm