セッション

セッションの概要

このページでは、クライアント ライブラリの作成時、REST API または RPC API の使用時、Google クライアント ライブラリの使用時のベスト プラクティスなど、Spanner でのセッションの高度なコンセプトについて説明します。

セッションは、Spanner データベース サービスとの通信チャネルを表します。セッションは、Spanner データベースにデータの読み取り、書き込みまたは変更を行うトランザクションで使用されます。各セッションは 1 つのデータベースに適用されます。

セッションで同時に実行されるトランザクションは 1 つだけです。独立した読み取り、書き込み、クエリは内部でトランザクションを使用するため、トランザクションの制限では 1 トランザクションとしてカウントされます。

セッション キャッシュのパフォーマンス上のメリット

セッションの作成には高額なコストがかかります。データベース オペレーションごとのコストの発生を避けるため、クライアントは使用可能なセッションのプールであるセッション キャッシュを維持する必要があります。キャッシュは既存のセッションを保存し、リクエストされたときに適切なタイプのセッションを返すとともに、未使用セッションのクリーンアップも処理する必要があります。セッション キャッシュを実装する方法の例については、Go クライアント ライブラリJava クライアント ライブラリなど、いずれかの Spanner クライアント ライブラリのソースコードをご覧ください。

セッションは長時間の使用を目的としているため、セッションをデータベース オペレーションに使用した後は、クライアントがセッションを再利用のためキャッシュに戻す必要があります。

Google クライアント ライブラリを使用する際のベストプラクティス

以降は、Spanner に Google クライアント ライブラリを使用する場合のベスト プラクティスについて説明します。

セッション数の構成

通常、クライアント ライブラリで使用されるデフォルトのセッション数を変更することはおすすめしません。

特殊なワークロードがある場合は、予想される同時実行トランザクションの数を下限に設定し、上限を初期テスト数(たとえば、100)に設定することをおすすめします。上限が十分でない場合は、数を増やします。アクティブなセッション数を増やすと、Spanner データベース サービスで追加のリソースが使用されます。未使用セッションをクリーンアップしないと、パフォーマンスが低下します。また、gRPC チャネルごとのセッション数を 100 未満にすることをおすすめします。

書き込みセッションの割合を管理する

Spanner は、ほとんどのクライアント ライブラリで読み取り / 書き込みトランザクションにセッションの一部を予約しています。この予約部分を書き込みセッションの割合といいます。アプリがすべての読み取りセッションを使い切ると、Spanner は読み取り専用トランザクションであっても読み取り / 書き込みセッションを使用します。読み取り / 書き込みセッションでは spanner.databases.beginOrRollbackReadWriteTransaction が必要です。ユーザーに spanner.databaseReader IAM ロールが割り当てられている場合、呼び出しは失敗し、Spanner は次のエラー メッセージを返します。

generic::permission_denied: Resource %resource% is missing IAM permission:
spanner.databases.beginOrRollbackReadWriteTransaction

クライアント ライブラリで書き込みセッションの割合を維持するには、書き込みセッションの割合を設定します。

C++

C++ セッションはすべて同じです。読み取りセッションまたは読み取り / 書き込み専用セッションはありません。

C#

C# のデフォルトの書き込みセッションの割合は 0.2 です。この割合は、SessionPoolOptions の WriteSessionsFraction フィールドを使用して変更できます。

Go

Go のデフォルトの書き込みセッションの割合は 0.2 です。この割合は、SessionPoolConfig の WriteSessions フィールドを使用して変更できます。

Java

Java セッションはすべて同じです。読み取りセッションまたは読み取り / 書き込み専用セッションはありません。

Node.js

Node.js のデフォルトの書き込みセッションの割合は 0(ゼロ)です。この割合は、writes フィールドで変更できます。

PHP

PHP セッションはすべて同じです。読み取りセッションまたは読み取り / 書き込み専用セッションはありません。

Python

Python では、読み取りセッションと読み取り / 書き込みセッションの管理に使用できる 4 種類のセッション プールタイプをサポートしています。

Ruby

Ruby のデフォルトの書き込みセッションの割合は 0.3 です。この割合は、クライアントの初期化メソッドを使用して変更できます。

クライアント ライブラリを作成する場合、または REST/RPC を使用する場合のベスト プラクティス

以降は、Spanner のクライアント ライブラリでセッションを実装する場合と、REST API または RPC API でセッションを使用する場合のベスト プラクティスについて説明します。

これらのベスト プラクティスは、クライアント ライブラリを開発している場合、または REST/RPC API を使用している場合にのみ適用されます。Cloud Spanner 用の Google クライアント ライブラリのいずれかを使用する場合は、Google クライアント ライブラリを使用する際のベスト プラクティスをご覧ください。

セッション キャッシュの作成とサイズ設定

