MemoryStoreService เป็นบริการข้อมูลที่มีอัตราการไหลสูงและความหน่วงต่ำ ซึ่งให้การเก็บข้อมูลที่อยู่ในหน่วยความจำได้อย่างรวดเร็วและสามารถเข้าถึงได้จากเซิร์ฟเวอร์ทั้งหมดในเซสชันที่ใช้งานอยู่ Memory Stores เหมาะสำหรับข้อมูลที่มีการเปลี่ยนแปลงบ่อยและชั่วคราว ซึ่งไม่จำเป็นต้องมีความทนทาน เนื่องจากเข้าถึงได้เร็วกว่าและหายไปเมื่อถึงอายุขmax. สำหรับข้อมูลที่ต้องการความคงที่ข้ามเซสชัน ให้ใช้ data stores.
โครงสร้างข้อมูล
แทนที่จะเข้าถึงข้อมูลดิบโดยตรง ระบบจัดเก็บข้อมูลหน่วยความจำมีโครงสร้างข้อมูลพื้นฐานสามแบบที่แชร์กันระหว่างเซิร์ฟเวอร์เพื่อการประมวลผลอย่างรวดเร็ว: sorted map, queue, และ hash map. โครงสร้างข้อมูลแต่ละแบบเหมาะกับกรณีใช้งานบางประการ:
- จับคู่ผู้เล่นตามทักษะ - บันทึกข้อมูลผู้ใช้ เช่น ระดับทักษะ ไว้ใน queue ที่แชร์กันระหว่างเซิร์ฟเวอร์ และใช้ล็อบบี้เซิร์ฟเวอร์เพื่อดำเนินการจับคู่เป็นระยะๆ
- การซื้อขายและประมูลข้ามเซิร์ฟเวอร์ - เปิดให้มีการซื้อขายทั่วถึงระหว่างเซิร์ฟเวอร์ที่แตกต่างกัน ซึ่งผู้สามารถเสนอราคาสำหรับสินค้าในราคาที่เปลี่ยนแปลงแบบเรียลไทม์ ด้วย sorted map ของคู่กุญแจ-ค่า
- กระดานผู้นำทั่วโลก - เก็บและอัปเดตอันดับผู้ใช้ในกระดานผู้นำที่แชร์กันภายใน sorted map
- สินค้าคงคลังที่แชร์กัน - เก็บสินค้าและสถิติใน hash map ที่แชร์กัน ซึ่งผู้ใช้สามารถใช้สินค้าในคลังพร้อมกัน
- แคชสำหรับข้อมูลถาวร - ซิงค์และคัดลอกข้อมูลถาวรของคุณใน data store ไปยัง hash map ในหน่วยความจำที่สามารถทำหน้าที่เป็นแคชและปรับปรุงประสิทธิภาพของเกมของคุณ
โดยทั่วไป หากคุณต้องเข้าถึงข้อมูลตามคีย์เฉพาะ ให้ใช้ hash map หากคุณต้องการให้ข้อมูลนั้นถูกจัดเรียงให้ใช้ sorted map หากคุณต้องการประมวลผลข้อมูลของคุณในลำดับเฉพาะให้ใช้ queue.
ขีดจำกัดและโควตา
เพื่อรักษาความสามารถในการขยายและประสิทธิภาพของระบบ ระบบจัดเก็บข้อมูลหน่วยความจำมีโควตาการใช้งานข้อมูลสำหรับขนาดหน่วยความจำ, คำขอ API และขนาดของโครงสร้างข้อมูล
ระบบจัดเก็บข้อมูลหน่วยความจำมีนโยบายการไล่ล based on expiration time ที่เรียกว่ายังมีชื่อว่า time to live (TTL). รายการต่างๆ จะถูกไล่หลังจากที่หมดอายุ และโควตาหน่วยความจำจะถูกปล่อยสำหรับการเข้ารายการใหม่ เมื่อคุณถึงขีดจำกัดหน่วยความจำ คำขอที่เขียนทั้งหมดที่ตามมาจะล้มเหลวจนกว่ารายการจะหมดอายุหรือลบด้วยตนเอง
โควตาขนาดหน่วยความจำ
โควตาขนาดหน่วยความจำจำกัดจำนวนหน่วยความจำรวมที่เกมสามารถใช้ได้ มันไม่ใช่ค่าคงที่ แทนที่จะเป็นแบบเปลี่ยนแปลงตามจำนวนผู้ใช้ในเกมตามสูตร 64KB + 1.2KB * [number of users]. โควตานี้ใช้ในระดับเกมแทนที่จะเป็นระดับเซิร์ฟเวอร์.
เมื่อผู้ใช้เข้าร่วมเกม โควตาหน่วยความจำเพิ่มเติมพร้อมใช้งานทันที เมื่อผู้ใช้ออกจากเกม โควตาไม่ลดลงทันที มีการสิ้นสุดระยะเวลาเป็นเวลาสามสิบวันก่อนที่โควตาจะประเมินใหม่ให้ต่ำกว่า
หลังจากเกมของคุณถึงขีดจำกัดขนาดหน่วยความจำ คำขอ API ใดๆ ที่เพิ่มขนาดหน่วยความจำจะล้มเหลวเสมอ คำขอที่ลดหรือไม่เปลี่ยนขนาดหน่วยความจำยังคงสำเร็จ
ด้วยแดชบอร์ด observability คุณสามารถดูโควตาขนาดหน่วยความจำของเกมในเวลาจริงโดยใช้กราฟ Memory Usage.
ขีดจำกัดคำขอ API
โควตาหน่วย request unit จะใช้กับการเรียก API ของ MemoryStoreService ทั้งหมด โควตานี้คือ 1000 + 120 * [number of concurrent users] หน่วยคำขอ ต่อหนึ่งนาที.
การเรียก API ส่วนใหญ่จะใช้เพียงหน่วยคำขอหนึ่งหน่วย โดยมีข้อยกเว้นบางประการ:
MemoryStoreSortedMap:GetRangeAsync()
ใช้หน่วยตามจำนวนรายการที่ส่งคืน ตัวอย่างเช่น หากวิธีนี้ส่งคืน 10 รายการ การเรียกจะนับเป็น 10 หน่วยคำขอ หากส่งคืนการตอบสนองว่าง ก็จะนับเป็นหนึ่งหน่วยคำขอ.
ใช้หน่วยตามจำนวนรายการที่ส่งคืน เช่นเดียวกับ MemoryStoreSortedMap:GetRangeAsync() แต่ใช้หน่วยเพิ่มเติมทุกๆ สองวินาทีในขณะที่อ่าน กำหนดระยะเวลาในการอ่านสูงสุดด้วยพารามิเตอร์ waitTimeout.
MemoryStoreHashMap:UpdateAsync()
ใช้หน่วยขั้นต่ำสองหน่วย.
MemoryStoreHashMap:ListItemsAsync()
ใช้ [number of partitions scanned] + [items returned] หน่วย.
โควตาคำขอจะถูกนำไปใช้ในระดับเกมแทนที่จะเป็นระดับเซิร์ฟเวอร์ ซึ่งทำให้มีความยืดหยุ่นในการจัดสรรคำขอระหว่างเซิร์ฟเวอร์ต่างๆ ตราบใดที่อัตราคำขอรวมไม่เกินขีดจำกัด หากคุณเกินโควตา คุณจะได้รับการตอบกลับข้อผิดพลาดเมื่อบริการปรับลดคำขอของคุณ.
ด้วยฟีเจอร์ observability ที่มีอยู่ คุณสามารถดูโควตาหน่วยคำขอของเกมในเวลาจริง.
ขีดจำกัดขนาดโครงสร้างข้อมูล
สำหรับ sorted map หรือ queue หนึ่งตัว จะมีขีดจำกัดขนาดและจำนวนรายการดังนี้:
- จำนวนรายการสูงสุด: 1,000,000
- ขนาดรวมสูงสุด (รวมถึงคีย์สำหรับ sorted map): 100 MB
ขีดจำกัดต่อพาร์ติชัน
แนวทางปฏิบัติที่ดีที่สุด
เพื่อรักษาแบบอย่างการใช้งานหน่วยความจำของคุณให้เหมาะสมและหลีกเลี่ยงการถึง limits ให้ทำตามแนวทางปฏิบัติที่ดีที่สุดต่อไปนี้:
ลบรายการที่ประมวลผลแล้ว การทำความสะอาดรายการที่อ่านอยู่เสมอโดยใช้วิธี MemoryStoreQueue:RemoveAsync() สำหรับคิวและ MemoryStoreSortedMap:RemoveAsync() สำหรับ sorted maps จะช่วยปล่อยหน่วยความจำและรักษาโครงสร้างข้อมูลให้อัปเดตอยู่เสมอ
กำหนดเวลาในวันหมดอายุให้น้อยที่สุดเมื่อเพิ่มข้อมูล แม้ว่าเวลาในวันหมดอายุมาตรฐานจะอยู่ที่ 45 วันสำหรับทั้ง MemoryStoreQueue:AddAsync() และ MemoryStoreSortedMap:SetAsync() แต่การตั้งค่าให้มีระยะเวลาสั้นที่สุดจะช่วยทำความสะอาดข้อมูลเก่าโดยอัตโนมัติเพื่อป้องกันไม่ให้เติมโควตาการใช้งานหน่วยความจำของคุณ
- หลีกเลี่ยงการจัดเก็บข้อมูลจำนวนมากที่มีวันหมดอายุยาว เนื่องจากอาจทำให้เกินโควตาหน่วยความจำและอาจทำให้เกิดปัญหาที่อาจทำให้เกมของคุณเสียหาย
- ควรกำจัดรายการที่ไม่จำเป็นหรือกำหนดวันหมดอายุรายการให้สั้นอยู่เสมอ
- โดยทั่วไป ควรใช้การลบที่ชัดเจนเพื่อปล่อยหน่วยความจำ และวันหมดอายุของรายการเป็นกลไกความปลอดภัยเพื่อป้องกันไม่ให้รายการที่ไม่ได้ใช้งานใช้หน่วยความจำเป็นระยะเวลานาน
เก็บค่าที่จำเป็นเท่านั้นในหน่วยความจำ.
ตัวอย่างเช่น สำหรับเกมบ้านประมูล คุณจำเป็นต้องรักษาเพียงราคาประมูลสูงสุด คุณสามารถใช้ MemoryStoreSortedMap:UpdateAsync() บนคีย์หนึ่งเพื่อให้เก็บราคาประมูลสูงสุดแทนที่จะเก็บราคาทั้งหมดในโครงสร้างข้อมูลของคุณ.
ใช้ exponential backoff เพื่อช่วยให้ต่ำกว่าขีดจำกัดคำขอ API
ตัวอย่างเช่น หากคุณได้รับ DataUpdateConflict คุณอาจลองอีกครั้งหลังจากสองวินาที แล้วสี่ วินาที แปด วินาที เป็นต้น แทนการส่งคำขอไปยัง MemoryStoreService อย่างต่อเนื่องเพื่อให้ได้รับการตอบกลับที่ถูกต้อง
แบ่งโครงสร้างข้อมูลขนาดใหญ่เป็นโครงสร้างขนาดเล็กหลายๆ ตัวโดยการ sharding.
มักจะจัดการข้อมูลให้ยากขึ้นในโครงสร้างขนาดเล็กกว่าการเก็บทุกอย่างในโครงสร้างข้อมูลขนาดใหญ่หนึ่งตัว แนวทางนี้ช่วยหลีกเลี่ยงการใช้งานและขีดจำกัดของอัตราได้เช่นกัน ตัวอย่างเช่น หากคุณมี sorted map ที่ใช้คีย์พร็อกซี ลองแยกแต่ละพร็อกซีออกไปเป็น sorted map ของตัวเอง สำหรับเกมที่มีความนิยมสูงอาจแยกผู้ใช้ไปเป็นหลายๆ แผนที่ตามตัวเลขตัวสุดท้ายของ ID ของผู้ใช้ของพวกเขา
Shard คีย์ที่เข้าถึงบ่อยใน hash map ด้วยสำเนาหลายๆ คีย์เพื่อกระจายโหลด
บีบอัดค่าที่เก็บไว้.
ตัวอย่างเช่น ลองพิจารณาใช้ LZW อัลกอริธึมเพื่อลดขนาดของค่าที่เก็บไว้
ลงทะเบียนในบริการขยาย
คุณสามารถเพิ่มโควตาการเก็บข้อมูลและคำขอได้โดยการเข้าร่วม Extended Services
การมองเห็น
แดชบอร์ดการมองเห็น ให้ข้อมูลเชิงลึกและการวิเคราะห์สำหรับการติดตามและการระบุปัญหาในการใช้งาน Memory Store ของคุณ ด้วยกราฟที่อัปเดตในเวลาจริงเกี่ยวกับแง่มุมต่างๆ ของการใช้งานหน่วยความจำและคำขอ API คุณสามารถติดตามรูปแบบการใช้งานหน่วยความจำของเกมของคุณ ดูโควตาที่จัดสรรในปัจจุบัน ติดตามสถานะ API และระบุปัญหาที่มีศักยภาพสำหรับการปรับปรุงประสิทธิภาพ
ตารางต่อไปนี้แสดงและอธิบายรหัสสถานะทั้งหมดของ API responses ที่มีอยู่บนกราฟ Request Count by Status และ Requests by API x Status ของแดชบอร์ดการมองเห็น สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการแก้ไขข้อผิดพลาดเหล่านี้ ดูที่ Troubleshooting สำหรับโควตาหรือขีดจำกัดเฉพาะที่เกี่ยวข้องกับข้อผิดพลาดนั้น ให้ดูที่ Limits and Quotas.
| รหัสสถานะ | คำอธิบาย |
|---|---|
| Success | สำเร็จ. |
| 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 | ไม่สามารถเรียกใช้ฟังก์ชัน callback ของการแปลงได้. |
| RequestThrottled | คำขอ MemoryStores ล่าสุดถึงขีดจำกัดหนึ่งหรือหลายที่. |
| UpdateConflict | เกินจำนวนความพยายามที่สูงสุด. |
การแก้ไขปัญหา
ตารางต่อไปนี้แสดงรหัสสถานะตอบกลับและอธิบายแนวทางแก้ไขที่แนะนำ
| ข้อผิดพลาด | ทางเลือกสำหรับการแก้ปัญหา |
|---|---|
| DataStructureRequestsOverLimit / PartitionRequestsOverLimit |
|
| TotalRequestsOverLimit | |
| DataStructureItemsOverLimit |
|
| DataStructureMemoryOverLimit | |
| TotalMemoryOverLimit | |
| DataUpdateConflict |
|
| Internal Error |
|
| InvalidRequest |
|
| ItemValueSizeTooLarge |
|
ทดสอบและดีบั๊กใน Studio
ข้อมูลใน MemoryStoreService จะแยกออกจากกันระหว่าง Studio และการผลิต ดังนั้นการเปลี่ยนแปลงข้อมูลใน Studio จะไม่ส่งผลต่อพฤติกรรมการผลิต นี่หมายความว่าการเรียก API ของคุณจาก Studio จะไม่เข้าถึงข้อมูลการผลิต ช่วยให้คุณสามารถทดสอบ Memory Store และฟีเจอร์ใหม่อย่างปลอดภัยก่อนการผลิต
การทดสอบใน Studio มี limits and quotas เช่นเดียวกับการผลิต สำหรับโควตาที่คำนวณจากจำนวนผู้ใช้ ได้รับผลเป็นโควตาที่เล็กมาก เนื่องจากคุณเป็นผู้ใช้เพียงคนเดียวในการทดสอบใน Studio เมื่อทำการทดสอบจาก Studio คุณอาจพบความหน่วงที่สูงขึ้นเล็กน้อยและอัตราข้อผิดพลาดที่สูงขึ้นเมื่อเปรียบเทียบกับการใช้งานในการผลิต เนื่องจากมีการตรวจสอบเพิ่มเติมเพื่อยืนยันการเข้าถึงและสิทธิ์
สำหรับข้อมูลเกี่ยวกับวิธีการดีบั๊ก Memory Store ในเกมสดหรือเมื่อทำการทดสอบใน Studio ใช้ Developer Console.