Tergantung pada jenis struktur data, MemoryStoreService menegakkan batasan pada memori dan jumlah item dalam struktur data. Semua struktur data juga dibatasi oleh batas permintaan global per-partisi.
Setiap game Roblox memiliki Dasbor Observabilitas Memory Store, yang mencakup serangkaian grafik yang dapat Anda gunakan untuk memantau penggunaan penyimpanan memori.
Peta terurut dan antrean
Peta terurut dan antrean sama-sama memiliki batasan pada jumlah maksimum item dan total memori maksimum. Selain itu, item dalam salah satu struktur data ini selalu berada di satu partisi. Setiap permintaan ke salah satu struktur data tersebut merupakan permintaan ke partisi yang sama.
Ketika peta terurut atau antrean mencapai batas item atau memori, langkah terbaik adalah menghapus item yang tidak perlu secara manual atau dengan menambahkan kebijakan kedaluwarsa untuk item tersebut. Sebagai alternatif, jika hanya batas memori yang menyebabkan throttling, Anda dapat mencoba mengurangi ukuran item Anda dengan menghapus informasi yang tidak perlu dari kunci dan nilai Anda.
Jika Anda membutuhkan semua item Anda atau mengalami throttling karena throughput permintaan, satu-satunya solusi adalah sharding.
Sharding
Sharding adalah proses menyimpan serangkaian data terkait di berbagai struktur data. Dengan kata lain, ini berarti mengambil struktur data yang ada dengan throughput tinggi dan menggantinya dengan beberapa struktur yang lebih kecil yang bersama-sama mengandung set data yang sama dengan yang asli.
Tantangan utama sharding adalah menemukan cara untuk menyebarkan data di seluruh struktur data yang berbeda dengan cara yang mempertahankan fungsi yang sama seperti yang asli.
Untuk peta hash, meskipun struktur datanya sudah terpartisi, sharding dilakukan dengan menyebarkan permintaan di antara beberapa kunci.
Sharding peta terurut
Untuk membagi peta terurut, pertimbangkan untuk membagi data Anda menjadi subbagian alfabet dengan rentang karakter. Misalnya, anggaplah Anda hanya memiliki kunci dengan huruf pertama dari A-Z, dan Anda percaya bahwa empat peta terurut sudah cukup untuk kasus penggunaan saat ini dan pertumbuhan di masa mendatang:
- Peta pertama dapat mencakup A-G, yang kedua H-N, yang ketiga O-T, dan yang keempat U-Z.
- Untuk menyisipkan atau mengambil item, gunakan peta yang sesuai berdasarkan karakter awal item.
Sharding Peta Terurut
-- Inisialisasi Layanan MemoryStore
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Buat ember Peta Terurut Anda
local sm_AtoG = MemoryStoreService:GetSortedMap("AtoG")
local sm_HtoM = MemoryStoreService:GetSortedMap("HtoM")
local sm_NtoT = MemoryStoreService:GetSortedMap("NtoT")
local sm_UtoZ = MemoryStoreService:GetSortedMap("UtoZ")
-- Fungsi pembantu untuk mengambil ember yang benar dari Kunci Item
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
-- Inisialisasi nama pemain dengan nilai default 0
for _, player in game:GetService("Players"):GetPlayers() do
local bucket = getSortedMapBucket(player)
bucket:SetAsync(player, 0, 600)
end
-- Ambil nilai pemain
local player = "myPlayer"
local bucket = getSortedMapBucket(player)
local playerScore = bucket:GetAsync(player)
print(playerScore)
Sharding antrean
Sharding antrean lebih rumit daripada sharding peta terurut. Meskipun Anda ingin menyebarkan throughput permintaan di berbagai antrean, penambahan, pembacaan, dan penghapusan hanya pernah terjadi di depan atau belakang antrean.
Salah satu solusinya adalah menggunakan antrean yang berputar, yang berarti membuat beberapa antrean dan berotasi di antara mereka saat Anda menambahkan atau membaca item:
Buat beberapa antrean dan tambahkan ke dalam array.
Buat dua pointer lokal. Satu mewakili antrean yang ingin Anda baca dan hapus item. Yang lainnya mewakili antrean yang ingin Anda tambahkan item:
- Untuk operasi baca, hitung jumlah item yang Anda butuhkan dari setiap antrean, serta di mana untuk memindahkan pointer baca.
- Untuk operasi hapus, kirim ID dari bacaan ke setiap antrean.
- Untuk operasi tambah, tambahkan ke antrean pada pointer tambahkan dan tingkatkan pointer tersebut.
Sharding Antrean
-- Inisialisasi Layanan MemoryStore
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Buat Antrean Anda
local q1 = MemoryStoreService:GetQueue("q1")
local q2 = MemoryStoreService:GetQueue("q2")
local q3 = MemoryStoreService:GetQueue("q3")
local q4 = MemoryStoreService:GetQueue("q4")
-- Tempatkan Antrean dalam Array
local queueArr = { q1, q2, q3, q4 }
-- Buat dua pointer yang mewakili indeks antrean baca dan tambahkan
local readIndex = 1
local addIndex = 1
-- Buat fungsi lokal yang memperbarui indeks dengan benar
local function rotateIndex(index, n)
return (index + n - 1) % 4 + 1
end
-- Buat fungsi lokal yang membaca n item dari antrean
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- looping melalui setiap antrean
for i = 1, 4, 1 do
-- tentukan apakah antrean ini akan membaca item tambahan
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- baca item dari setiap antrean
-- +1 item jika memenuhi kriteria baca tambahan
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
-- Buat fungsi lokal yang menghapus n item dari antrean
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[readIndex]
queue:RemoveAsync(ids[i])
end
end
-- Buat fungsi lokal yang menambahkan item ke antrean
local function addToQueue(itemKey, expiration, priority)
local queue = queueArr[readIndex]
queue:AddAsync(itemKey, expiration, priority)
addIndex = rotateIndex(addIndex, 1)
end
-- Tulis beberapa kode!
for _, player in game:GetService("Players"):GetPlayers() do
addToQueue(player, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)
Peta hash
Peta hash tidak memiliki batasan memori atau jumlah item individu dan secara otomatis dibagi, tetapi Anda masih dapat menghadapi throttling jika menggunakannya dengan buruk.
Sebagai contoh, anggaplah sebuah game dengan peta hash data, disimpan sebagai nilai dari satu kunci yang bernama metadata. Jika metadata ini berisi objek bersarang dengan informasi seperti ID tempat, jumlah pemain, dan lainnya, setiap kali metadata dibutuhkan, Anda tidak punya pilihan selain memanggil GetAsync("metadata") dan mengambil seluruh objek. Dalam kasus ini, semua permintaan pergi ke satu kunci dan karena itu ke satu partisi.
Alih-alih menyimpan semua metadata sebagai satu objek bersarang, pendekatan yang lebih baik adalah menyimpan setiap field sebagai kuncinya sendiri sehingga peta hash dapat memanfaatkan sharding otomatis. Jika Anda perlu memisahkan antara metadata dan sisa peta hash, tambahkan awalan penamaan (misalnya metadata_user_count daripada hanya user_count).
Selain itu, jika satu atau beberapa kunci diakses secara sering, penting untuk membagi panggilan ini di antara banyak kunci. Misalnya, jika semua server game harus mengambil nilai dari satu kunci peta hash, Anda dapat mengalami throttling partisi. Untuk mencegah ini, Anda dapat menyebarkan panggilan tersebut di antara beberapa kunci dengan nilai yang sama sampai throttling partisi tidak lagi terjadi.