書き込み

概要

このページでは、Cloud Bigtable に送信できる書き込みリクエストのタイプの一覧を示します。また、それぞれの書き込みリクエストに関して、それを使用すべき場合と使用すべきでない場合について説明します。

Cloud Bigtable Data API とクライアント ライブラリを使用すると、プログラムによってテーブルにデータを書き込むことができます。Bigtable はそれぞれの書き込みに対してレスポンス(確認応答)を返します。

各クライアント ライブラリには、次のタイプの書き込みリクエストを送信する機能があります。

  • 単純な書き込み
  • インクリメントと追加
  • 条件付き書き込み
  • バッチ書き込み

Bigtable クライアント ライブラリには、単純な書き込みとバッチ書き込み用に、スマート再試行機能が組み込まれています。これにより、一時的に可用性が損なわれた状態をシームレスに処理します。たとえば、アプリケーションがデータの書き込みを試行して、一時的なサービス停止またはネットワークの問題が発生した場合は、書き込みが commit されるかリクエストの期限に達するまで自動的に再試行が行われます。この耐障害性は、単一クラスタ ルーティングまたは複数クラスタ ルーティングを通じて、単一クラスタと複数クラスタのいずれのインスタンスでも機能します。

バッチ書き込みオペレーションとストリーミング書き込みオペレーションの場合は、Bigtable 用の Dataflow コネクタを使用できます。 書き込みリクエストに適用される上限については、割り当てと上限をご覧ください。

各タイプの書き込みの例が、各 Bigtable クライアント ライブラリ向けに用意されています。

書き込みのタイプとそれらを使用する場合

すべての書き込みリクエストには、次の基本コンポーネントが含まれます。

  • 書き込み先のテーブルの名前。
  • アプリ プロファイル ID。トラフィックのルーティング方法を Bigtable に伝えます。
  • 1 つ以上のミューテーション。ミューテーションは次の 4 つの要素で構成されています。
    • 列ファミリー名
    • 列修飾子
    • タイムスタンプ
    • テーブルに書き込む値

ミューテーションのタイムスタンプのデフォルト値は現在の日付と時刻です。1 回の書き込みリクエストに含まれるミューテーションのタイムスタンプは、オーバーライドしない限りすべて同一です。書き込みリクエスト内のすべてのミューテーションのタイムスタンプを同一にすることもできれば、それぞれ異なるようにすることもできます。

単純な書き込み

MutateRow リクエストを使用すると、Bigtable に単一行を書き込むことができます。リクエストでは、テーブル名、使用するアプリ プロファイルの ID、行キーが指定されていて、その行のミューテーションを 100,000 個まで含めることができます。単一行の書き込みはアトミックです。単一行に対して複数のミューテーションを作成する場合は、この書き込みタイプを使用します。

単純な書き込みリクエストの送信方法を示すコードサンプルについては、単純な書き込みの実行をご覧ください。

単純な書き込みを使用すべきでない場合

以下のユースケースでは、単純な書き込みは最適なデータ書き込み方法ではありません。

  • 連続した行キーが含まれるデータのバッチを書き込む場合。この場合は、単純な書き込みを連続して行う代わりに、バッチ書き込みを使用することをおすすめします。連続行のバッチを 1 回のバックエンド呼び出しで適用できるためです。

  • 高スループット(1 秒あたりの行数または 1 秒あたりのバイト数)が必要であり、低レイテンシが必須ではない場合。この場合は、バッチ書き込みの方が高速です。

インクリメントと追加

既存の値にデータを追加するか、既存の数値をインクリメントする場合は、ReadModifyWriteRow リクエストを送信します。このリクエストには、テーブル名、使用するアプリ プロファイルの ID、行キー、データ書き込み時に使用する一連のルールを含めます。各ルールには、列ファミリー名と列修飾子、さらには追加値とインクリメント量のいずれか一方を含めます。

