Cloud SQL Insights の概要

Cloud SQL Insights は、Cloud SQL データベースにおけるクエリのパフォーマンスの問題を検出、診断、防止するのに役立ちます。セルフサービス方式で直観的にわかりやすく、単なる検出機能を超えた、パフォーマンスの問題の根本原因の特定に役立つ診断情報が提供されます。

この Codelab では、Cloud SQL for PostgreSQL インスタンスを設定し、Cloud SQL インスタンスをバックエンド ストレージとして使用するように Node.js アプリをデプロイする方法と、Cloud SQL Insights を使用してクエリを表示、モニタリングする方法を学習します。

要件

  • Node.js プログラミング言語とツールの基本知識

演習内容

  • Node.js アプリで Cloud SQL を使用します。
  • Node.js アプリで SQL Commenter を有効にします。
  • Cloud SQL Insights を使用して、クエリのパフォーマンスをモニタリングして調査します。

必要なもの

  • API を有効にしてサービスを作成する権限を持つ Google Cloud アカウント

セルフペース型の環境設定

  1. Cloud Console にログインし、新しいプロジェクトを作成するか、既存のプロジェクトを再利用します。(Gmail アカウントや Google Workspace アカウントをまだお持ちでない場合は、アカウントを作成する必要があります)。

使用しているプロジェクトのプロジェクト ID を覚えておいてください。以降、この Codelab では PROJECT-ID と呼びます。

  1. 次に、Google Cloud リソースを使用するには、Cloud Console で課金を有効にする必要があります。

この Codelab で実行すると、コストがまったく発生しません。「クリーンアップと詳細」セクションの手順に沿ってください。このセクションでは、このチュートリアル以外で料金が発生しないようにリソースのシャットダウンする方法について説明しています。Google Cloud の新規ユーザーは $300 の無料トライアル プログラムの対象です。

Cloud Shell をアクティブにする

  1. Cloud Console で、[Cloud Shell をアクティブにする] をクリックします。

Cloud Shell をアクティブにする

まだ Cloud Shell を起動したことがない場合は、その内容を説明する中間画面(スクロールしなければ見えない位置)が表示されます。その場合は、[続行] をクリックします(以後表示されなくなります)。ワンタイム スクリーンは次のようになります。

Cloud Shell ダイアログ ウィンドウ

Cloud Shell のプロビジョニングと接続に少し時間がかかる程度です。

Cloud Shell ターミナル

この仮想マシンには、必要な開発ツールがすべて準備されています。5 GB の永続ホーム ディレクトリが用意されており、Google Cloud で稼働するため、ネットワークのパフォーマンスと認証が大幅に強化されています。

  1. Cloud Shell で次のコマンドを実行して、正しいプロジェクトを使用していることを確認します。

Cloud Shell に接続すると、すでに認証は完了しており、プロジェクトに各自の プロジェクト ID が設定されていることがわかります。

次のコマンドを実行して、正しいプロジェクトを使用していることを確認します。

gcloud config list project

Cloud Shell を開いたときに選択したプロジェクトとは異なるプロジェクトを使用する場合は、次のコマンドを実行して新しいプロジェクトを設定します。

gcloud config set project <PROJECT-ID>;
  1. Cloud Shell の起動後、コマンドラインを使用して、my-instance という名前の新しい Cloud SQL インスタンスを作成し、Cloud SQL Insights を有効にできます。
gcloud sql instances create my-instance --tier db-f1-micro --database-version=POSTGRES_12 --region=us-central --root-password=<PASSWORD> --insights-config-query-insights-enabled --insights-config-record-application-tags --insights-config-record-client-address

フラグとその意味について簡単に説明します。

  • --tier db-f1-micro フラグは、開発用のリソースであり、Codelab 用に多くのリソースを必要としないため、最小限のリソースでマシンタイプを指定します。階層の詳細については、こちらをご覧ください。
  • --database-version=POSTGRES_12 フラグを指定すると、PostgreSQL バージョン 12 になるインスタンスを作成します。
  • --region=us-central フラグは、インスタンスを作成するリージョンを指定します。
  • --root-password=<PASSWORD> フラグを使用すると、ルート postgres ユーザーのパスワードを指定できます。<PASSWORD> は、任意のパスワードに置き換えてください。
  • --insights-config-query-insights-enabled フラグを指定すると、インスタンスで Cloud SQL Insights が有効になります。
  • --insights-config-record-application-tags フラグを指定すると、アプリケーション タグを記録できます。アプリケーション タグの詳細については、後のセクションで説明します。
  • --insights-config-record-client-address フラグを使用すると、Cloud SQL Insights でクライアント IP アドレスを記録できます。

