😎

Memorystore キャッシュを使用して Cloud Run の API を高速化する。

2023/11/02に公開

はじめに

この記事は、
 Speed up your API on Cloud Run with Memorystore caching
という動画を視聴し『実際にやってみた』という記事になります。

この記事でできるようになる事

Cloud Memorystore を使って、API実行を高速化させる。

Cloud Memorystore について簡単に理解しておく

Cloud Memorystoreは、フルマネージドのインメモリデータストアで、
Googleが管理するスケーラブルで安全な高可用性インフラを提供する。

これを使用する事で、データはRAM上に保存され、
高速なアクセス頻度、レイテンシの低減、スケーラビリティを実現できる。

他にも複雑なタスクの自動化や、アプリの可用性への影響を
最小限に抑えながら、インスタンスを容易に拡張できる特徴がある。

また、データの耐障害性の確保や、テータの定期的な
自動バックアップによるデータの復元も容易である。

サポートしているプロダクトには、RedisMemcachedがあり、
これらの特徴から、Cloud Memorystoreは、Webアプリケーションや
モバイルアプリ、ゲーム、分析ツールなどの多様な用途に適している。

Google Cloud API を有効化

GCPプロジェクトのコンソールへ接続。

Serverless VPC Access API
Cloud Build API
Artifact Registry API
Cloud Run Admin API

これらのAPIを有効化。
その他、APIの有効化は、必要に応じて、適宜行ってください。

sample code を git clone する。

cloud-run-redis を、git clone してください。

git clone https://github.com/GoogleCloudPlatform/serverless-expeditions.git

git cloneの実行が完了したら、cdコマンドを使って、対象のディレクトリ階層へ移動。

cd serverless-expeditions/cloud-run-redis

APIの実行速度が遅い事を確認する。

まずは、Cloud Memorystoreを使用しないで、
どれだけ速度に違いが出るのかを体感する為に、
既に完成形となっているコードを一部修正します。

なお、SERVCICE_NAME は任意のCloud Run Serviceの名前、
regionは最寄りのリージョンを選択して、入力してください。

deploy.sh

GOOGLE_PROJECT_ID=[プロジェクトIDを入力してください。]
SERVICE_NAME=rest-api
#REDIS_HOST=
#REDIS_PORT=
#VPC_CONNECTOR=

gcloud beta run deploy $SERVICE_NAME \
  --source . \
  --platform managed \
  --region asia-northeast1 \
  --allow-unauthenticated \
  # --update-env-vars REDIS_HOST=$REDIS_HOST,REDIS_PORT=$REDIS_PORT
  # --vpc-connector $VPC_CONNECTOR
  --project=$GOOGLE_PROJECT_ID

memorystore-deploy-slow.png
deploy.sh を変更する際の注意事項
今回は、Google Cloud Shell上でvimコマンドを使って
直接修正を行なっていますが、下記のErrorがDeploy時に
コンソールへ出力される可能性があります。
memorystore-deploy-error.png
このErrorが起こるのは、Windows環境での
改行文字 (\r\n) がUnixやLinux環境での
改行文字 (\n) として認識されていないことが原因との事。

これを解決するためには、以下のコマンドを実行してください。

sed -i 's/\r$//' deploy.sh

index.js
こちらのJSファイルは、一部コードの修正が
必要な箇所近くを抜粋しています。

/*
const redisClient = require('redis').createClient(
  process.env.REDIS_PORT,
  process.env.REDIS_HOST
);
*/

// Read one artist, by id.
app.get('/artist/:id', async (req, res) => {
  try {
    const id = req.params.id;
    const artist = await getArtistFromDatabase(id);
    if (artist) {
      res.json(artist);
      return;
    }
    else {
      res.status(404).json({error: `Artist ${id} not found`});
    }
  }
  catch(ex) {
    res.status(500).json({error: ex.toString()});
  }
})

memorystore-index-slow.png
deploy.shindex.js それぞれコードの修正が終わったら、
Cloud Run Service を Deploy するために下記のコマンドを実行してください。

./deploy.sh

次に、Postmanを起動して、Deployされた
Cloud Run ServiceURLを確認して、
以下のコマンドを修正して、GET Request を実行。

[Cloud Run Service URL]/artist/1

cloudrun-memorystore.png
時間が、3s以上かかっていれば、速度が遅い状態となります。
これを何度か繰り返して行なって、
すべてのRequestが3sかかる事を確認してください。
postman-slow.png

APIの実行速度を速くする。

