これらのプラクティスを使用して、ライフサイクル全体にわたって信頼性が高く、スケーラブルで観測可能なデータを整理し、管理します。
データを整理する
データストアを少なくする
データストアはデータベースのテーブルに似た動作をします。小さく固定されたデータストアのセットを使用し、その中でレコードをキーによって整理します。たとえば、各プレイヤーのプロファイルを個別のデータストアを作成するのではなく、1つの PlayerData データストアに保存します。
プレイヤーごとに1つまたは少数のキーを使用する
データが 4 MB オブジェクトサイズ制限 内に収まる場合は、各プレイヤーの永続データを1つのキーの下に保存します。たとえば、PlayerData データストア内で User_123456 のようなキーを使用します。このパターンはリクエストを減らし、関連する値を原子的に更新でき、ロールバックをより簡単に理解できるようにします。
プレイヤーのデータの異なる部分が異なるアクセスパターンを持っている場合や、キーごとのサイズまたはスループット制限に近づく場合は、レコードを少数の決定論的なキーに分割します。原子的に変更する必要があるデータは同じキーに保持します。
静的キーのパターンとプレフィックスを使用する
安定した識別子と静的パターンからキー名を構築します。たとえば、User_{UserId} のようにします。表示名や変更可能な他の値は使用しないでください。静的パターンは、サーバーやツール間でキーを予測可能にします。データストアの場合、自動的な忘れられる権利処理 がプレイヤーデータを特定できるようにします。
関連するキーをグループ化するために プレフィックス を使用します。たとえば、複数のキャラクタープロファイルをサポートする体験では、User_123456/Profile/Warrior と User_123456/Profile/Mage を使用するかもしれません。次に、User_123456/Profile を ListKeysAsync() に渡して、そのプレイヤーのプロファイルをリストできます。
スコープ はデータストアを細分化する別の方法です。スコープは、そのデータストアインスタンス内のすべてのキーの前に文字列を追加し、デフォルトは global です。
データストアモジュールを評価する
サードパーティのデータストアモジュールは常に選択肢であり、多くの場合、ゼロからシステムを構築するよりも好まれることがあります。採用する前に、その所有権、メンテナンス状況、および機能セットを確認してください。モジュールなしでデータにアクセスし、移行する方法を理解します。
リクエストを減らし、分散させる
プレイヤーデータをメモリにバッファリングする
セッションの開始時にプレイヤーのデータをロードし、ゲームプレイのためにサーバーのローカルコピーを保持します。すべての変更に対してデータストアリクエストを送信するのではなく、ローカルコピーを更新します。プレイヤーが離れたとき、サーバーがシャットダウンするとき、購入処理などの重要なチェックポイントで定期的に保存します。リクエスト制限内に収まり、セッションロックの有効期限よりも短い定期的な保存間隔を選択します。たとえば、プレイヤーデータと購入サンプル は180秒を使用しています。
繰り返しリクエストをずらす
すべてのサーバーから同じスケジュールで繰り返しリクエストを開始しないでください。固定周波数のループを開始する前に、各サーバーまたはプレイヤーにランダムな初期オフセットを割り当てます。正確なリズムを必要としないポーリングや調整ループの場合は、各間隔に制限付きのランダムジッターを追加します。これらのパターンは、時間をかけてリクエストを分散させ、同期したトラフィックスパイクを減らします。
一時的な失敗を再試行する
リクエストを pcall() でラップし、一時的な失敗を指数バックオフで再試行します。サーバーが同時に再試行しないように、各遅延にランダムジッターを追加します。遅延と試行回数に上限を設け、無効なリクエストやもはや有用な結果を提供できない操作によって引き起こされたエラーは再試行しないでください。
各キーのデータストア再試行を順番に処理します。新しいリクエストが成功した後に古いリクエストが再試行されると、新しいデータが上書きされる可能性があります。また、結果が不明な書き込みも考慮します。失敗した呼び出しはサーバーが成功した応答を受け取らなかったことを意味しますが、バックエンドは書き込みを完了している可能性があります。詳細については、データストアエラーコードと制限 および 再試行 を参照してください。
SetAsync よりも UpdateAsync を優先する
書き込みが現在の値に依存する場合や、複数のサーバーが同じキーに書き込む可能性がある場合は、UpdateAsync() を優先します。UpdateAsync() は書き込む前にコールバックに最新の値を読み込み、更新の損失を減らします。SetAsync() は最初に読み込まずにキーを上書きし、2つのサーバーが同時に書き込むと不整合を引き起こす可能性があります。
新しいキーを作成する場合や、前の値に依存しない値を置き換える場合は SetAsync() を使用します。2つのメソッドの比較については、Set と Update を参照してください。
ホットキーをシャーディングする
各キーには 読み取りおよび書き込みスループット制限 があります。不要なリクエストを減らした後に1つの論理レコードがこれらの制限に一貫して達する場合は、決定論的なキーにシャーディングします。User_{UserId}_Inventory_{ShardId} のように識別子から安定したシャードを選択し、すべてのサーバーが同じデータを同じシャードにルーティングします。
シャーディングは、一貫性を維持し、将来の移行を行うことをより複雑にします。1つのキーに収まり、スループット制限を下回るデータをシャーディングしないでください。
オペレーションワークフローを構築する
利用可能なツールを一緒に使用します:
- 観察する。 データストアの可観測性ダッシュボード を使用して、リクエスト、応答ステータス、スループット、ストレージを追跡します。重要なデータストアメトリックのために カスタムアラート を設定し、チームが持続的な障害や予期しない成長に対応できるようにします。クリエイターハブの通知は、ストレージが制限に近づくか超えたときに知らせ、ガイダンスやダッシュボードへのリンクを含みます。
- 検査する。 データストアマネージャー を使用して、データストア、キー、ストレージ使用量、および推定コストを調べます。体験が100以上のデータストアを持つ場合、データストアリストにはサイズとキーのカウントが表示されません。これらのメトリックには、Open Cloud または データストアバッチプロセッサ を使用します。
- 修正する。 個々のレコードにはデータストアマネージャーを使用します。繰り返し可能または大規模なワークフローには、Open Cloud データストア API または データストアバッチプロセッサ を使用します。
- 意図的にスケールする。 まず、不要なストレージとリクエストを減らします。正当な使用がデフォルトのクォータを超える場合は、拡張サービス を評価します。
Open Cloud とゲームサーバーは、体験レベルのリクエスト予算を共有します。運用の Open Cloud スクリプトのレート制限を行い、ライブトラフィックに干渉しないようにします。
データライフサイクルを管理する
新しいキーを作成するのではなく、データストアのバージョンを使用します。キーの最新バージョンのみがストレージ使用量にカウントされ、バージョンを使用すると以前の値を検査または復元できます。
一時的で急速に変化するデータには メモリストア を使用します。メモリストアのデータは自動的に期限切れになり、永続データストアのストレージには追加されません。
テストが終了したらテストデータを削除し、期限切れのイベントや退役した機能のデータを削除します。データストアを削除のためにマークした後、復元できる30日間のバッファがあります。その30日後、Roblox はデータストアを永久に削除します。詳細については、データストアマネージャー を参照してください。
忘れられる権利処理を設定する
静的データストアおよびキーのパターンに従うプレイヤーデータのために、自動的な忘れられる権利 (RTBF) 処理 を設定します。自動RTBFは、Roblox が適格なリクエストを処理する際に削除テンプレートを適用するため、推奨されるワークフローです。
自動RTBFがデータスキーマをサポートしていない場合は、削除の権利ウェブフック を使用してカスタム削除ワークフローを実行します。いずれのワークフローも、すべての一致するプレイヤーデータを削除することを確認してください。