書き込み
このページでは、Bigtable に送信できる書き込みリクエストのタイプの一覧を示します。また、それぞれの書き込みリクエストに関して、それを使用すべき場合と使用すべきでない場合について説明します。書き込み時にセル内のデータを集計する方法については、書き込み時に値を集計する(プレビュー)をご覧ください。
Bigtable Data API とクライアント ライブラリを使用すると、プログラムによってテーブルにデータを書き込むことができます。Bigtable はそれぞれの書き込みに対してレスポンス(確認応答)を返します。
各クライアント ライブラリには、次のタイプの書き込みリクエストを送信する機能があります。
- 単純な書き込み
- インクリメントと追加
- 条件付き書き込み
- バッチ書き込み
Bigtable クライアント ライブラリには、単純な書き込みとバッチ書き込み用に、スマート再試行機能が組み込まれています。これにより、一時的に可用性が損なわれた状態をシームレスに処理します。たとえば、アプリケーションがデータの書き込みを試行して、一時的なサービス停止またはネットワークの問題が発生した場合は、書き込みが commit されるかリクエストの期限に達するまで自動的に再試行が行われます。この耐障害性は、単一クラスタ ルーティングまたはマルチクラスタ ルーティングを通じて、単一クラスタのインスタンスと複製されたインスタンスの両方で機能します。
バッチ書き込みオペレーションとストリーミング書き込みオペレーションの場合は、Bigtable Beam コネクタを使用できます。詳細については、バッチ書き込みをご覧ください。
書き込みリクエストに適用される上限については、割り当てと上限をご覧ください。
このページで説明する書き込みリクエストの Cloud Bigtable クライアント ライブラリの例については、書き込みの例をご覧ください。
書き込みのタイプとそれらを使用する場合
すべての書き込みリクエストには、次の基本コンポーネントが含まれます。
- 書き込み先のテーブルの名前。
- アプリ プロファイル ID。トラフィックのルーティング方法を Bigtable に伝えます。
- 1 つ以上のミューテーション。 ミューテーションは次の要素で構成されています。
- 列ファミリー名
- 列修飾子
- タイムスタンプ
- テーブルに書き込む値
ミューテーションのタイムスタンプのデフォルト値は現在の日時です。これは、Unix エポック(1970 年 1 月 1 日 00:00:00 UTC)からの経過時間として測定されます。
Bigtable に送信するタイムスタンプは、ミリ秒以下の精度を持つマイクロ秒の値にする必要があります。マイクロ秒精度のタイムスタンプ(3023483279876543
など)は拒否されます。この例では、指定できるタイムスタンプ値は 3023483279876000
です。
1 回の書き込みリクエストに含まれるミューテーションのタイムスタンプは、オーバーライドしない限りすべて同一です。書き込みリクエスト内のすべてのミューテーションのタイムスタンプを同一にすることもできれば、それぞれ異なるようにすることもできます。
単純な書き込み
MutateRow
リクエストを使用すると、Bigtable に単一行を書き込むことができます。リクエストでは、テーブル名、使用するアプリ プロファイルの ID、行キーが指定されていて、その行のミューテーションを 100,000 個まで含めることができます。 単一行の書き込みはアトミックです。単一行に対して複数のミューテーションを作成する場合は、この書き込みタイプを使用します。
単純な書き込みリクエストの送信方法を示すコードサンプルについては、単純な書き込みの実行をご覧ください。
単純な書き込みを使用すべきでない場合
以下のユースケースでは、単純な書き込みは最適なデータ書き込み方法ではありません。
連続した行キーが含まれるデータのバッチを書き込む場合。この場合は、単純な書き込みを連続して行う代わりに、バッチ書き込みを使用することをおすすめします。連続行のバッチを 1 回のバックエンド呼び出しで適用できるためです。
高スループット(1 秒あたりの行数または 1 秒あたりのバイト数)が必要であり、低レイテンシが必須ではない場合。この場合は、バッチ書き込みの方が高速です。
インクリメントと追加
値を引き上げる、または増加させる場合は、集計を使用して書き込み時に値を更新することをおすすめします。集計は、追加オペレーションをサポートしていません。詳細については、書き込み時に値を集計する(プレビュー)をご覧ください。
既存の値にデータを追加する場合や、既存の数値を増分する必要があるが集計を使用できない場合は、ReadModifyWriteRow
リクエストを送信できます。このリクエストには、テーブル名、使用するアプリ プロファイルの ID、行キー、データ書き込み時に使用する一連のルールが含まれます。各ルールには、列ファミリー名と列修飾子、さらには追加値とインクリメント量のいずれか一方を含めます。
ルールは順番に適用されます。たとえば、リクエストの中に列の値を 2 つインクリメントするリクエストが含まれていて、同じリクエスト内の後にあるルールでその同じ列を 1 つインクリメントする場合、この単一アトミック書き込みで列は 3 つインクリメントされます。後のルールによって前のルールが上書きされてしまうことはありません。
値をインクリメントできるのは、その値が 64 ビット ビッグ エンディアン符号付き整数としてエンコードされている場合に限られます。Bigtable は、空の値または存在しない値に対するインクリメントは、値がゼロである場合と同様に扱います。ReadModifyWriteRow
リクエストはアトミックです。なんらかの理由で失敗しても、再試行されません。
セルに値を追加する方法を示すサンプルコードについては、既存の値のインクリメントをご覧ください。
ReadModifyWriteRow
を使用すべきでない場合
次のような場合は、ReadModifyWriteRow
リクエストを送信しないでください。
複数クラスタ ルーティングが含まれるアプリ プロファイルを使用している場合。
複数の単一クラスタ アプリ プロファイルを使用していて、インスタンス内の他のクラスタの同じ行と列に書き込まれるデータと競合する可能性のある書き込みを送信する場合。単一クラスタ ルーティングでは、書き込みリクエストは単一クラスタに送信されてから複製されます。
クライアント ライブラリで提供されているスマート再試行機能に依存している場合。インクリメントと追加は再試行できません。
大量のデータを書き込み、書き込みを迅速に完了する必要がある場合。行を読み取ってからその行を変更するリクエストは、単純な書き込みリクエストよりも低速です。その結果、このタイプの書き込みは大規模な書き込みのための最適なアプローチではないことがよくあります。
たとえば、ページビューなど、数値が数百万規模のカウントを行う場合は、集計を使用して、書き込み時にカウントを更新します。また、値をインクリメントするのではなく、各ビューを単純な書き込みとして記録し、Dataflow ジョブを使用してデータを集計することもできます。
条件付き書き込み
条件に照らして行を確認してから、その結果に応じて行にデータを書き込む場合は、CheckAndMutateRow
リクエストを送信します。 このタイプのリクエストには行キーと行フィルタが含まれます。行フィルタは、既存のデータの値を確認するために使用する一連のルールです。フィルタによって課される特定の条件が満たされている場合のみ、行の特定の列にミューテーションが commit されます。確認に続いて書き込みが行われるこのプロセスは、単一のアトミックな処理として完了します。
フィルタ リクエストには、次のタイプのミューテーションのいずれかまたは両方を含める必要があります。
- true ミューテーション(フィルタが値を返す場合に適用されるミューテーション)
- false ミューテーション(フィルタが何も返さない場合に適用されるミューテーション)
1 回の書き込みで、それぞれのタイプのミューテーション(true と false)を最大 100,000 個指定できます。少なくとも 1 つのミューテーションを送信する必要があります。すべてのミューテーションが完了すると Bigtable はレスポンスを送信します。
条件付き書き込みを送信する方法を示すコードサンプルについては、値の条件付き書き込みをご覧ください。
条件付き書き込みを使用すべきでない場合
以下のユースケースでは、条件付き書き込みを使用できません。
複数クラスタ ルーティングが含まれるアプリ プロファイルを使用している場合。
複数の単一クラスタ アプリ プロファイルを使用していて、インスタンス内の他のクラスタの同じ行と列に書き込まれるデータと競合する可能性のある書き込みを送信する場合。単一クラスタ ルーティングでは、書き込みリクエストは単一クラスタに送信されてから複製されます。
大量のデータを書き込み、書き込みを迅速に完了する必要がある場合。
ReadModifyWriteRow
と同様に、条件付き書き込みリクエストは変更前に行を読み取る必要があるため、CheckAndModifyRow
リクエストは単純な書き込みリクエストよりも低速です。その結果、このタイプの書き込みは大規模な書き込みのための最適なアプローチではないことがよくあります。
バッチ書き込み
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 Beam コネクタ(
BigtableIO
) - Java 用 Bigtable クライアント ライブラリ
- Bigtable HBase Beam コネクタ(
CloudBigtableIO
) - Java 用 Bigtable HBase クライアント
Dataflow ジョブでバッチ書き込みのフロー制御を有効にすると、Bigtable は次の処理を自動的に実行します。
- トラフィックをレート制限して Bigtable クラスタの過負荷を回避する
- Bigtable の自動スケーリングをトリガーするためにクラスタの負荷が十分にあることを確認して(有効な場合)、必要に応じてさらにノードが自動的にクラスタに追加されるようにする
これらの組み合わせたアクションは、クラスタの過負荷とジョブの失敗を防ぐので、バッチ書き込みの実行を見越してクラスタの手動スケーリングを行う必要はありません。フロー制御が有効になっている場合、Dataflow ジョブの前ではなくこの実行中にクラスタ スケーリングが行われるため、クラスタを手動でスケーリングする場合よりもジョブの完了に時間がかかることがあります。
単一クラスタ ルーティング用に構成されたアプリ プロファイルを使用する必要があります。宛先クラスタの Bigtable 自動スケーリングを有効にする必要はありませんが、自動スケーリングでは、バッチ書き込みフロー制御を最大限に活用できます。Dataflow 自動スケーリングは、他のジョブと同様に使用できます。
Bigtable の自動スケーリングの詳細については、自動スケーリングをご覧ください。アプリ プロファイルのルーティング ポリシーについては、アプリ プロファイルの概要をご覧ください。
Bigtable HBase Beam コネクタを使用してバッチ書き込みのフロー制御を有効にする方法を示すコードサンプルについては、Bigtable への書き込みをご覧ください。
承認済みビューにデータを書き込む
承認済みビューにデータを書き込むには、次のいずれかを使用する必要があります。
- gcloud CLI
- Java 用 Bigtable クライアント
他の Bigtable クライアント ライブラリでは、承認済みビューのアクセス権限はまだサポートされていません。
承認済みビューにデータを書き込むときは、テーブル ID に加えて承認済みビューの ID を指定します。
承認済みビューへの書き込みはすべて、基となるテーブルに直接適用されます。
承認済みビューの定義の制限事項
承認済みビューでは、データの書き込み先となる行または列は、承認済みビューの定義によって制限されます。つまり、認可されたビューに指定された条件を満たす行と列にのみ書き込むことができます。
たとえば、承認済みビューが行キーの接頭辞 examplepetstore1
によって定義されている場合、examplepetstore2
の行キーを使用してデータを書き込むことはできません。行キー値の先頭には文字列 examplepetstore1
全体を含める必要があります。
同様に、承認済みビューが列修飾子の接頭辞 order-phone
によって定義されている場合、order-phone123
列修飾子を使用してデータを書き込むことができますが、order-tablet
列修飾子は使用できません。
書き込みリクエストでは、条件付き書き込みリクエストの値をチェックしようとする場合など、承認済みビュー外のデータを参照することもできません。
承認済みビュー外のデータの書き込みまたは参照を行うリクエストでは、PERMISSION_DENIED
のエラー メッセージが返されます。
レプリケーション
マルチクラスタ インスタンスの 1 つのクラスタが書き込みを受け取ると、その書き込みはインスタンス内の他のクラスタに直ちに複製されます。
アトミック性
マルチクラスタ インスタンスに送信する各 MutateRows
リクエストは、リクエストのルーティング先となるクラスタに対する単一のアトミック アクションとしてコミットされます。この書き込みがインスタンス内の他のクラスタに複製されると、それらの各クラスタも書き込みをアトミック オペレーションとして受け取ります。クラスタが部分的なミューテーションを受け取ることはありません。ミューテーションは、変更するすべてのセルに対してアトミックに適用され、全体が成功するか失敗するかのいずれかになります。
整合性
書き込んだデータが読み取りに使用できるようになるまでに要する時間は、インスタンス内のクラスタの数や、アプリ プロファイルで使用するルーティングのタイプなど、複数の要因によって左右されます。
単一クラスタ インスタンスでは、データはすぐに読み取り可能になりますが、インスタンスに複数のクラスタがある場合、つまりレプリケーションを使用している場合、Bigtable は結果整合性になります。リクエストを同一クラスタにルーティングすると、read-your-writes の整合性を実現できます。
書き込みリクエストを送信した後は、整合性トークンを作成して使用し、StandardReadRemoteWrites
モードで CheckConsistency
を呼び出すことができます。このトークンはレプリケーションの整合性を確認します。一般的には、書き込みのバッチが送信された後、または 1 時間などの特定の間隔の後に、整合性トークンを作成します。続いて、読み取りリクエストを行うモジュールなど、別のプロセスにトークンを渡してそのプロセスで使用することができます。そのプロセスでは、このトークンを使用して読み取り試行の前にすべてのデータが複製されていることを確認します。
トークンを作成した直後に使用する場合は、初回使用時の整合性の確認に数分かかることがあります。この遅延が発生するのは、各クラスタが他のすべてのクラスタをチェックして、追加のデータが送信されていないことを確認するためです。トークンの初回使用が完了している場合、またはトークンを初回使用する際に数分待機した場合、トークンの使用は即座に完了します。
競合の解決
Bigtable テーブルの各セルの値は 4 タプル(行キー、列ファミリー、列修飾子、タイムスタンプ)で一意に識別されます。これらの識別子の詳細については、Bigtable ストレージ モデルをご覧ください。まったく同じ 4 つのタプルの 2 つの書き込みが 2 つの異なるクラスタに送信された場合、Bigtable は、サーバー側の時間に基づいて最後の書き込みを優先する内部アルゴリズムを使用して、競合を自動的に解決します。Bigtable の「最後の書き込みの優先」の実装は確定的で、レプリケーションが完了すると、すべてのクラスタの 4 つのタプルが同じ値になります。