はじめに
OCI(Oracle Cloud Infrastructure) の API Gateway から提供されているレスポンス・キャッシュの機能について、ことはじめ的な記事を書きたいと思います。
OCI API Gateway のもつレスポンスキャッシュの仕組み
OCI API Gateway は、外部のキャッシュサーバー(Redis, KeyDB, etc...)と統合することでレスポンスをキャッシュする機能を持っています。これは、パフォーマンスの向上やバックエンドサービスに対して不要な負荷をかけないという意味で重要な役割があります。
全体の流れとしては、
- クライアントから API のリクエストが発行される
- リクエストの URL、HTTP メソッド(GET, HEAD, OPTIONS)、API デプロイメントの OCID からキャッシュ・キーを導出し、そのキャッシュ・キーを元に外部のキャッシュ・サーバーに問い合わせを行う
- キャッシュ・ヒットの有無で以下のように振舞う
- キャッシュ・ヒットした場合 → キャッシュ・サーバから結果を取得し、返却する
- キャッシュ・ヒットしなかった場合 → 対応するバックエンドサービスから結果が返却される
といった形で機能します。実際にキャッシュ・ヒットしたかどうか?の確認は、API Gateway で HTTP Response Header に X-Cache-Status
が追加されるので、このヘッダーをクライアント側で確認すると良いでしょう。実際に返却される X-Cache-Status
の値は以下のようになっています。
-
X-Cache-Status: HIT
: 一致するキャッシュ・キーがキャッシュ・サーバーで見つかり、レスポンスがキャッシュ・サーバーから取得されたことを表す -
X-Cache-Status: MISS
: 一致するキャッシュ・キーがキャッシュ・サーバーで見つからなかったため、レスポンスがバックエンドサーバーから取得されたことを表す -
X-Cache-Status: BYPASS
: キャッシュ・サーバーに対して問い合わせが行われなかったことを表す。(通常、キャッシュ・サーバーとの通信に何か問題がある場合が多いと思います)
API Gateway のキャッシュ機能を試してみる
前提
以下の前提で手順を書きたいと思います。
- Oracle Cloud Infrastructure のアカウントを有していること(NOT Always Free)
- Docker, Docker Compose がセットアップ済みの Compute Instance を有していること
- API Gateway から OCI Vault に対するポリシーの設定が完了していること
- Oracle Functions の開発環境の設定が完了していること(Fn CLI を用いて、Oracle Functions のアプリケーションに関数コードをデプロイすることができること)
手順
それでは、実際に構築して行きたいと思います。今回は、キャッシュ・サーバーに Redis、バックエンドサーバーは、Oracle Functions を使用します。そのため、全体の構成は以下のようになります。
1. OCI Vault に Redis へアクセスするための Secret を作成する
OCI Vault に Redis へアクセスするための Secret を作成します。OCI コンソールの左上のハンバーガーメニューから、アイデンティティとセキュリティ > ボールトと選択します。
ボールトの作成を押し、新規にボールトを作成します。
任意の名前を入力し、ボールトの作成をクリックします。
ボールトの作成が完了後、マスター暗号化キーを作成します。ボールトの詳細画面のマスター暗号化キーリソースでキーの作成をクリックします。
任意の名前を入力し、マスター暗号化キーを作成します。
次に、シークレットを作成します。ボールトの詳細画面のシークレットリソースでシークレットの作成をクリックします。
以下のように入力し、シークレットを新規に作成します。
- コンパートメントに作成: 任意のコンパートメント(API Gateway, Vault のリソースが含まれているコンパートメント)
- 名前: 任意の名前
- 説明(オプション): for oci api gateway cache feature
- 暗号化キー: 前述の手順で作成したマスター暗号化キーを指定
- シークレット・タイプ・テンプレート: プレーン・テキスト
- シークレット・コンテンツ: {"password": "<your-password>"}
これで、API Gateway -> Redis へアクセスするために必要なパスワードを格納する Vault の設定は完了です。
2. Compute Instance に Redis を構築する
Compute に直接 Redis をインストールしても良いのですが、より手軽に実施するために今回は Docker, Docker Compose を使用して Redis を構築します。まずは、Redis 用のポートを開放します。
Compute の Firewall の設定:
sudo firewall-cmd --add-port=6379/tcp --zone=public --permanent
sudo firewall-cmd --reload
OCI のセキュリティ・リストの設定:
Redis を構築するインスタンスが属している VCN のセキュリティ・リストのイングレス・ルールを以下のように更新します。
- ソースタイプ: CIDR
- ソース CIDR: 0.0.0.0/0
- IP プロトコル: TCP
- ソース・ポート範囲 オプション: 未入力
- 宛先ポート範囲 オプション: 6379
- 説明 オプション: for Redis default port.
次に、以下の docker-compose.yaml
を任意のディレクトリ($HOME/redis
等)に作成します。
version: '3.8'
volumes:
redis-data:
services:
redis:
image: redis:6.2.6
container_name: redis
ports:
- 6379:6379
command: redis-server --requirepass <your-password>
volumes:
- redis-data:/data
ここで、<your-password>は、1. OCI Vault に Redis へアクセスするための Secret を作成するで作成した Secret の値に更新してください。(本記事の例だと、shukawam-secret
)
更新後、Redis を起動します。
docker-compose up -d
起動の確認
docker ps | grep redis
2e0812dd38a8 redis:6.2.6 "docker-entrypoint.s…" 6 hours ago Up 6 hours 0.0.0.0:6379->6379/tcp redis
設定したパスワードを用いてアクセス可能か確認します。
docker exec -it redis redis-cli -h <your-compute-public-ip> -p 6379
設定したパスワードを用いて、認証する。
auth <your-password>
OK
適当なキーで参照の操作が可能かどうか確認する。
get foo
(nil)
これで、Redis の構築は完了です。
3. Oracle Functions を作成する
バックエンドを構成するための Function を作成します。
fn init --runtime java11 fn-java
ビルド & デプロイ
cd fn-java; fn deploy --app <your-app>
4. API Gateway の設定をする
API Gateway をキャッシュ・サーバーを使用するように構築します。OCI コンソールの左上のハンバーガーメニューから、開発者サービス > ゲートウェイと選択します。
ゲートウェイの作成をクリックし、以下のように入力して新規に API Gateway を作成します。(既に API Gateway を作成済みの場合は、キャッシュを使うように再設定が可能です)
- 名前: 任意の名前
- タイプ: パブリック
- コンパートメント: 任意のコンパートメント
- 仮想クラウド・ネットワーク: 任意の VCN
- サブネット: 任意のリージョナルサブネット
- レスポンス・キャッシングの有効化: チェックを入れる
- ホスト: 前述の手順で Redis を構築した Compute Instance のパブリック IP を入力
- ポート: 6379
- ボールト: 前述の手順で作成したボールト
- シークレット: 前述の手順で作成したシークレット
- バージョン番号: 1(更新した場合には最新のバージョンを選択する)
次に、Oracle Functions をバックエンドに持つデプロイメントとルーティングを作成します。ゲートウェイの詳細画面でデプロイメントの作成をクリックします。
基本情報で以下のように入力し、次をクリックします。
- 名前: cache-deployment
- パス接頭辞: /cache
ルーティングを新規に作成するために以下のように入力し、確認画面で作成を押し、デプロイメントを新規に作成します。
- パス: /hello
- メソッド: GET
- タイプ: Oracle Functions
- アプリケーション: 作成済みのアプリケーション
- 機能名: fn-java
- レスポンス・キャッシング・ポリシーを表示
- このルートのキャッシングの有効化にチェック
- キャッシュされたレスポンスの TTL(秒): 120
これで、構築したキャッシュ・サーバーを使うような API Gateway とデプロイメントの設定は完了です。
5. キャッシュが正しく使われているかどうか確認をする
作成した API Gateway のルーティングに対してリクエストを送ってみます。
1 回目 リクエスト:
curl --dump-header - https://...apigateway.ap-tokyo-1.oci.customer-oci.com/cache/hello
1 回目 レスポンス:
HTTP/1.1 200 OK
Date: Fri, 05 Nov 2021 08:45:49 GMT
Content-Type: text/plain
Connection: keep-alive
Content-Length: 13
Server: Oracle API Gateway
X-Cache-Status: MISS
opc-request-id: /2C552C5FE8188F8E35BE0D97FCDEF927/5D2EDF4F87E162E086CD0E04E9B4B287
Strict-Transport-Security: max-age=31536000
X-Content-Type-Options: nosniff
X-Frame-Options: sameorigin
X-XSS-Protection: 1; mode=block
Hello, world!
X-Cache-Status: MISS
でキャッシュ・ヒットしなかったことが確認できます。次に、同じリクエストを再度送ってみます。
2 回目 レスポンス:
HTTP/1.1 200 OK
Date: Fri, 05 Nov 2021 08:46:17 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Server: Oracle API Gateway
X-Content-Type-Options: nosniff
X-Frame-Options: sameorigin
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000
opc-request-id: /5CE6249E287877B2658F4CA18139A93B/BFBD0317FE423AB5D7DE61041B0BCF50
X-Cache-Status: HIT
Hello, world!
X-Cache-Status: HIT
で確かにキャッシュ・ヒットしたことが確認できます。