Tốt nhất khi thiết kế cấu trúc dữ liệu MemoryStore

*Nội dung này được dịch bằng AI (Beta) và có thể có lỗi. Để xem trang này bằng tiếng Anh, hãy nhấp vào đây.

Tùy thuộc vào loại đánh máytrúc dữ liệu, MemoryStoreService thiết lập giới hạn cho bộ nhớ và số lượng vật phẩm trong cấu trúc dữ liệu.Tất cả các cấu trúc dữ liệu cũng bị giới hạn bởi giới hạn yêu cầu phân chia toàn cầu.

Mỗi trải nghiệm Roblox có Bảng Quan Sát Khả Năng Nhớ Memory Store Observability Dashboard, bao gồm một bộ các biểu đồ mà bạn có thể sử dụng để theo dõi sử dụng kho nhớ.

Bản đồ và hàng đợi được sắp xếp

Cả bản đồ và hàng đợi được sắp xếp đều có giới hạn về số lượng tối đa của vật phẩm và tổng bộ nhớ tối đa.Ngoài ra, các mục trong một trong những cấu trúc dữ liệu này luôn nằm trên một phân vùng duy nhất.Mỗi yêu cầu đến một trong những cấu trúc dữ liệu đó là một yêu cầu đến cùng một phân vùng.

Khi một bản đồ hoặc hàng đợi được sắp xếp đạt đến giới hạn vật phẩm hoặc bộ nhớ, hành động tốt nhất là loại bỏ các vật phẩm không cần thiết bằng cách thủ công hoặc bằng cách thêm chính sách hết hạn cho các vật phẩm.Ngoài ra, nếu chỉ giới hạn bộ nhớ gây giảm tốc độ, bạn có thể cố gắng giảm kích thước của các mục của bạn bằng cách loại bỏ thông tin không cần thiết khỏi chìa khóa và giá trị của bạn.

Nếu bạn cần tất cả các mục của mình hoặc đang gặp phải giới hạn do lưu lượng yêu cầu, giải pháp duy nhất là phân mảnh.

Phân mảnh

Phân mảnh là quá trình lưu trữ một bộ dữ liệu liên quan trên nhiều cấu trúc dữ liệu.Nói cách khác, nó có nghĩa là lấy một cấu trúc dữ liệu hiện có, có tốc độ cao và thay thế nó bằng nhiều cấu trúc dữ liệu nhỏ hơn, chứa cùng một bộ dữ liệu như ban đầu.

Thử thách chính của việc phân mảnh là tìm cách để phân phối dữ liệu trên nhiều cấu trúc dữ liệu theo cách duy trì chức năng tương tự như ban đầu.

Phân mảnh một bản đồ được sắp xếp

Để phân mảnh một bản đồ được sắp xếp, hãy xem xét chia dữ liệu thành các phần phân loại theo chữ cái với phạm vi ký tự.Ví dụ, cho rằng bạn chỉ có chìa khóa với chữ cái đầu tiên từ A-Z, và bạn tin rằng bốn bản đồ được sắp xếp là đủ cho trường hợp sử dụng hiện tại và tăng trưởng trong tương lai:

  • Bản đồ đầu tiên có thể bao phủ A-G, bản thứ hai H-N, bản thứ ba O-T, và bản thứ tư U-Z.
  • Để chèn hoặc lấy lại một vật phẩm, sử dụng bản đồ thích hợp dựa trên nhân vật khởi động của vật phẩm.
Phân mảnh một bản đồ được sắp xếp

-- Khởi tạo dịch vụ MemoryStore
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Tạo các thùng bản đồ sắp xếp của bạn
local sm_AtoG = MemoryStoreService:GetSortedMap("AtoG")
local sm_HtoM = MemoryStoreService:GetSortedMap("HtoM")
local sm_NtoT = MemoryStoreService:GetSortedMap("NtoT")
local sm_UtoZ = MemoryStoreService:GetSortedMap("UtoZ")
-- Chức năng trợ giúp để lấy lại chiếc xô đúng từ Chìa khóa Vật phẩm
local function getSortedMapBucket(itemKey)
if (itemKey >= "a" and itemKey < "h") then
return sm_AtoG
elseif (itemKey < "n") then
return sm_HtoM
elseif (itemKey < "u") then
return sm_NtoT
else
return sm_UtoZ
end
end
-- Khởi tạo tên người chơi với giá trị mặc định là 0
for _, player in game:GetService("Players"):GetPlayers() do
local bucket = getSortedMapBucket(player)
bucket:SetAsync(player, 0, 600)
end
-- Lấy giá trị của một người chơi
local player = "myPlayer"
local bucket = getSortedMapBucket(player)
local playerScore = bucket:GetAsync(player)
print(playerScore)

