데이터 구조 입력따라 MemoryStoreService는 메모리와 데이터 구조의 항목 수에 제한을 적용합니다.모든 데이터 구조도 전체 파티션 요청 제한으로 제한됩니다.
각 Roblox 경험에는 메모리 저장소 가시성 대시보드가 있으며, 메모리 저장소 사용을 모니터링하는 데 사용할 수 있는 차트 세트가 포함되어 있습니다.
정렬된 맵과 큐
정렬된 맵과 큐 모두 최대 아이템 수와 최대 총 메모리에 제한이 있습니다.또한 이러한 데이터 구조 중 하나의 항목은 항상 단일 파티션에 있습니다.해당 데이터 구조 중 하나에 대한 모든 요청은 동일한 파티션에 대한 요청입니다.
정렬된 맵이나 큐가 항목이나 메모리 한도에 도달하면 불필요한 항목을 수동으로 제거하거나 항목에 만료 정책을 추가하여 행동할 수 있는 최선의 방법입니다.또는 메모리 제한만 스로틀링을 일으키는 경우 키와 값에서 불필요한 정보를 제거하여 아이템 크기를 줄이려고 시도할 수 있습니다.
모든 아이템이 필요하거나 요청 처리량으로 인해 병목이 발생하는 경우 유일한 해결책은 분할입니다.
분할
분할은 여러 데이터 구조에 걸쳐 관련 데이터 세트를 저장하는 프로세스입니다.즉, 기존의 고성능 데이터 구조를 가져와 원래와 동일한 데이터 집합을 포함하는 여러 작은 구조로 교체하는 것을 의미합니다.
샤딩의 주요 도전은 원래와 동일한 기능을 유지하면서 여러 데이터 구조에 데이터를 분산하는 방법을 찾는 것입니다.
정렬된 맵 분할
정렬된 맵을 분할하려면 문자 범위가 있는 알파벳순 하위 세그먼트로 데이터를 분할하십시오.예를 들어, A-Z의 첫 번째 문자만 키가 있고 4개의 정렬된 맵이 현재 사용 사례와 미래의 성장에 충분하다고 생각하면:
- 첫 번째 맵은 A-G, 두 번째 H-N, 세 번째 O-T, 네 번째 U-Z를 커버할 수 있습니다.
- 아이템삽입하거나 검색하려면 아이템시작 문자에 따라 적절한 맵을 사용하십시오.
정렬된 맵 분할
-- 메모리 저장소 서비스 초기화
local MemoryStoreService = game:GetService("MemoryStoreService")
-- 정렬된 맵 버킷 만들기
local sm_AtoG = MemoryStoreService:GetSortedMap("AtoG")
local sm_HtoM = MemoryStoreService:GetSortedMap("HtoM")
local sm_NtoT = MemoryStoreService:GetSortedMap("NtoT")
local sm_UtoZ = MemoryStoreService:GetSortedMap("UtoZ")
-- 아이템 키에서 올바른 버킷을 검색하는 도우미 함수
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
-- 플레이어 이름을 기본값인 0으로 초기화
for _, player in game:GetService("Players"):GetPlayers() do
local bucket = getSortedMapBucket(player)
bucket:SetAsync(player, 0, 600)
end
-- 플레이어의 값 검색
local player = "myPlayer"
local bucket = getSortedMapBucket(player)
local playerScore = bucket:GetAsync(player)
print(playerScore)
큐 분할
큐를 분할하는 것은 정렬된 맵을 분할하는 것보다 까다롭습니다.여러 큐에서 요청 처리량을 분산하려고 하더라도, 추가, 읽기 및 제거는 큐의 앞이나 뒤에만 발생합니다.
하나의 솔루션은 회전 큐를 사용하는 것으로, 즉 아이템추가하거나 읽을 때 여러 큐를 생성하고 서로 회전하는 것을 의미합니다.
여러 큐를 만들고 배열에 추가합니다.
두 개의 로컬 포인터를 만듭니다. 하나는 읽고 제거하려는 큐를 나타내며, 다른 하나는 항목을 추가하려는 큐를 나타냅니다.
- 읽기 작업의 경우 각 큐에서 필요한 항목 수와 읽기 포인터를 이동할 위치를 계산합니다.
- 제거 작업의 경우 읽기에서 각 큐에 ID를 전달합니다.
- 작업 추가를 위해 추가 포인터에서 큐에 추가하고 포인터를 증가시킵니다.
큐 분할
-- 메모리 저장소 서비스 초기화
local MemoryStoreService = game:GetService("MemoryStoreService")
-- 큐 생성
local q1 = MemoryStoreService:GetQueue("q1")
local q2 = MemoryStoreService:GetQueue("q2")
local q3 = MemoryStoreService:GetQueue("q3")
local q4 = MemoryStoreService:GetQueue("q4")
-- 큐를 배열에 넣기
local queueArr = { q1, q2, q3, q4 }
-- 읽기와 추가 큐의 인덱스를 나타내는 두 포인터 생성
local readIndex = 1
local addIndex = 1
-- 적절하게 업데이트되는 지수를 업데이트하는 로컬 함수 만들기
local function rotateIndex(index, n)
return (index + n - 1) % 4 + 1
end
-- 큐에서 n개의 항목을 읽는 로컬 함수 만들기
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- 각 큐에서 루프 통과
for i = 1, 4, 1 do
-- 이 큐가 추가 아이템읽을지 여부 결정
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- 각 큐에서 아이템 읽기
-- 추가 읽기 조건에 일치하는 경우 +1 항목
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
-- 큐에서 n개의 항목을 제거하는 로컬 함수를 만듭니다
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[readIndex]
queue:RemoveAsync(ids[i])
end
end
-- 큐에 항목을 추가하는 로컬 함수 만들기
local function addToQueue(itemKey, expiration, priority)
local queue = queueArr[readIndex]
queue:AddAsync(itemKey, expiration, priority)
addIndex = rotateIndex(addIndex, 1)
end
-- 코드를 작성하세요!
for _, player in game:GetService("Players"):GetPlayers() do
addToQueue(player, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)
해시 맵
해시 맵에는 개별 메모리 또는 항목 수 제한이 없으며 자동으로 분할되지만, 잘못 사용하면 속도 저하가 발생할 수 있습니다.
예를 들어, 게임 데이터의 해시맵으로 저장된 단일 키의 값인 metadata의 경험을 고려하십시오.이 메타데이터에 장소 ID, 플레이어 수 등의 정보가 포함된 중첩 개체가 있는 경우, 메타데이터가 필요할 때마다 GetAsync("metadata")하고 전체 개체를 검색할 수밖에 없습니다.이 경우 모든 요청이 단일 키로 이동하고 따라서 단일 파티션으로 이동합니다.
모든 메타데이터를 단일 중첩 개체로 저장하는 대신, 해시 맵이 자동 분할을 활용할 수 있도록 각 필드를 자체 키로 저장하는 것이 더 좋습니다.메타데이터와 해시 맵의 나머지 부분 사이에 분리가 필요한 경우 이름 접두사를 추가하십시오(예:metadata_user_count 대신 단순히 user_count).