プロジェクトで API sqladmin.googleapis.com を有効にするように求められる場合があります。プロンプトが表示されたら、[y] を選択して API を有効にします。

インスタンスの作成には数分かかります。このオペレーションが完了すると、インスタンスを使用できるようになります。

  1. 次に、サンプルアプリに使用するデータベースを作成します。
gcloud sql databases create votesdb --instance my-instance

Cloud Console からインスタンスにアクセスし、構成することもできます。

  1. 次のコマンドを実行して、インスタンス接続名を PROJECT-ID:ZONE-ID:INSTANCE-ID という形式で取得します。これは後で Node.js アプリを構成するときに使用します。
gcloud sql instances describe my-instance | grep connectionName

サービス アカウントは、GCP プロジェクト内で異なるサービスを使用する権限を付与するために使用されます。この Codelab では、Cloud SQL インスタンスに接続する権限を与えるために Cloud SQL プロキシに権限を付与する必要があります。

Console でサービス アカウントを作成する

  1. [IAM サービス アカウント] ページに移動し、ページの上部にある [-PCvKR3aQ2zKaUcml8w9lW4JNlmYtN5-r2--mC6kMUp6HOXW8wT1wUvLoYEPU-aA-oGskT3XkAqfNwRAKkZkllwTe6ugdrUVFwaeKT0M9Y1RwHA8JPZeGmCWYBfr8d9TSycNMIRsLw] ボタンをクリックします。
  2. サービス アカウントに一意の名前と ID を指定して、[作成] をクリックします。
  3. 次のページのプルダウンで [ロール] をクリックします。「Cloud SQL」でフィルタし、Cloud SQL クライアントのロールを選択します。[続行] をクリックし、[完了] をクリックします。
  4. サービス アカウントが作成されたら、新しいサービス アカウントの [アクション] にある 3 つのドットをクリックし、[キーを作成] を選択します。JSON が選択されます。デフォルトのまま [作成] をクリックします。これにより、JASON 秘密鍵ファイルがダウンロードされます。[閉じる] をクリックします。
  5. Cloud Shell で [その他] メニューの 3 つのドットをクリックし、[ファイルをアップロード] を選択します。ローカルマシンにダウンロードした JASON ファイルを参照して選択します。これにより、Cloud Shell の JASON ファイルがホーム ディレクトリにアップロードされます。

アプリケーションとデータベース インスタンス間の通信には、Cloud SQL プロキシを使用します。

  1. Cloud SQL プロキシをダウンロードします。Cloud Shell で次のコマンドを実行します。
wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy && chmod +x cloud_sql_proxy
  1. プロキシを実行するには、Cloud SQL インスタンスの詳細からコピーしたインスタンス接続名を使用して、<INSTANCE_CONNECTION_NAME> を置き換えます。認証情報ファイルには、前の手順でアップロードしたファイルへのパスを入力します。
./cloud_sql_proxy -credential_file=/path/to/credential_file.json -instances=<INSTANCE_CONNECTION_NAME>=tcp:5432 &

正常に終了すると、出力が数行にわたって、Ready for new connections メッセージが表示されます。

  1. サンプル アプリケーションのリポジトリのクローンを作成し、アプリの実行に必要なパッケージをインストールします。
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples/

cd nodejs-docs-samples/cloud-sql/postgres/knex

npm install
  1. 次の環境変数を設定します。
export CLOUD_SQL_CONNECTION_NAME='<PROJECT-ID>:<ZONE-ID>:<INSTANCE-ID>'
export DB_HOST='127.0.0.1:5432'
export DB_USER='postgres>'
export DB_PASS='<PASSWORD>'
export DB_NAME='votesdb'
  1. createTable.js を実行してアプリに必要なデータベース テーブルを作成し、データベースが正しく構成されていることを確認してから、サンプルアプリを起動します。
node createTable.js $DB_USER $DB_PASS $DB_NAME $CLOUD_SQL_CONNECTION_NAME votes $DB_HOST

npm start
  1. Cloud Shell で「ウェブでプレビューウェブ プレビュー アイコン をクリックし、[ポート 8080 でプレビュー] を選択します。