Phân mảnh một hàng chờ

Phân mảnh một hàng đợi là khó khăn hơn phân mảnh một bản đồ được sắp xếp.Mặc dù bạn muốn phân phối lưu lượng yêu cầu qua nhiều hàng đợi, thêm, đọc và xóa chỉ xảy ra ở phía trước hoặc phía sau hàng đợi.

Một giải pháp là sử dụng hàng đợi xoay vòng, có nghĩa là tạo nhiều hàng đợi và xoay giữa chúng khi bạn thêm hoặc đọc một vật phẩm:

  1. Tạo một số hàng đợi và thêm chúng vào một array.

  2. Tạo hai điểm địa phương. Một đại diện cho hàng đợi bạn muốn đọc và xóa các mục. Cái kia đại diện cho hàng đợi bạn muốn thêm các mục:

    • Đối với các hoạt động đọc, tính số lượng vật phẩm bạn cần từ mỗi hàng đợi, cũng như nơi để di chuyển điểm đọc đến.
    • Đối với các hoạt động xóa, chuyển ID từ đọc sang mỗi hàng đợi.
    • Đối với các thao tác thêm, thêm vào hàng đợi tại điểm thêm và tăng điểm chỉ.
Phân mảnh một hàng chờ

-- Khởi tạo dịch vụ MemoryStore
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Tạo hàng đợi của bạn
local q1 = MemoryStoreService:GetQueue("q1")
local q2 = MemoryStoreService:GetQueue("q2")
local q3 = MemoryStoreService:GetQueue("q3")
local q4 = MemoryStoreService:GetQueue("q4")
-- Đặt hàng chờ vào một array
local queueArr = { q1, q2, q3, q4 }
-- Tạo hai điểm chỉ ra các chỉ mục của việc đọc và thêm hàng đợi
local readIndex = 1
local addIndex = 1
-- Tạo một chức năng địa phương cập nhật các chỉ mục thích hợp
local function rotateIndex(index, n)
return (index + n - 1) % 4 + 1
end
-- Tạo một chức năng địa phương đọc n items từ hàng đợi
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- vòng lặp qua mỗi hàng đợi
for i = 1, 4, 1 do
-- xác định xem hàng đợi này có đọc thêm một vật phẩmkhông
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- đọc các mục từ mỗi hàng đợi
-- +1 vật phẩm nếu phù hợp với tiêu chí đọc bổ sung
if diff < endIndex then
items[i], ids[i] = queue:ReadAsync(countPerQueue + 1, allOrNothing,waitTimeout)
else
items[i], ids[i] = queue:ReadAsync(countPerQueue, allOrNothing,waitTimeout)
end
end
readIndex = rotateIndex(readIndex, count)
return items, ids
end
-- Tạo một chức năng địa phương xóa n vật phẩm khỏi hàng đợi
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[readIndex]
queue:RemoveAsync(ids[i])
end
end
-- Tạo một chức năng địa phương thêm một mục vào hàng chờ
local function addToQueue(itemKey, expiration, priority)
local queue = queueArr[readIndex]
queue:AddAsync(itemKey, expiration, priority)
addIndex = rotateIndex(addIndex, 1)
end
-- Viết một số mã!
for _, player in game:GetService("Players"):GetPlayers() do
addToQueue(player, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)

Bản đồ hash

Bản đồ hash không có giới hạn bộ nhớ hoặc số lượng mục riêng lẻ và sẽ bị phân mảnh tự động, nhưng bạn vẫn có thể gặp tắc nghẽn nếu sử dụng chúng kém hiệu quả.

Ví dụ, hãy xem xét một trải nghiệm với bản đồ hash của dữ liệu trò chơi, được lưu dưới dạng giá trị của một chìa khóa duy nhất có tên là metadata .Nếu dữ liệu này chứa một đối tượng lồng với thông tin như ID địa điểm, số lượng người chơi và nhiều hơn nữa, mỗi khi cần dữ liệu, bạn không có lựa chọn nào khác ngoài việc gọi GetAsync("metadata") và lấy lại toàn bộ đối tượng.Trong trường hợp này, tất cả các yêu cầu đi đến một chìa khóa duy nhất và do đó một phân vùng duy nhất.

Thay vì lưu tất cả các métadữ liệu như một đối tượng duy nhất, xếp chồng, tốt hơn là lưu mỗi trường như là chìa khóa của riêng nó để bản đồ hash có thể tận dụng tự động phân mảnh.Nếu bạn cần phân biệt giữa metadata và phần còn lại của bản đồ hash, hãy thêm một tiền tố đặt tên (ví dụmetadata_user_count thay vì chỉ user_count ).