[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 機能を使うことで、便利に負荷分散していくことが可能です。

前提作業

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

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

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 した内容が確認できます。

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

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

Session Persistence の設定

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

Backend Sets の Edit を選択します。

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 の有効期間などを指定することが可能

Session Persistence 動作確認

アクセス確認

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

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 で、以下の黄色い箇所をクリックします

Cookie を選択します

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

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

バックエンドサーバー側の標準出力を見ると、先ほどまで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 がまた変わっています。

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

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

参考URL