ポート 8080 のメニュー項目をプレビュー

ブラウザに次のようなタブとスペースの投票アプリが表示されます。

タブとスペースの投票アプリのスクリーンショット

  1. ボタンをクリックすると投票を行い、いくつかのデータをデータベースに保存できます。

このサンプル アプリケーションはごく単純なので、投すべての投票を表示するページを追加します。これを行う主な理由は、後で Cloud SQL Insights を使用する際に確認するデータが増えるためです。

  1. Cloud Shell に「Ctrl+c」と入力して、サンプルアプリを停止します。
  2. Cloud Shell で [エディタを開くボタン] ボタンをクリックし、Cloud Shell エディタを起動します。
  3. ファイル エクスプローラで、nodejs-docs-samples/cloud-sql/postgres/knex/server.js を見つけてクリックし、エディタで server.js ファイルを読み込みます。

getVotes 関数を定義した後に次のコードを追加します。

/**
 * Retrieve all vote records from the database.
 *
 * @param {object} pool The Knex connection object.
 * @returns {Promise}
 */
const getAllVotes = async pool => {
  return await pool
    .select('candidate', 'time_cast')
    .from('votes')
    .orderBy('time_cast', 'desc');
};
  1. 他のルートが定義されている以下の '/getAllVotes' ルートに、次のコードを追加します。
app.get('/getAllVotes', async (req, res) => {
  pool = pool || createPool();
  try {
    // Query all votes from the database.
    const votes = await getAllVotes(pool);

    res.render('allvotes.pug', {
      votes: votes,
    });
  } catch (err) {
    console.error(err);
    res
      .status(500)
      .send('Unable to load page; see logs for more details.')
      .end();
  }
});
  1. nodejs-docs-samples/cloud-sql/postgres/knex/views ディレクトリに allvotes.pug という新しいファイルを作成します。次のコードを貼り付けます。