APIの実行速度が3s以上かかっている事を確認できたら、
次にAPIの実行速度を上げる為に必要な、
Cloud MemorystoreのDeployを行います。

なお、Cloud Memorystoreは、VPC内に
できる為、外部からのアクセスを受け付けません。
そこで、Cloud Runから仮想プライベートクラウド
接続できるように、『サーバレスVPCアクセス」を設定します。

以下はその必要となる大まかな構成になります。
image.png

Cloud Memorystoreを設定。

  1. GCPコンソールからMemorystoreを開いて、
    Redisタブを選択した状態で、『インスタンスを作成』を実行。
    memorystore-create.png
  2. インスタンス名をつけて、最寄りリージョン、
    ネットワークを選択、残りフィールドはデフォルトのまま『作成』を実行。
    ネットワークはdefaultを選択。
    memorystore-create-instanceid.png
    memorystore-create-region.png
    memorystore-create-nw.png

サーバレスVPCアクセスを設定

  1. GCPコンソールからVPCネットワークを開いて、
    サーバレスVPCアクセスタブを選択した状態で、『コネクタを作成』を実行。
    serverless-vpc-access-create.png
  2. 任意のコネクタ名をつけて、最寄りリージョン、ネットワークはdefaultを選択。
    serverless-vpc-access-info.png
  3. サブネットは『カスタムIP範囲』を選択して、
    推奨値『10.8.0.0』を入力して、『作成』を実行する。
    serverless-vpc-access-subnet.png

REDIS_HOST, REDIS_PORT には、Deployされた
Memorystoreのプライマリエンドポイントを入力してください。
memorystore-praimary.png

VPC_CONNECTOR は、Deployされた
サーバレスVPCアクセスの名前を入力してください。
image.png
コードは上記の内容を適用させたものになります。
GOOGLE_PROJECT_IDREDIS_HOSTは、
それぞれ環境ごとに異なる為、そのまま利用しないでください。

deploy.sh

GOOGLE_PROJECT_ID=[プロジェクトIDを入力してください。]
SERVICE_NAME=rest-api
REDIS_HOST=10.44.88.21
REDIS_PORT=6379
VPC_CONNECTOR=my-vpc-connecter

gcloud beta run deploy $SERVICE_NAME \
  --source . \
  --platform managed \
  --region asia-northeast1 \
  --allow-unauthenticated \
  --update-env-vars REDIS_HOST=$REDIS_HOST,REDIS_PORT=$REDIS_PORT \
  --vpc-connector $VPC_CONNECTOR \
  --project=$GOOGLE_PROJECT_ID

memorystore-deploy-fast.png
index.js
こちらのJSファイルは、一部コードの修正が
必要な箇所近くを抜粋しています。

const redisClient = require('redis').createClient(
  process.env.REDIS_PORT,
  process.env.REDIS_HOST
);

// Read one artist, by id.
app.get('/artist/:id', async (req, res) => {
  try {
    const id = req.params.id;
    const artist = await getArtistFromCache(id);
    if (artist) {
      res.json(artist);
      return;
    }
    else {
      res.status(404).json({error: `Artist ${id} not found`});
    }
  }
  catch(ex) {
    res.status(500).json({error: ex.toString()});
  }
})

memorystore-index-fast.png

deploy.shindex.jsの修正が完了したら、
続けて以下のコマンドを実行して、
Cloud Run Serviceの再Deployを行なってください。

./deploy.sh

再DeployされたCloud Run ServicePostmanを使って実行。
最初のRequestは、3s以上かかりますが、
2回目以降は速くなっていることを確認できればOK。
postman-fast-1.png
Memorystoreを利用して、キャッシュからRequestされた結果が返されている状態。
postman-fast-2.png

終わりに

今回の記事は、動画を視聴しまして、
実際に『手を動かしてみた』という内容でまとめました。

Cloud Memorystoreを利用することで、
一度、Requestされたデータをキャッシュに残すことが、
可能となり、処理の高速化を確認できました。

APIの実行にかかる時間が遅いと
感じていれば、Cloud Memorystore
検討するのも良いかもしれません。

Cloud Memorystoreがどのようなものか、
試してみたい人は、参考にしていただけると幸いです。

あとで『じっくり読みたい』、『繰り返し読みたい』と
思ってくれましたら、『ストック』へ登録、
この記事が読まれている方にとって、
参考になる記事となりましたら、『いいね』を
付けていただけますと、励みになりますので、
よろしくお願いします。

Discussion