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