ルールは順番に適用されます。たとえば、リクエストの中に列の値を 2 つインクリメントするリクエストが含まれていて、同じリクエスト内の後にあるルールでその同じ列を 1 つインクリメントする場合、この単一アトミック書き込みで列は 3 つインクリメントされます。後のルールによって前のルールが上書きされてしまうことはありません。

値をインクリメントできるのは、その値が 64 ビット ビッグ エンディアン符号付き整数としてエンコードされている場合に限られます。Bigtable は、空の値または存在しない値に対するインクリメントは、値がゼロである場合と同様に扱います。ReadModifyWriteRow リクエストはアトミックです。なんらかの理由で失敗しても、再試行されません。

セルに値を追加する方法を示すサンプルコードについては、既存の値のインクリメントをご覧ください。

インクリメントと追加を使用すべきでない場合

次のような場合は、ReadModifyWriteRow リクエストを送信しないでください。

  • 複数クラスタ ルーティングが含まれるアプリ プロファイルを使用している場合。

  • 複数の単一クラスタ アプリ プロファイルを使用していて、インスタンス内の他のクラスタの同じ行と列に書き込まれるデータと競合する可能性のある書き込みを送信する場合。単一クラスタ ルーティングでは、書き込みリクエストは単一クラスタに送信されてから複製されます。

  • クライアント ライブラリで提供されているスマート再試行機能に依存している場合。インクリメントと追加の再試行はできません。

  • 大量のデータを書き込み、書き込みを迅速に完了する必要がある場合。行を読み取ってからその行を変更するリクエストは、単純な書き込みリクエストよりも低速です。その結果、このタイプの書き込みは大規模な書き込みのための最適なアプローチではないことがよくあります。たとえば、ページビューなど、数値が数百万規模のカウントを行う場合は、値をインクリメントするのではなく、単純な書き込みとして各ビューを記録することを検討してください。Dataflow ジョブを使用してデータを集計できます。

条件付き書き込み

条件に照らして行を確認してから、その結果に応じて行にデータを書き込む場合は、CheckAndMutateRow リクエストを送信します。このタイプのリクエストには行キーと行フィルタが含まれます。行フィルタは、既存のデータの値を確認するために使用する一連のルールです。フィルタによって課される特定の条件が満たされている場合のみ、行の特定の列にミューテーションが commit されます。確認に続いて書き込みが行われるこのプロセスは、単一のアトミックな処理として完了します。

フィルタ リクエストには、次の 2 種類のミューテーションの一方または両方を含める必要があります。

  • true ミューテーション(フィルタが値を返す場合に適用されるミューテーション)
  • false ミューテーション(フィルタが何も返さない場合に適用されるミューテーション)

1 回の書き込みで、それぞれのタイプのミューテーション(true と false)を最大 100,000 個指定できます。少なくとも 1 つのミューテーションを送信する必要があります。すべてのミューテーションが完了すると Bigtable はレスポンスを送信します。

条件付き書き込みを送信する方法を示すコードサンプルについては、値の条件付き書き込みをご覧ください。

条件付き書き込みを使用すべきでない場合

以下のユースケースでは、条件付き書き込みを使用できません。

  • 複数クラスタ ルーティングが含まれるアプリ プロファイルを使用している場合。

  • 複数の単一クラスタ アプリ プロファイルを使用していて、インスタンス内の他のクラスタの同じ行と列に書き込まれるデータと競合する可能性のある書き込みを送信する場合。単一クラスタ ルーティングでは、書き込みリクエストは単一クラスタに送信されてから複製されます。

バッチ書き込み

MutateRows リクエストを使用すると、1 回の呼び出しで複数の行を書き込むことができます。MutateRows リクエストには、最大 100,000 個のエントリのセットが含まれ、各エントリがアトミックに適用されます。各エントリは、1 つの行キーと、その行に適用される 1 つ以上のミューテーションから構成されます。バッチ書き込みリクエストには、すべてのエントリを合わせて最大 100,000 個のミューテーションを含めることができます。たとえば、バッチ書き込みには次のような組み合わせを含めることができます。

  • 各エントリに 1 個のミューテーションが含まれる 100,000 個のエントリ
  • 100,000 個のミューテーションが含まれる 1 個のエントリ
  • 各エントリに 100 個のミューテーションが含まれる 1,000 個のエントリ

