MemoryStoreService は、高スループットで低遅延のデータサービスで、ライブセッション中のすべてのサーバーからアクセス可能な迅速なメモリ内データストレージを提供します。 メモリストア は、頻繁に変化し、耐久性を必要としない一時的なデータに適しており、アクセスが速く、最大寿命に達すると消失します。セッションをまたいで持続する必要があるデータには、データストアを使用してください。
データ構造
生データに直接アクセスする代わりに、メモリストアには、サーバー間で迅速に処理できる3つの基本データ構造があります: ソートマップ、キュー、および ハッシュマップ。各データ構造は特定のユースケースに適しています:
- スキルベースのマッチメイキング - サーバー間で共有されるキューにユーザー情報(スキルレベルなど)を保存し、ロビーサーバーを使用して定期的にマッチメイキングを実行します。
- クロスサーバー取引とオークション - ユーザーがリアルタイムで変化する価格でアイテムに入札できるように、異なるサーバー間でのユニバーサルトレーディングを可能にし、キーと値のペアのソートマップを使用します。
- グローバルリーダーボード - 共有リーダーボード内でユーザーのランキングを保存および更新します。
- 共有インベントリ - ユーザーが互いにインベントリアイテムを同時に利用できるように、共有ハッシュマップにインベントリアイテムと統計を保存します。
- 永続データのキャッシュ - データストアの永続データをメモリストアのハッシュマップに同期およびコピーし、キャッシュとして機能させてゲームのパフォーマンスを向上させます。
一般的に、特定のキーに基づいてデータにアクセスする必要がある場合は、ハッシュマップを使用します。データを順序付ける必要がある場合は、ソートマップを使用します。特定の順序でデータを処理する必要がある場合は、キューを使用します。
制限とクォータ
スケーラビリティとシステムパフォーマンスを維持するために、メモリストアにはメモリサイズ、APIリクエスト、およびデータ構造サイズに関するデータ使用クォータがあります。
メモリストアには、TTL(生存時間)とも呼ばれる有効期限に基づく排出ポリシーがあります。アイテムは期限が切れた後に排出され、新しいエントリのためにメモリクォータが解放されます。メモリ制限に達すると、その後のすべての書き込みリクエストは、アイテムが期限切れになるか、手動で削除されるまで失敗します。
メモリサイズクォータ
メモリクォータは、ゲームが消費できるメモリの総量を制限します。これは固定値ではなく、ゲーム内のユーザー数に応じて時間とともに変化します。計算式は 64 KB + 1.2 KB * [ユーザー数] です。クォータはサーバーレベルではなく、ゲームレベルに適用されます。
ユーザーがゲームに参加すると、追加のメモリクォータがすぐに利用可能になります。ユーザーがゲームを離れると、クォータはすぐには減少しません。クォータが低い値に再評価されるまでのトレースバック期間は8日間です。
ゲームがメモリサイズクォータに達すると、メモリサイズを増加させるAPIリクエストは常に失敗します。メモリサイズを減少させるか、変更しないリクエストは成功します。
可観測性ダッシュボードを使用すると、メモリ使用量チャートを使用して、ゲームのメモリサイズクォータをリアルタイムで確認できます。
APIリクエスト制限
リクエストユニットクォータは、すべての MemoryStoreService API呼び出しに適用されます。このクォータは 1000 + 120 * [同時ユーザー数] リクエストユニット/分です。
ほとんどのAPI呼び出しは1リクエストユニットしか消費しませんが、いくつかの例外があります:
MemoryStoreSortedMap:GetRangeAsync()
戻り値のアイテム数に基づいてユニットを消費します。たとえば、このメソッドが10アイテムを返す場合、呼び出しは10リクエストユニットとしてカウントされます。空の応答を返す場合は、1リクエストユニットとしてカウントされます。
戻り値のアイテム数に基づいてユニットを消費します。MemoryStoreSortedMap:GetRangeAsync()と同様ですが、読み取り中に2秒ごとに追加のユニットを消費します。waitTimeoutパラメータで最大読み取り時間を指定します。
MemoryStoreHashMap:UpdateAsync()
最低2ユニットを消費します。
MemoryStoreHashMap:ListItemsAsync()
[スキャンされたパーティション数] + [返されたアイテム] ユニットを消費します。
リクエストクォータもサーバーレベルではなく、ゲームレベルに適用されます。これにより、合計リクエストレートがクォータを超えない限り、サーバー間でリクエストを柔軟に割り当てることができます。クォータを超えると、サービスがリクエストを制限したときにエラーレスポンスが返されます。
可観測性機能を使用すると、ゲームのリクエストユニットクォータをリアルタイムで確認できます。
データ構造サイズ制限
単一のソートマップまたはキューに対して、次のサイズおよびアイテム数の制限が適用されます:
- 最大アイテム数: 1,000,000
- 最大総サイズ(ソートマップのキーを含む): 100 MB
パーティションごとの制限
パーティションごとの制限を参照してください。
ベストプラクティス
メモリ使用パターンを最適に保ち、制限に達するのを避けるために、次のベストプラクティスに従ってください:
処理済みアイテムを削除します。 MemoryStoreQueue:RemoveAsync()メソッドを使用してキューの読み取ったアイテムを一貫してクリーンアップし、MemoryStoreSortedMap:RemoveAsync()を使用してソートマップを更新することで、メモリを解放し、データ構造を最新の状態に保つことができます。
データを追加する際には、可能な限り短い時間枠に有効期限を設定します。 MemoryStoreQueue:AddAsync()および MemoryStoreSortedMap:SetAsync()のデフォルトの有効期限は45日ですが、最短の時間を設定することで、古いデータを自動的にクリーンアップし、メモリ使用量クォータを埋め尽くすのを防ぐことができます。
- 長い有効期限で大量のデータを保存しないでください。これはメモリクォータを超えるリスクがあり、ゲーム全体を壊す可能性のある問題を引き起こす可能性があります。
- 不要なアイテムは常に明示的に削除するか、短いアイテムの有効期限を設定してください。
- 一般的に、メモリを解放するためには明示的な削除を使用し、アイテムの有効期限を安全機構として使用して、未使用のアイテムが長期間メモリを占有するのを防ぐべきです。
メモリに必要な値のみを保持します。
たとえば、オークションハウスゲームでは、最高入札額のみを維持する必要があります。すべての入札をデータ構造に保持するのではなく、1つのキーに対して MemoryStoreSortedMap:UpdateAsync()を使用して最高入札額を保持できます。
指数バックオフを使用してAPIリクエスト制限を下回るようにします。
たとえば、DataUpdateConflictを受け取った場合、2秒後、次に4秒、8秒などで再試行することができます。MemoryStoreServiceに対して正しい応答を得るためにリクエストを常に送信するのではなく。
巨大なデータ構造を複数の小さなものに分割します。シャーディングを使用します。
すべてを1つの大きなデータ構造に保存するのではなく、小さな構造でデータを管理する方が簡単です。このアプローチは、使用制限やレート制限を回避するのにも役立ちます。たとえば、キーにプレフィックスを使用するソートマップがある場合は、各プレフィックスを独自のソートマップに分けることを検討してください。特に人気のあるゲームの場合、ユーザーIDの最後の数字に基づいてユーザーを複数のマップに分けることもできます。
ハッシュマップで頻繁にアクセスされるキーを複数のキーのコピーでシャーディングして負荷を分散します。
保存された値を圧縮します。
たとえば、保存された値のサイズを減らすためにLZWアルゴリズムを使用することを検討してください。
拡張サービスに登録します。
拡張サービスにオンボーディングすることで、ストレージおよびリクエスト制限のクォータを増やすことができます。
可観測性
可観測性ダッシュボードは、メモリストアの使用状況を監視およびトラブルシューティングするための洞察と分析を提供します。メモリ使用量やAPIリクエストのさまざまな側面に関するリアルタイム更新チャートを使用して、ゲームのメモリ使用パターンを追跡し、現在の割り当てクォータを表示し、APIの状態を監視し、パフォーマンス最適化のための潜在的な問題を特定できます。
以下の表は、可観測性ダッシュボードのステータス別リクエスト数およびAPI x ステータス別リクエストチャートで利用可能なAPIレスポンスのすべてのステータスコードをリストし、説明します。これらのエラーを解決する方法の詳細については、トラブルシューティングを参照してください。エラーに関連する特定のクォータまたは制限については、制限とクォータを参照してください。
| ステータスコード | 説明 |
|---|---|
| 成功 | 成功。 |
| DataStructureMemoryOverLimit | データ構造レベルのメモリサイズ制限(100 MB)を超えています。 |
| DataUpdateConflict | 同時更新による競合。 |
| AccessDenied | ゲームデータにアクセスする権限がありません。このリクエストはリクエストユニットを消費せず、クォータを使用しません。 |
| InternalError | 内部エラー。 |
| InvalidRequest | リクエストに必要な情報が含まれていないか、情報が不正です。 |
| DataStructureItemsOverLimit | データ構造レベルのアイテム数制限(1M)を超えています。 |
| NoItemFound | MemoryStoreQueue:ReadAsync()またはMemoryStoreSortedMap:UpdateAsync()でアイテムが見つかりませんでした。ReadAsync()は2秒ごとにポーリングし、キュー内にアイテムが見つかるまでこのステータスコードを返します。 |
| DataStructureRequestsOverLimit | データ構造レベルのリクエストユニット制限(100,000リクエストユニット/分)を超えています。 |
| PartitionRequestsOverLimit | パーティションリクエストユニット制限を超えています。 |
| TotalRequestsOverLimit | ユニバースレベルのリクエストユニット制限を超えています。 |
| TotalMemoryOverLimit | ユニバースレベルのメモリクォータを超えています。 |
| ItemValueSizeTooLarge | 値のサイズが制限(32 KB)を超えています。 |
以下の表は、クライアント側のステータスコードをリストしており、現在可観測性ダッシュボードでは利用できません。
| ステータスコード | 説明 |
|---|---|
| InternalError | 内部エラー。 |
| UnpublishedPlace | MemoryStoreServiceを使用するには、この場所を公開する必要があります。 |
| InvalidClientAccess | MemoryStoreServiceはサーバーから呼び出す必要があります。 |
| InvalidExpirationTime | フィールド「expiration」時間は0から3,888,000の間でなければなりません。 |
| InvalidRequest | 値をjsonに変換できません。 |
| InvalidRequest | sortKeyを有効な数値または文字列に変換できません。 |
| TransformCallbackFailed | 変換コールバック関数の呼び出しに失敗しました。 |
| RequestThrottled | 最近のMemoryStoresリクエストが1つ以上の制限に達しました。 |
| UpdateConflict | 最大リトライ回数を超えました。 |
トラブルシューティング
以下の表は、各レスポンスステータスコードに対する推奨解決策をリストして説明します:
| エラー | トラブルシューティングオプション |
|---|---|
| DataStructureRequestsOverLimit / PartitionRequestsOverLimit |
|
| TotalRequestsOverLimit | |
| DataStructureItemsOverLimit |
|
| DataStructureMemoryOverLimit | |
| TotalMemoryOverLimit | |
| DataUpdateConflict |
リクエスト中止の例 |
| 内部エラー |
|
| InvalidRequest |
|
| ItemValueSizeTooLarge |
|
スタジオでのテストとデバッグ
MemoryStoreServiceのデータはスタジオと本番環境で隔離されているため、スタジオでデータを変更しても本番環境の動作には影響しません。これは、スタジオからのAPI呼び出しが本番データにアクセスしないことを意味し、メモリストアや新機能を本番環境に移行する前に安全にテストできます。
スタジオでのテストは、本番環境と同じ制限とクォータが適用されます。ユーザー数に基づいて計算されるクォータの場合、スタジオテストのユーザーはあなた一人だけなので、結果として得られるクォータは非常に小さくなる可能性があります。スタジオからテストする際には、アクセスと権限を確認するために実行される追加のチェックのために、本番環境での使用に比べてわずかに高い遅延とエラー率が見られることがあります。
ライブゲームやスタジオでのテスト中にメモリストアをデバッグする方法については、開発者コンソールを使用してください。