クライアント プロセスに最適なセッション キャッシュ サイズを特定するため、下限は予想される同時実行トランザクションの数に設定し、上限は 100 などの初期テスト数に設定します。上限が十分でない場合は、数を増やします。アクティブなセッション数を増やすと、Spanner データベース サービスで追加のリソースが使用されます。未使用セッションをクリーンアップしないと、パフォーマンスが低下します。RPC API を使用しているユーザーの場合は、gRPC チャネルごとのセッション数を 100 未満にすることをおすすめします。

削除されたセッションの処理

セッションを削除するには、次の 3 つの方法があります

  • クライアントがセッションを削除する。
  • Spanner データベース サービスが、アイドル状態が 1 時間を超えたセッションを削除する。
  • セッションが 28 日を越えた場合、Spanner データベースサービスによってセッションが削除されることがある。

削除されたセッションを使用しようとすると、NOT_FOUND になります。このエラーが発生した場合は、新しいセッションを作成して使用します。新しいセッションをキャッシュに追加して、削除済みのセッションをキャッシュから削除します。

アイドル セッションを維持する

Spanner データベース サービスは未使用のセッションを削除できます。アイドル セッションを維持する必要がある場合(データベースの使用が短期間で増加することが予想される場合など)、セッションが削除されないように設定できます。セッションを維持するには、SQL クエリ SELECT 1 など、低コストなオペレーションを実行します。近い将来使用する予定がないアイドル セッションは Spanner に削除させ、必要になったときに新しいセッションを作成します。

たとえば、データベースの負荷が定期的に高くなる場合にセッションを維持します。毎日午前 9 時から午後 6 時までデータベースの負荷が高くなる場合、この期間はアイドル セッションを残し、ピーク時の対応に備えます。午後 6 時以降は、Spanner にアイドル セッションを削除させます。毎日、午前 9 時前に、予想される需要に合わせて新しいセッションを作成します。

また、Spanner を使用するアプリケーションがあり、接続のオーバーヘッドを回避する必要がある場合にもセッションを維持します。セッションを維持しておくと、接続のオーバーヘッドを回避できます。

クライアント ライブラリのユーザーにセッションの詳細を隠す

クライアント ライブラリを作成する場合、クライアント ライブラリのユーザーにセッションの詳細を公開しないでください。クライアントがセッションの作成や維持などの複雑な処理を行うことなく、データベースを呼び出せるようにする必要があります。クライアント ライブラリのユーザーにセッションの詳細を隠すクライアント ライブラリについては、Java 用 Spanner クライアント ライブラリをご覧ください。

べき等でない書き込みトランザクションのエラーを処理する

リプレイ保護のない書き込みトランザクションが複数回ミューテーションに適用される場合があります。ミューテーションがべき等でない場合、ミューテーションが複数回適用されると、エラーが発生します。たとえば、書き込み前に行が存在していなくても、ALREADY_EXISTS エラーで挿入が失敗することがあります。バックエンド サーバーがミューテーションを commit していても、クライアントに接続できないと、この問題が発生します。この場合、ミューテーションが再試行され、ALREADY_EXISTS エラーが発生します。

独自のクライアント ライブラリの実装または REST API の使用時にこの問題を回避するには、次の方法が考えられます。

  • 書き込みをべき等にする。
  • リプレイ保護のある書き込みを使用する。
  • upsert ロジックを実行するメソッドを実装する。新規の場合に挿入を行い、既存の場合に更新を行う。
  • クライアントの代わりにエラーを処理する。

安定した接続を維持する

最高のパフォーマンスを得るには、セッションをホストするために使用する接続が安定している必要があります。セッションをホストする接続が変更されると、セッション メタデータの更新中に Spanner がセッションでアクティブなトランザクションを中止し、データベースに余分な負荷がかかる場合があります。いくつかの接続が散発的に変更されても問題ありませんが、多数の接続が同時に変更される状況は避ける必要があります。クライアントと Spanner 間でプロキシを使用する場合は、セッションごとに接続の安定性を維持する必要があります。

アクティブなセッションのモニタリング

ListSessions コマンドを使用すると、REST API または RPC API により、コマンドラインからデータベース内のアクティブなセッションをモニタリングできます。ListSessions は特定のデータベースのアクティブなセッションを表示します。これは、セッション リークの原因を特定する必要がある場合に便利です。(セッション リークは、セッションが作成はされるが再利用のためセッション キャッシュに戻されないというインシデントです)。

ListSessions を使用すると、セッションが作成されたときやセッションが最後に使用されたときなど、アクティブなセッションに関するメタデータを表示できます。このデータを分析することで、セッションのトラブルシューティングを行う際に、正しい方向へ向かうことができます。ほとんどのアクティブなセッションに最新の approximate_last_use_time がない場合は、アプリケーションでセッションが正しく再利用されていないことを示している可能性があります。approximate_last_use_time フィールドの詳細については、RPC API リファレンスをご覧ください。

ListSessions の使用方法の詳細については、REST API リファレンスRPC API リファレンスgcloud コマンドライン ツール リファレンスをご覧ください。