doctype html
html(lang="en")
  head
    title Tabs VS Spaces

    link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css")
    link(rel="stylesheet", href="https://fonts.googleapis.com/icon?family=Material+Icons")
    script(src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js")
  body

    nav(class="red lighten-1")
      div(class="nav-wrapper")
        a(href="#" class="brand-logo center") Tabs VS Spaces

    div(class="section")

      h4(class="header center") Recent Votes
      ul(class="container collection center")
        each vote in votes
          li(class="collection-item avatar")
            if vote.candidate.trim() === 'TABS'
              i(class="material-icons circle green") keyboard_tab
            else
              i(class="material-icons circle blue") space_bar
            span(class="title") A vote for <b>#{vote.candidate}</b>
            p was cast at #{vote.time_cast}.
  1. [ターミナルを開くボタン] ボタンをクリックして Cloud Shell に戻り、次のコマンドを実行します。
npm start
  1. ウェブ プレビューからアプリを開いて、アプリが動作していることを確認します。ブラウザの URL に /getAllVotes を追加して、追加した新しいページを表示します。

SQL Commenter をインストールして有効にします。これは、ORM が実行前にコメントで SQL ステートメントを拡張できるようにするオープンソースライブラリです。SQLcommenter は、サンプルアプリの Knex.js など、複数の ORM とフレームワークをサポートします。Cloud SQL Insights は、これらのコメントの情報を使用して、データベースのパフォーマンスに関するアプリケーション中心のビューを提供し、問題の原因となっているアプリケーションコードを特定します。パフォーマンスのオーバーヘッドは小さいと予想しています。パフォーマンスの詳細については、こちらのドキュメントをご覧ください。

  1. Cloud Shell に「Ctrl+c」と入力して、サンプルアプリを停止します。
  2. 次のコマンドを実行して、SQL Commenter に必要なパッケージをインストールします。
  npm install @google-cloud/sqlcommenter-knex @opencensus/nodejs @opencensus/propagation-tracecontext @opentelemetry/api @opentelemetry/core --save
  1. Cloud Shell で [エディタを開くボタン] ボタンをクリックし、Cloud Shell エディタを起動します。
  2. ファイル エクスプローラで、nodejs-docs-samples/cloud-sql/postgres/knex/server.js を見つけてクリックし、エディタで server.js ファイルを読み込みます。
  3. ファイルで次のコードを見つけます。
const process = require('process');

その下に次のコードを追加します。

const {wrapMainKnexAsMiddleware} = require('@google-cloud/sqlcommenter-knex');
  1. ファイルで次のコードを見つけます。
// Set Content-Type for all responses for these routes.
app.use((req, res, next) => {
  res.set('Content-Type', 'text/html');
  next();
});

その下に次のコードを追加します。

app.use(wrapMainKnexAsMiddleware(Knex, {
    traceparent: true,
    tracestate: true,
    route: true,
    db_driver: true
}));

上記の手順を行うと、コードは次のようになります。

...
// Require process, so we can mock environment variables.
const process = require('process');

const {wrapMainKnexAsMiddleware} = require('@google-cloud/sqlcommenter-knex');
const express = require('express');
const bodyParser = require('body-parser');
const Knex = require('knex');

const app = express();
app.set('view engine', 'pug');
app.enable('trust proxy');

// Automatically parse request body as form data.
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

// Set Content-Type for all responses for these routes.
app.use((req, res, next) => {
  res.set('Content-Type', 'text/html');
  next();
});

app.use(wrapMainKnexAsMiddleware(Knex, {
    traceparent: true,
    tracestate: true,
    route: true,
    db_driver: true
}));
...
  1. [ターミナルを開くボタン] ボタンをクリックして Cloud Shell に戻り、次のコマンドを実行します。
npm start
  1. タブとスペースのアプリケーションで、クリックしてさらに投票し、データベースにデータを追加します。

Query Insights ダッシュボードは、Cloud SQL クエリのトラブルシューティングを行い、パフォーマンスの問題がないか調べます。

データベースの負荷 - すべてのクエリグラフ

トップレベルの Query Insights ダッシュボードには、[データベース負荷 - すべてのクエリ] グラフが表示されます。

すべてのクエリグラフ

グラフには、CPU 容量、CPU と CPU 待機、IO 待機、ロック待機に関する情報が含まれています。これらの指標の意味、指標が格納される場所、問題のあるクエリが表示されるグラフの例を、こちらのドキュメントで詳しく確認できます。このサンプル アプリケーションの場合、データベースのクエリ負荷が低いため、グラフが急激に変化することはありません。

最も負荷の高いクエリの確認

下のグラフに、選択した期間に正規化されたクエリを含むクエリのテーブルが表示されます。テーブル内のクエリは、合計実行時間でソートされています。

上位クエリのテーブル

個々のクエリをクリックすると、そのクエリのデータベース負荷、クエリのレイテンシ、クエリプランのサンプル、上位ユーザーなど、クエリに関する詳細情報が表示されます。サンプル アプリケーションの場合と同様に、アプリケーションが ORM を使用して構築されている場合、アプリケーションのどの部分がどのクエリを行うのか分からない場合があります。[上位のタグ] セクションは役立ちます。

アプリケーションでクエリの負荷が発生している場所の特定

クエリのテーブルからタグのテーブルに切り替えると、ビジネス ロジックでタグ付けされたクエリのリストが表示され、アプリケーション中心のビューを得ることができます。

上位タグのテーブル

タグのテーブルには、負荷の発生源となったデータベースの負荷が表示されます。上のスクリーンショットでは、'/getAllVotes' ルートの平均実行時間が長く、返される平均行数が多いことがわかります。テーブルに表示される実行時間は問題ではありませんが、この場合は、'/getAllVotes' の行をクリックしてデータを詳しく調べてみましょう。

クエリの実行が遅い理由

[クエリプランのサンプル] グラフでドットをクリックすると、クエリプランが表示されます。

クエリプランのサンプル

クエリプランには、PostgreSQL が内部でどのようにクエリを実行しているかが示されるため、動作が遅くなる原因があるかどうか簡単にわかります。

速度低下の原因となったアプリケーション コード

Cloud SQL Insights では、エンドツーエンドのトレースをコンテキスト内で可視化することもできます。この分析は、アプリケーションのどの部分でクエリの生成が遅くなっているかを把握するのに役立ちます。

[エンドツーエンド] タブをクリックして、コンテキスト内トレースを表示します。

エンドツーエンド トレース

ここでは、Cloud SQL Insights を使用して、Node.js アプリと Cloud SQL PostgreSQL データベースでクエリのパフォーマンスをモニタリングし、調査する方法を学びました。

クリーンアップ

Cloud SQL インスタンスの実行をやめる場合は、ここで削除できます。

gcloud sql instances delete my-instance

詳細