MutateRows リクエストの各エントリはアトミックですが、リクエスト全体はアトミックではありません。必要に応じて、Bigtable は、すべての書き込みが成功するか、リクエストの期限に達するまで、バッチ内の成功しなかったエントリを再試行します。次に、バッチの各書き込みと、書き込みの成否を示すレスポンスを返します。

バッチ書き込みの送信方法を示すコードサンプルについては、バッチ書き込みの実行をご覧ください。

バッチ書き込みを使用すべきでない場合

  • 互いに近い位置にはない行にバルクデータを書き込む場合。Bigtable は、行キーの辞書的順番でデータを格納します。これは、バイナリのアルファベット順に相当します。このため、リクエスト内の行キーが互いに類似していない場合、Bigtable はそれらを並列処理せず、順次処理します。スループットは高くなりますが、レイテンシも長くなります。行キーが類似していて Bigtable が互いに近い位置にある行を書き込む場合にレイテンシが長くなるのを避けるには、MutateRows を使用します。行が互いに近い位置にない場合は、MutateRow、つまり単純な書き込みを使用します。

  • 同じ行に対する複数のミューテーションをリクエストする場合。この場合は、1 回の単純な書き込みリクエストですべてのミューテーションを実行するほうがパフォーマンスが高くなります。なぜなら、単純な書き込みではすべての変更が 1 回のアトミックな処理で commit されるのに対して、バッチ書き込みでは同じ行に対してミューテーションを順次処理しなければならず、レイテンシが発生するためです。

レプリケーションを使用する際の整合性

書き込んだデータが読み取りに使用できるようになるまでに要する時間は、インスタンス内のクラスタの数や、アプリ プロファイルで使用するルーティングのタイプなど、複数の要因によって左右されます。単一クラスタ インスタンスでは、データはすぐに読み取り可能になりますが、インスタンスに複数のクラスタがある場合、つまりレプリケーションを使用している場合、Bigtable は結果整合性になります。リクエストを同一クラスタにルーティングすると、read-your-writes の整合性を実現できます。

書き込みリクエストを送信した後は、整合性トークンを作成して使用できます。このトークンはレプリケーションの整合性を確認します。一般的には、書き込みのバッチが送信された後、または 1 時間などの特定の間隔の後に、整合性トークンを作成します。続いて、読み取りリクエストを行うモジュールなど、別のプロセスにトークンを渡してそのプロセスで使用することができます。そのプロセスでは、このトークンを使用して読み取り試行の前にすべてのデータが複製されていることを確認します。

トークンを作成した直後に使用する場合は、初回使用時の整合性の確認に数分かかることがあります。この遅延が発生するのは、各クラスタが他のすべてのクラスタをチェックして、追加のデータが送信されていないことを確認するためです。トークンの初回使用が完了している場合、またはトークンを初回使用する際に数分待機した場合、トークンの使用は即座に完了します。

競合の解決

Bigtable テーブルの各セルの値は 4 タプル(行キー、列ファミリー、列修飾子、タイムスタンプ)で一意に識別されます。これらの識別子の詳細については、Bigtable ストレージ モデルをご覧ください。まったく同じ 4 つのタプルの 2 つの書き込みが 2 つの異なるクラスタに送信された場合、Bigtable は、サーバー側の時間に基づいて最後の書き込みを優先する内部アルゴリズムを使用して、競合を自動的に解決します。Bigtable の「最後の書き込みの優先」の実装は確定的で、レプリケーションが完了すると、すべてのクラスタの 4 つのタプルが同じ値になります。

次のステップ