MemoryStoreService هي خدمة بيانات ذات سعة عالية وزمن استجابة منخفض توفر تخزين بيانات سريع في الذاكرة يمكن الوصول إليه من جميع الخوادم في جلسة حية. مخازن الذاكرة مناسبة للبيانات المتكررة والزائلة التي تتغير بسرعة ولا تحتاج إلى أن تكون دائمة، لأنها أسرع في الوصول وتختفي عند الوصول إلى الحد الأقصى لعمرها. بالنسبة للبيانات التي تحتاج إلى الاستمرار عبر الجلسات، استخدم مخازن البيانات.
هياكل البيانات
بدلاً من الوصول مباشرة إلى البيانات الخام، تحتوي مخازن الذاكرة على ثلاث هياكل بيانات بدائية مشتركة عبر الخوادم لمعالجة سريعة: خريطة مرتبة، طابور، وخريطة تجزئة. كل هيكل بيانات مناسب لحالات استخدام معينة:
- مطابقة قائمة على المهارات - حفظ معلومات المستخدم، مثل مستوى المهارة، في طابور مشترك بين الخوادم، واستخدام خوادم اللوبي لتشغيل المطابقة بشكل دوري.
- التجارة والمزادات عبر الخوادم - تمكين التجارة العالمية بين الخوادم المختلفة، حيث يمكن للمستخدمين المزايدة على العناصر بأسعار تتغير في الوقت الحقيقي، مع خريطة مرتبة من أزواج المفتاح والقيمة.
- لوحات المتصدرين العالمية - تخزين وتحديث تصنيفات المستخدمين على لوحة متصدرين مشتركة داخل خريطة مرتبة.
- المخازن المشتركة - حفظ عناصر المخزون والإحصائيات في خريطة تجزئة مشتركة، حيث يمكن للمستخدمين استخدام عناصر المخزون بالتزامن مع بعضهم البعض.
- ذاكرة مؤقتة للبيانات الدائمة - مزامنة ونسخ بياناتك الدائمة في مخزن بيانات إلى خريطة تجزئة في الذاكرة يمكن أن تعمل كذاكرة مؤقتة وتحسن أداء لعبتك.
بشكل عام، إذا كنت بحاجة إلى الوصول إلى البيانات بناءً على مفتاح معين، استخدم خريطة تجزئة. إذا كنت بحاجة إلى أن تكون تلك البيانات مرتبة، استخدم خريطة مرتبة. إذا كنت بحاجة إلى معالجة بياناتك بترتيب معين، استخدم طابور.
الحدود والحصص
للحفاظ على قابلية التوسع وأداء النظام، تحتوي مخازن الذاكرة على حصص استخدام البيانات لحجم الذاكرة، طلبات API، وحجم هيكل البيانات.
تحتوي مخازن الذاكرة على سياسة إخلاء تعتمد على وقت انتهاء الصلاحية، والمعروفة أيضًا باسم الوقت للحياة (TTL). يتم إخلاء العناصر بعد انتهاء صلاحيتها، ويتم تحرير حصة الذاكرة لإدخالات جديدة. عندما تصل إلى حد الذاكرة، تفشل جميع طلبات الكتابة اللاحقة حتى تنتهي صلاحية العناصر أو تقوم بحذفها يدويًا.
حصة حجم الذاكرة
تحدد حصة الذاكرة الحد الأقصى لمقدار الذاكرة التي يمكن أن تستهلكها اللعبة. إنها ليست قيمة ثابتة؛ بدلاً من ذلك، تتغير مع مرور الوقت اعتمادًا على عدد المستخدمين في اللعبة وفقًا للصيغة 64 كيلوبايت + 1.2 كيلوبايت * [عدد المستخدمين]. تنطبق الحصة على مستوى اللعبة بدلاً من مستوى الخادم.
عندما ينضم المستخدمون إلى اللعبة، تتوفر حصة الذاكرة الإضافية على الفور. عندما يغادر المستخدمون اللعبة، لا تقل الحصة على الفور. هناك فترة تتبع مدتها ثمانية أيام قبل أن تعيد الحصة تقييمها إلى قيمة أقل.
بعد أن تصل لعبتك إلى حصة حجم الذاكرة، تفشل أي طلبات API تزيد من حجم الذاكرة دائمًا. لا تزال الطلبات التي تقلل أو لا تغير حجم الذاكرة تنجح.
مع لوحة المراقبة، يمكنك عرض حصة حجم الذاكرة للعبتك في الوقت الحقيقي باستخدام مخطط استخدام الذاكرة.
حدود طلبات API
تنطبق حصة وحدة الطلب على جميع استدعاءات API لـ MemoryStoreService. هذه الحصة هي 1000 + 120 * [عدد المستخدمين المتزامنين] وحدات طلب في الدقيقة.
تستهلك معظم استدعاءات API وحدة طلب واحدة فقط، مع بعض الاستثناءات:
MemoryStoreSortedMap:GetRangeAsync()
تستهلك وحدات بناءً على عدد العناصر المعادة. على سبيل المثال، إذا أعاد هذا الأسلوب 10 عناصر، فإن الاستدعاء يُحتسب كـ 10 وحدات طلب. إذا أعاد استجابة فارغة، يُحتسب كـ وحدة طلب واحدة.
تستهلك وحدات بناءً على عدد العناصر المعادة، تمامًا مثل MemoryStoreSortedMap:GetRangeAsync()، ولكن تستهلك وحدة إضافية كل ثانيتين أثناء القراءة. حدد الحد الأقصى لوقت القراءة باستخدام معلمة waitTimeout.
MemoryStoreHashMap:UpdateAsync()
تستهلك حدًا أدنى من وحدتين.
MemoryStoreHashMap:ListItemsAsync()
تستهلك [عدد الأقسام الممسوحة] + [العناصر المعادة] وحدات.
تُطبق حصة الطلبات أيضًا على مستوى اللعبة بدلاً من مستوى الخادم. وهذا يوفر مرونة لتوزيع الطلبات بين الخوادم طالما أن معدل الطلبات الإجمالي لا يتجاوز الحصة. إذا تجاوزت الحصة، ستتلقى استجابة خطأ عندما يقوم النظام بتقليل طلباتك.
مع ميزة المراقبة المتاحة، يمكنك عرض حصة وحدة الطلب للعبتك في الوقت الحقيقي.
حدود حجم هيكل البيانات
بالنسبة لخريطة مرتبة واحدة أو طابور، تنطبق الحدود التالية على الحجم وعدد العناصر:
- الحد الأقصى لعدد العناصر: 1,000,000
- الحد الأقصى للحجم الإجمالي (بما في ذلك المفاتيح لخريطة مرتبة): 100 ميغابايت
حدود لكل قسم
انظر الحدود لكل قسم.
أفضل الممارسات
للحفاظ على نمط استخدام الذاكرة الخاص بك مثاليًا وتجنب الوصول إلى الحدود، اتبع هذه الممارسات الجيدة:
إزالة العناصر المعالجة. يمكن أن يؤدي التنظيف المستمر للعناصر المقروءة باستخدام طريقة MemoryStoreQueue:RemoveAsync() للطوابير وMemoryStoreSortedMap:RemoveAsync() لخريطة مرتبة إلى تحرير الذاكرة والحفاظ على تحديث هيكل البيانات.
تعيين وقت انتهاء الصلاحية لأقصر فترة زمنية ممكنة عند إضافة البيانات. على الرغم من أن وقت انتهاء الصلاحية الافتراضي هو 45 يومًا لكل من MemoryStoreQueue:AddAsync() وMemoryStoreSortedMap:SetAsync()، فإن تعيين أقصر وقت ممكن يمكن أن ينظف تلقائيًا البيانات القديمة لمنعها من ملء حصة استخدام الذاكرة الخاصة بك.
- لا تخزن كمية كبيرة من البيانات مع انتهاء صلاحية طويلة، حيث إن ذلك يعرضك لخطر تجاوز حصة الذاكرة الخاصة بك وقد يتسبب في مشاكل قد تؤدي إلى كسر لعبتك بالكامل.
- احرص دائمًا على حذف العناصر غير الضرورية بشكل صريح أو تعيين انتهاء صلاحية قصيرة للعناصر.
- بشكل عام، يجب عليك استخدام الحذف الصريح لتحرير الذاكرة وانتهاء صلاحية العناصر كآلية أمان لمنع العناصر غير المستخدمة من شغل الذاكرة لفترة طويلة من الزمن.
احتفظ فقط بالقيم الضرورية في الذاكرة.
على سبيل المثال، بالنسبة للعبة مزاد، تحتاج فقط إلى الحفاظ على أعلى مزايدة. يمكنك استخدام MemoryStoreSortedMap:UpdateAsync() على مفتاح واحد للحفاظ على أعلى مزايدة بدلاً من الاحتفاظ بجميع المزايدات في هيكل البيانات الخاص بك.
استخدم التراجع الأسي للمساعدة في البقاء تحت حدود طلبات API.
على سبيل المثال، إذا تلقيت DataUpdateConflict، قد تعيد المحاولة بعد ثانيتين، ثم أربع، وثماني، إلخ، بدلاً من إرسال الطلبات باستمرار إلى MemoryStoreService للحصول على الاستجابة الصحيحة.
قسم هياكل البيانات الضخمة إلى هياكل أصغر متعددة عن طريق التجزئة.
غالبًا ما يكون من الأسهل إدارة البيانات في هياكل أصغر بدلاً من تخزين كل شيء في هيكل بيانات كبير واحد. يمكن أن تساعد هذه الطريقة أيضًا في تجنب حدود الاستخدام والمعدل. على سبيل المثال، إذا كان لديك خريطة مرتبة تستخدم بادئات لمفاتيحها، فكر في فصل كل بادئة إلى خريطة مرتبة خاصة بها. بالنسبة للعبة شائعة بشكل خاص، قد تفكر حتى في فصل المستخدمين إلى خرائط متعددة بناءً على الأرقام الأخيرة من معرفات المستخدمين الخاصة بهم.
قم بتجزئة المفاتيح التي يتم الوصول إليها بشكل متكرر في خرائط التجزئة مع نسخ متعددة من المفتاح لتوزيع الحمل.
ضغط القيم المخزنة.
على سبيل المثال، فكر في استخدام خوارزمية LZW لتقليل حجم القيمة المخزنة.
انضم إلى خدمات موسعة.
يمكنك زيادة حصص التخزين وطلباتك من خلال الانضمام إلى خدمات موسعة.
المراقبة
توفر لوحة المراقبة رؤى وتحليلات لمراقبة واستكشاف استخدام مخزن الذاكرة الخاص بك. مع الرسوم البيانية التي تتحدث في الوقت الحقيقي حول جوانب مختلفة من استخدام الذاكرة وطلبات API، يمكنك تتبع نمط استخدام الذاكرة للعبتك، عرض الحصص المخصصة الحالية، مراقبة حالة API، وتحديد المشكلات المحتملة لتحسين الأداء.
تسرد الجدول التالي وتصف جميع رموز الحالة لاستجابات API المتاحة على مخطط عدد الطلبات حسب الحالة والطلبات حسب API x الحالة في لوحة المراقبة. لمزيد من المعلومات حول كيفية حل هذه الأخطاء، انظر استكشاف الأخطاء وإصلاحها. للحصول على الحصة أو الحد المحدد الذي يتعلق به الخطأ، انظر الحدود والحصص.
| رمز الحالة | الوصف |
|---|---|
| نجاح | نجاح. |
| DataStructureMemoryOverLimit | يتجاوز حد حجم الذاكرة على مستوى هيكل البيانات (100 ميغابايت). |
| DataUpdateConflict | تعارض بسبب تحديث متزامن. |
| AccessDenied | غير مصرح بالوصول إلى بيانات اللعبة. لا تستهلك هذه الطلبات وحدات الطلب أو تستخدم الحصة. |
| InternalError | خطأ داخلي. |
| InvalidRequest | الطلب لا يحتوي على المعلومات المطلوبة أو يحتوي على معلومات مشوهة. |
| DataStructureItemsOverLimit | يتجاوز حد عدد العناصر على مستوى هيكل البيانات (1M). |
| NoItemFound | لم يتم العثور على عنصر في MemoryStoreQueue:ReadAsync() أو MemoryStoreSortedMap:UpdateAsync(). تقوم ReadAsync() بالاستطلاع كل ثانيتين وتعيد رمز الحالة هذا حتى تجد عناصر في الطابور. |
| DataStructureRequestsOverLimit | يتجاوز حد وحدات الطلب على مستوى هيكل البيانات (100,000 وحدة طلب في الدقيقة). |
| PartitionRequestsOverLimit | يتجاوز حد وحدات الطلب على مستوى القسم. |
| TotalRequestsOverLimit | يتجاوز حد وحدات الطلب على مستوى الكون. |
| TotalMemoryOverLimit | يتجاوز حد حصة الذاكرة على مستوى الكون. |
| ItemValueSizeTooLarge | يتجاوز حجم القيمة الحد (32 كيلوبايت). |
تسرد الجدول التالي رموز الحالة من جانب العميل، والتي لا تتوفر حاليًا على لوحة المراقبة.
| رمز الحالة | الوصف |
|---|---|
| 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 |
مثال على إلغاء الطلب |
| Internal Error |
|
| InvalidRequest |
|
| ItemValueSizeTooLarge |
|
الاختبار وتصحيح الأخطاء في الاستوديو
البيانات في MemoryStoreService معزولة بين الاستوديو والإنتاج، لذا فإن تغيير البيانات في الاستوديو لا يؤثر على سلوك الإنتاج. وهذا يعني أن استدعاءات API الخاصة بك من الاستوديو لا تصل إلى بيانات الإنتاج، مما يسمح لك باختبار مخازن الذاكرة والميزات الجديدة بأمان قبل الانتقال إلى الإنتاج.
يحتوي اختبار الاستوديو على نفس الحدود والحصص مثل الإنتاج. بالنسبة للحصص المحسوبة بناءً على عدد المستخدمين، يمكن أن تكون الحصة الناتجة صغيرة جدًا نظرًا لأنك المستخدم الوحيد لاختبار الاستوديو. عند الاختبار من الاستوديو، قد تلاحظ أيضًا زمن استجابة أعلى قليلاً ومعدلات خطأ مرتفعة مقارنةً بالاستخدام في الإنتاج بسبب بعض الفحوصات الإضافية التي يتم إجراؤها للتحقق من الوصول والأذونات.
للحصول على معلومات حول كيفية تصحيح مخزن الذاكرة في الألعاب الحية أو عند الاختبار في الاستوديو، استخدم وحدة التحكم للمطورين.