데이터 저장소에 대한 요청은 연결 문제가 있거나 기타 문제로 인해 실패할 수 있습니다. 오류를 처리하고 오류 코드와 함께 메시지를 반환하려면 데이터 저장소 기능을 pcall()로 감싸야 합니다.
UpdateAsync()와 같은 실패한 쓰기 호출은 게임 서버가 성공적인 응답을 받지 못했음을 의미합니다. 백엔드 쓰기가 발생하지 않았음을 보장하지는 않습니다. 일부 실패 시나리오에서는 호출자가 캐시 없이 후속 읽기로 확인할 때까지 최종 쓰기 상태를 알 수 없을 수 있습니다.
오류 코드 참조
| 오류 코드 | 오류 이름 | 오류 메시지 | 메모 | |
|---|---|---|---|---|
| 101 | KeyNameEmpty | 키 이름은 비어 있을 수 없습니다. | 데이터 저장소 함수에 입력된 키가 빈 문자열인지 확인하세요. | |
| 102 | KeyNameLimit | 키 이름이 50자 제한을 초과했습니다. | 데이터 저장소 함수에 입력된 키가 50자 길이를 초과하는지 확인하세요. | |
| 103 | ValueNotAllowed | DataStore에서 X를 허용할 수 없습니다. | 잘못된 업데이트 함수가 X 유형의 값을 반환했습니다. | |
| 104 | CantStoreValue | DataStore에 X를 저장할 수 없습니다. | 업데이트 함수가 직렬화되지 않은 X 유형의 값을 반환했습니다. | |
| 105 | ValueTooLarge | 직렬화된 값이 X 제한을 초과했습니다. | SetAsync() 또는 UpdateAsync()를 사용하여 값을 설정하는 경우, 값의 직렬화된 길이가 X를 초과할 수 없습니다. 데이터의 직렬화된 길이를 확인하려면 JSONEncode()를 사용하세요. | |
| 106 | MaxValueInvalid | MaxValue는 정수여야 합니다. | GetSortedAsync()에 최대 값을 전달하는 경우, 이는 정수여야 합니다. | |
| 106 | MinValueInvalid | MinValue는 정수여야 합니다. | GetSortedAsync()에 최소 값을 전달하는 경우, 이는 정수여야 합니다. | |
| 106 | PageSizeGreater | PageSize는 사전 정의된 범위 내에 있어야 합니다. | OrderedDataStore의 최소 페이지 크기는 1입니다. | |
| 106 | PageSizeLesser | PageSize는 사전 정의된 범위 내에 있어야 합니다. | OrderedDataStore의 최대 페이지 크기는 100입니다. | |
| 107 | MinMaxOrderInvalid | MaxValue는 MinValue보다 크거나 같아야 합니다. | 최대 값은 GetSortedAsync()에 대한 최소 값보다 크거나 같아야 합니다. | |
| 301 | GetAsyncThrottle | GetAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았지만 대기열이 가득 차 있었습니다. | GetAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | |
| 302 | SetAsyncThrottle | SetAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았지만 대기열이 가득 차 있었습니다. | SetAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | |
| 303 | IncreAsyncThrottle | IncrementAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았지만 대기열이 가득 차 있었습니다. | IncrementAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | |
| 304 | UpdateAsyncThrottle | UpdateAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았지만 대기열이 가득 차 있었습니다. | UpdateAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | |
| 304 | TransformThrottle | UpdateAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았지만 대기열이 가득 차 있었습니다. | UpdateAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | |
| 305 | GetSortedThrottle | GetSorted 요청이 중단되었습니다. 요청이 속도 제한을 받았지만 대기열이 가득 차 있었습니다. | GetSortedAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | |
| 306 | RemoveAsyncThrottle | RemoveAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았지만 대기열이 가득 차 있었습니다. | RemoveAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | |
| 401 | DataModelNoAccess | 요청 실패. 경험이 종료되는 동안 DataModel에 접근할 수 없습니다. | DataModel이 초기화되지 않았습니다. 이는 경험이 종료되고 있어서입니다. | |
| 402 | LuaWebSrvsNoAccess | 요청 실패. 경험이 종료되는 동안 LuaWebService에 접근할 수 없습니다. | LuaWebService가 초기화되지 않았습니다. 이는 경험이 종료되고 있어서입니다. | |
| 403 | StudioAccessToApisNotAllowed | API 액세스가 활성화되지 않아 Studio에서 DataStore에 쓸 수 없습니다. | Studio에서 데이터 저장소를 사용하려면 API 액세스가 활성화되어야 합니다. | |
| 404 | InternalError | OrderedDataStore가 존재하지 않습니다. | 이 요청과 관련된 OrderedDataStore를 찾을 수 없습니다. 이는 데이터 손상의 징후일 수 있습니다. 나중에 다시 시도하세요. | |
| 501 | InternalError | 응답을 파싱할 수 없습니다. 데이터가 손상되었을 수 있습니다. | 서버가 요청에 대한 응답을 파싱할 수 없었습니다. 이는 데이터 손상의 징후일 수 있습니다. 나중에 다시 시도하세요. | |
| 502 | RequestRejected | API 서비스가 오류 X로 요청을 거부했습니다. | Roblox 서버에서 처리하는 동안 오류 X가 발생했습니다. 나중에 다시 시도하세요. | |
| 503 | InternalError | 데이터 저장소 요청은 성공적이었지만 키를 찾을 수 없습니다. | 요청한 키가 데이터 저장소에 없습니다. 이는 데이터 손상의 징후일 수 있습니다. 나중에 다시 시도하세요. | |
| 504 | InternalError | 데이터 저장소 요청은 성공적이었지만 응답이 올바르게 포맷되지 않았습니다. | 서버가 요청에 대한 응답을 파싱할 수 없었습니다. 이는 데이터 손상의 징후일 수 있습니다. 나중에 다시 시도하세요. | |
| 505 | InternalError | OrderedDataStore 요청은 성공적이었지만 응답이 올바르게 포맷되지 않았습니다. | 서버가 요청한 OrderedDataStore에 대한 응답을 파싱할 수 없었습니다. 이는 데이터 손상의 징후일 수 있습니다. 나중에 다시 시도하세요. | |
| 509 | OperationNotAllowed | 데이터 저장소 작업이 개인 RCC에서 실행되는 동안 차단되어 데이터 손상을 방지합니다. | 사설 RCC 채널에서 데이터 저장소 쓰기가 차단되었습니다. | |
| 511 | AttributeSizeTooLarge | 메타데이터 속성 크기가 X 제한을 초과했습니다. | 직렬화된 메타데이터 크기가 X의 제한을 초과합니다. 값 X는 동적입니다. 크기가 변경되면 값도 변경됩니다. | |
| 512 | UserIdLimitExceeded | UserID 크기가 X 제한을 초과했습니다. | 사용자가 제공한 사용자 ID 배열의 길이가 X의 제한을 초과했습니다. | |
| 513 | AttributeFormatError | 속성 userId 형식이 잘못되었습니다. | 제공된 사용자 ID가 숫자가 아닙니다. | |
| 513 | AttributeFormatError | 속성 메타데이터 형식이 잘못되었습니다. | 메타데이터가 테이블이 아닙니다. | |
| GetVersionAsyncThrottle | GetVersionAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았습니다. | GetVersionAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | ||
| GetVersionAtTimeAsyncThrottle | GetVersionAtTimeAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았습니다. | GetVersionAtTimeAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | ||
| ListDataStoresAsyncThrottle | ListDataStoresAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았습니다. | ListDataStoresAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | ||
| ListKeysAsyncThrottle | ListKeysAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았습니다. | ListKeysAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | ||
| ListVersionsAsyncThrottle | ListVersionsAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았습니다. | ListVersionsAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | ||
| RemoveVersionAsyncThrottle | RemoveVersionAsync 요청이 중단되었습니다. 요청이 속도 제한을 받았습니다. | RemoveVersionAsync() 요청이 최대 대기열 크기를 초과했으며 Roblox가 현재 처리량で 요청을 처리할 수 없습니다. | ||
| InvalidTimestamp | 타임스탬프는 양수여야 하며 미래의 10분을 초과할 수 없습니다. | GetVersionAtTimeAsync()에 제공된 타임스탬프가 유효하지 않았습니다. | ||
| StandardReadExperienceThrottled | StandardRead 요청이 경험 한계로 인해 제한되었습니다. | GetAsync(), GetVersionAsync(), GetVersionAtTimeAsync(), 또는 표준 데이터 저장소에서 UpdateAsync()의 읽기가 StandardRead 경험 수준 속도 제한을 초과했습니다. | ||
| StandardWriteExperienceThrottled | StandardWrite 요청이 경험 한계로 인해 제한되었습니다. | SetAsync(), IncrementAsync(), 또는 표준 데이터 저장소에서 UpdateAsync()의 쓰기가 StandardWrite 경험 수준 속도 제한을 초과했습니다. | ||
| StandardListExperienceThrottled | StandardList 요청이 경험 한계로 인해 제한되었습니다. | ListKeysAsync(), ListVersionsAsync(), 또는 표준 데이터 저장소에서 ListDataStoresAsync()의 요청이 StandardList 경험 수준 속도 제한을 초과했습니다. | ||
| StandardRemoveExperienceThrottled | StandardRemove 요청이 경험 한계로 인해 제한되었습니다. | RemoveAsync()의 표준 데이터 저장소에 대한 요청이 StandardRemove 경험 수준 속도 제한을 초과했습니다. | ||
| OrderedReadExperienceThrottled | OrderedRead 요청이 경험 한계로 인해 제한되었습니다. | GetAsync() 또는 정렬된 데이터 저장소에서 UpdateAsync()의 읽기가 OrderedRead 경험 수준 속도 제한을 초과했습니다. | ||
| OrderedWriteExperienceThrottled | OrderedWrite 요청이 경험 한계로 인해 제한되었습니다. | SetAsync(), IncrementAsync(), 또는 정렬된 데이터 저장소에서 UpdateAsync()의 쓰기가 OrderedWrite 경험 수준 속도 제한을 초과했습니다. | ||
| OrderedListExperienceThrottled | OrderedList 요청이 경험 한계로 인해 제한되었습니다. | GetSortedAsync()의 정렬된 데이터 저장소에 대한 요청이 OrderedList 경험 수준 속도 제한을 초과했습니다. | ||
| OrderedRemoveExperienceThrottled | OrderedRemove 요청이 경험 한계로 인해 제한되었습니다. | RemoveAsync()의 정렬된 데이터 저장소에 대한 요청이 OrderedRemove 경험 수준 속도 제한을 초과했습니다. | ||
| StandardReadGameServerThrottled | StandardRead 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | GetAsync(), GetVersionAsync(), GetVersionAtTimeAsync(), 또는 표준 데이터 저장소에서 UpdateAsync()의 읽기가 StandardRead 게임 서버 수준 속도 제한을 초과했습니다. | ||
| StandardWriteGameServerThrottled | StandardWrite 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | SetAsync(), IncrementAsync(), 또는 표준 데이터 저장소에서 UpdateAsync()의 쓰기가 StandardWrite 게임 서버 수준 속도 제한을 초과했습니다. | ||
| StandardListGameServerThrottled | StandardList 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | ListKeysAsync(), ListVersionsAsync(), 또는 표준 데이터 저장소에서 ListDataStoresAsync()에 대한 요청이 StandardList 게임 서버 수준 속도 제한을 초과했습니다. | ||
| StandardRemoveGameServerThrottled | StandardRemove 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | RemoveAsync()의 표준 데이터 저장소에 대한 요청이 StandardRemove 게임 서버 수준 속도 제한을 초과했습니다. | ||
| OrderedReadGameServerThrottled | OrderedRead 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | GetAsync() 또는 정렬된 데이터 저장소에서 UpdateAsync()의 읽기가 OrderedRead 게임 서버 수준 속도 제한을 초과했습니다. | ||
| OrderedWriteGameServerThrottled | OrderedWrite 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | SetAsync(), IncrementAsync(), 또는 정렬된 데이터 저장소에서 UpdateAsync()의 쓰기가 OrderedWrite 게임 서버 수준 속도 제한을 초과했습니다. | ||
| OrderedListGameServerThrottled | OrderedList 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | GetSortedAsync()의 정렬된 데이터 저장소에 대한 요청이 OrderedList 게임 서버 수준 속도 제한을 초과했습니다. | ||
| OrderedRemoveGameServerThrottled | OrderedRemove 요청이 게임 서버 한계 또는 요청 대기열이 가득 차서 제한되었습니다. | RemoveAsync()의 정렬된 데이터 저장소에 대한 요청이 OrderedRemove 게임 서버 수준 속도 제한을 초과했습니다. |
서버 오류 코드
| 오류 이름 | 오류 메시지 | 메모 |
|---|---|---|
| DatastoreDeleted | 데이터 저장소가 삭제되었습니다. | 데이터 저장소에서 작업을 수행할 수 없습니다. 데이터 저장소가 이전에 삭제되었기 때문입니다. |
| DatastoreThrottled | 요청 속도가 datastore에 대해 허용된 최대 속도를 초과했습니다. | 하나의 데이터 저장소에 너무 많은 요청을 보냈습니다. |
| InternalServerError | 내부 서버 오류가 발생했습니다. | Roblox 서버에서 간헐적으로 발생하는 오류입니다. 다시 시도하세요. 이상적으로는 지수 백오프와 함께. |
| InvalidExclusiveStartKey | 제공된 독점 시작 키가 유효하지 않습니다. | ListKeysAsync()와 같은 목록 작업에 제공된 독점 시작 키(커서)가 유효하지 않습니다. |
| InvalidPlace | 제공된 장소가 유효하지 않습니다. | 장소에 대한 일치하는 Universe ID가 없습니다. 나중에 다시 시도하세요. |
| InvalidTarget | 제공된 대상이 유효하지 않습니다. | 정렬된 데이터 저장소 키 이름이 50자 제한을 초과했습니다. |
| InvalidUniverse | 제공된 우주가 유효하지 않습니다. | 우주에 대한 일치하는 장소 ID가 없습니다. 나중에 다시 시도하세요. |
| InvalidUserIds | 제공된 사용자 ID에 잘못된 형식이 있습니다. | 사용자 ID를 파싱하는 데 실패했습니다. |
| KeyThrottled | 요청 속도가 키에 대해 허용된 최대 속도를 초과했습니다. | 단일 키에 대해 허용된 최대 요청 속도를 초과했습니다. |
| KeyNotFound | 요청된 키가 존재하지 않습니다. | 키가 존재하지 않습니다. |
| N/A | 진행할 페이지가 없습니다. | 마지막 페이지에서 Pages:AdvanceToNextPageAsync()를 호출할 때 이 오류가 발생합니다. |
| StandardReadExperienceThrottled | 표준 읽기 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | GetAsync(), GetVersionAsync(), GetVersionAtTimeAsync(), 또는 표준 데이터 저장소에서 UpdateAsync()의 읽기가 StandardRead 경험 수준 속도 제한을 초과했습니다. |
| StandardWriteExperienceThrottled | 표준 쓰기 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | SetAsync(), IncrementAsync(), 또는 표준 데이터 저장소에서 UpdateAsync()의 쓰기가 StandardWrite 경험 수준 속도 제한을 초과했습니다. |
| StandardListExperienceThrottled | 표준 목록 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | ListKeysAsync(), ListVersionsAsync(), 또는 표준 데이터 저장소에서 ListDataStoresAsync()의 요청이 StandardList 경험 수준 속도 제한을 초과했습니다. |
| StandardRemoveExperienceThrottled | 표준 제거 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | RemoveAsync()의 표준 데이터 저장소에 대한 요청이 StandardRemove 경험 수준 속도 제한을 초과했습니다. |
| OrderedReadExperienceThrottled | 정렬된 읽기 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | GetAsync() 또는 정렬된 데이터 저장소에서 UpdateAsync()의 읽기가 OrderedRead 경험 수준 속도 제한을 초과했습니다. |
| OrderedWriteExperienceThrottled | 정렬된 쓰기 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | SetAsync(), IncrementAsync(), 또는 정렬된 데이터 저장소에서 UpdateAsync()의 쓰기가 OrderedWrite 경험 수준 속도 제한을 초과했습니다. |
| OrderedListExperienceThrottled | 정렬된 목록 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | GetSortedAsync()의 정렬된 데이터 저장소에 대한 요청이 OrderedList 경험 수준 속도 제한을 초과했습니다. |
| OrderedRemoveExperienceThrottled | 정렬된 제거 요청 속도가 경험에 대해 허용된 최대 속도를 초과했습니다. | RemoveAsync()의 정렬된 데이터 저장소에 대한 요청이 OrderedRemove 경험 수준 속도 제한을 초과했습니다. |
한계
데이터 모델에는 한계가 있습니다. 경험이 이러한 한계를 초과하면 서비스가 자동으로 경험의 데이터 저장소 사용을 속도 제한하고 이후 요청을 다음 대기열 중 하나에 배치합니다:
- 설정
- 정렬된 설정
- 가져오기
- 정렬된 가져오기
대기열 내의 요청은 수신된 순서대로 처리됩니다. 호출된 함수는 요청이 여전히 대기 중인 한 계속해서 대기해야 합니다. 데이터 저장소 키 자체가 제한된 경우 요청은 대기열에 배치되지만 일시적으로 건너뜁니다.
각 대기열의 한계는 30 요청입니다. 대기열의 한계에 도달하면 요청이 301-306 범위의 오류 코드로 실패하며 요청이 완전히 삭제되었음을 나타냅니다.
접근 한계
데이터 저장소는 경험 및 서버 수준 한계의 적용을 받습니다. 경험 수준 한계는 경험 전반에 걸쳐 총 동시 사용자 수에 따라 증가하며, 서버 수준 한계는 변동 가능하며 크리에이터가 사용하는 도구로 설계되었습니다.
경험 한계
각 경험은 데이터 저장소 유형, 요청 유형 및 동시 사용자 수에 따라 특정 수의 데이터 저장소 요청을 허용합니다. 각 데이터 저장소 유형과 요청 유형에 대해 한계는 나열된 모든 기능 간에 공유됩니다.
- UpdateAsync()는 읽기와 쓰기 요청 예산을 모두 소모합니다. 단일 호출이 두 한계를 모두 감소시킵니다.
- 게임 서버와 오픈 클라우드는 예산을 공유합니다. 오픈 클라우드 트래픽은 경험 내 사용으로 인해 속도가 제한될 수 있으며(그리고 그 반대도 마찬가지입니다). 속도 제한 제어에서 더 자세한 안내를 참조하세요.
표준 데이터 저장소
| 요청 유형 | 게임 서버 API | 오픈 클라우드 API | 공유 한계 (분당 요청 수) |
|---|---|---|---|
| 읽기 | GetAsync() GetVersionAsync() GetVersionAtTimeAsync() UpdateAsync() | 데이터 저장소 항목 가져오기 | 300 + 동시 사용자 × 40 |
| 쓰기 | SetAsync() IncrementAsync() UpdateAsync() | 데이터 저장소 항목 만들기, 업데이트, 증가 | 300 + 동시 사용자 × 20 |
| 목록 | ListDataStoresAsync() ListKeysAsync() ListVersionsAsync() | 데이터 저장소 나열, 데이터 저장소 항목 목록, 데이터 저장소 항목 수정판 목록 | 300 + 동시 사용자 × 2 |
| 제거 | RemoveAsync() | 데이터 저장소 항목 삭제, 데이터 저장소 삭제, 데이터 저장소 복원 | 300 + 동시 사용자 × 40 |
정렬된 데이터 저장소
| 요청 유형 | 게임 서버 API | 오픈 클라우드 API | 공유 한계 (분당 요청 수) |
|---|---|---|---|
| 읽기 | GetAsync() UpdateAsync() | 정렬된 데이터 저장소 항목 가져오기 | 300 + 동시 사용자 × 40 |
| 쓰기 | SetAsync() IncrementAsync() UpdateAsync() | 정렬된 데이터 저장소 항목 만들기, 업데이트, 증가 | 300 + 동시 사용자 × 20 |
| 목록 | GetSortedAsync() | 정렬된 데이터 저장소 항목 나열 | 300 + 동시 사용자 × 2 |
| 제거 | RemoveAsync() | 정렬된 데이터 저장소 항목 삭제 | 300 + 동시 사용자 × 40 |
속도 제한 제어
오픈 클라우드와 게임 서버의 요청은 공유되므로 각 요청의 소모량을 독립적으로 제어하는 것이 중요합니다.
게임 서버
각 개별 서버는 위에 설명된 내장 한계가 있습니다. SetRateLimitForRequestType()와 GetRequestBudgetForRequestType()의 조합을 사용하여 개별 서버가 총 예산에 기여하는 것을 세부적으로 제어할 수 있습니다.
오픈 클라우드
오픈 클라우드 요청은 외부 속도 제한 솔루션이 필요합니다. 다음 접근 중 하나를 권장합니다:
- (간단하게) 각 요청 후 짧은 타임아웃을 추가합니다. 특히 동일한 API를 연속 루프에서 호출하는 경우에 필요합니다. 이 타임아웃을 60 / (원하는 예산 소모량 분당) 초로 설정하세요. 이 접근 방식은 요청을 일시적으로 보낼 수 없습니다.
- (강력하게) 누수 버킷 전략을 사용하는 로컬 속도 제한기를 구현합니다.
다음 Node.js 코드 샘플에는 참조 구현이 포함되어 있습니다.
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('API_KEY 환경 변수가 설정되지 않았습니다.');
}
const apiHeaderKey = 'x-api-key';
const universeId = '';
const dataStoreId = 'Inventory';
const baseUrl = 'https://apis.roblox.com/cloud/v2/';
// --- 작업별 속도 제한 구성 (분당 요청 수) ---
const LIST_RATE_PER_MIN = 60;
const GET_RATE_PER_MIN = 120;
const UPDATE_RATE_PER_MIN = 60;
// 작업별 상한 간격: 60 / (분당 요청 수) 초.
const LIST_INTERVAL_MS = (60 / LIST_RATE_PER_MIN) * 1000;
const GET_INTERVAL_MS = (60 / GET_RATE_PER_MIN) * 1000;
const UPDATE_INTERVAL_MS = (60 / UPDATE_RATE_PER_MIN) * 1000;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// 요청을 수행한 다음 이 작업 자체의 간격을 기다립니다.
async function throttledFetch(url, options, intervalMs) {
const response = await fetch(url, options);
await sleep(intervalMs);
return response;
}
async function listEntries(universe, dataStore) {
const listPath = `universes/${universe}/data-stores/${dataStore}/entries`;
const url = baseUrl + listPath;
const response = await throttledFetch(url, {
headers: { [apiHeaderKey]: apiKey }
}, LIST_INTERVAL_MS);
return response.json();
}
async function getEntry(path) {
const url = baseUrl + path;
const response = await throttledFetch(url, {
headers: { [apiHeaderKey]: apiKey }
}, GET_INTERVAL_MS);
return response.json();
}
async function updateEntry(path, payload) {
const url = baseUrl + path;
const response = await throttledFetch(url, {
method: 'PATCH',
headers: {
[apiHeaderKey]: apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload) // 본문은 문자열이어야 합니다.
}, UPDATE_INTERVAL_MS);
return response;
}
(async () => {
try {
const entries = await listEntries(universeId, dataStoreId);
for (const entry of entries.dataStoreEntries) {
const path = entry.path;
console.log(`\n처리 중인 항목: ${path}`);
const currentData = await getEntry(path);
currentData.value.currency += 10;
const payload = { value: currentData.value };
const updateResponse = await updateEntry(path, payload);
console.log(`상태: ${updateResponse.status}`);
console.log(`응답: ${await updateResponse.text()}`);
}
} catch (error) {
console.error('실행 중 오류가 발생했습니다:', error);
}
})();서버 한계
각 서버는 해당 서버의 플레이어 수에 따라 각 요청 유형에 대한 구성 가능한 속도 제한을 갖습니다. 서버는 처음 생성될 때 한 번의 시작 버스트 요청 예산이 추가로 수여됩니다. GetRequestBudgetForRequestType()를 사용하여 현재 서버가 언제든지 만들 수 있는 데이터 저장소 요청 수를 확인하세요.
이러한 한계는 크리에이터가 사용하는 SetRateLimitForRequestType() API를 통해 구성 가능합니다. 이 API를 사용하면 크리에이터가 각 요청 유형에 대한 데이터 저장소 속도 제한을 구성할 수 있습니다.
API를 호출하지 않으면 다음 기본 속도 제한이 적용됩니다:
표준 데이터 저장소
| 요청 유형 | DataStoreRequestType 열거형 | 게임 서버 API | 분당 요청 수 |
|---|---|---|---|
| 읽기 | StandardRead | GetAsync() GetVersionAsync() GetVersionAtTimeAsync() UpdateAsync() | 60 + numPlayers × 40 |
| 쓰기 | StandardWrite | SetAsync() IncrementAsync() UpdateAsync() | 60 + numPlayers × 40 |
| 목록 | StandardList | ListDataStoresAsync() ListKeysAsync() ListVersionsAsync() | 5 + numPlayers × 2 |
| 제거 | StandardRemove | RemoveAsync() | 60 + numPlayers × 40 |
| RemoveVersion (Deprecated) | RemoveVersionAsync | RemoveVersionAsync() | 5 + numPlayers × 2 |
정렬된 데이터 저장소
| 요청 유형 | DataStoreRequestType 열거형 | 게임 서버 API | 분당 요청 수 |
|---|---|---|---|
| 읽기 | OrderedRead | GetAsync() UpdateAsync() | 60 + numPlayers × 40 |
| 쓰기 | OrderedWrite | SetAsync() IncrementAsync() UpdateAsync() | 30 + numPlayers × 5 |
| 목록 | OrderedList | GetSortedAsync() | 5 + numPlayers × 2 |
| 제거 | OrderedRemove | RemoveAsync() | 30 + numPlayers × 5 |
데이터 한계
데이터 저장소는 각 항목에 대해 사용할 수 있는 데이터 양을 제한합니다.
데이터 저장소 이름, 키 이름 및 범위는 모두 특정 문자 길이 이하이어야 합니다. 이들의 길이를 확인하려면 string.len()을 사용하세요.
데이터(키 값)도 초기 유형에 관계없이 문자열로 저장됩니다. JSONEncode() 함수를 통해 데이터의 크기를 확인할 수 있으며, 이 함수는 Luau 데이터를 직렬화된 JSON 테이블로 변환합니다.
| 구성 요소 | 최대 문자 수 |
|---|---|
| 데이터 저장소 이름 | 50 |
| 키 이름 | 50 |
| 범위 | 50 |
| 데이터(키 값) | 4,194,304 per key |
메타데이터 한계
사용자가 정의한 메타데이터의 문자 수에 대한 한계입니다.
| 구성 요소 | 최대 문자 수 |
|---|---|
| 키 이름 | 50 |
| 값 | 250 |
| 키-값 쌍 | 300 |
처리량 한계
키당 처리량 한계는 Roblox 서버에서 성능을 최적화하도록 보장합니다. 각 한계는 경험의 모든 서버에 걸쳐 모든 키에 적용되며 시간에 따라 새로 고쳐집니다.
Roblox는 지난 60초 동안 키와 관련된 할당량의 사용량을 조사합니다. 현재 요청을 포함한 사용량이 처리량 한계 내에 있는 경우 요청이 승인됩니다. 사용량이 한계를 초과하면 요청이 거부됩니다.
| 요청 유형 | 게임 서버 API | 오픈 클라우드 API | 한계 |
|---|---|---|---|
| 읽기 | GetAsync() GetVersionAsync() GetVersionAtTimeAsync() ListVersionsAsync() UpdateAsync() | 데이터 저장소 항목 가져오기 | 분당 25MB |
| 쓰기 | SetAsync() IncrementAsync() UpdateAsync() RemoveAsync() | 데이터 저장소 항목 작성, 업데이트, 증가, 제거 | 분당 4MB |
위의 처리량 한계 외에도 Roblox는 데이터를 내부 스키마에 따라 파티션으로 구성합니다. 따라서 백엔드 서버가 동일한 데이터 저장소에 대한 요청의 높은 볼륨을 받을 경우 추가적인 속도 제한이 발생할 수 있습니다. 원인에 관계없이, 속도 제한은 처리량 한계를 초과했는지 여부에 따라 DatastoreThrottled 또는 KeyThrottled 오류로 나타납니다. 이러한 오류 메시지는 정렬된 데이터 저장소와 표준 데이터 저장소 모두에 적용됩니다.
저장 한계
저장을 안정적이고 확장 가능하게 유지하기 위해 데이터 저장소는 게임 수준에서 저장 사용량에 대한 한계를 사용합니다.
이 한계는 각 게임에 대한 기본 할당량과 평생 사용자 수에 따라 추가적으로 할당량을 구성합니다. 평생 사용자는 최소한 한 번 게임에 입장한 모든 사용자를 의미합니다.
저장 한계는 다음 공식을 사용하여 계산됩니다: 최신 버전 총 저장 한계 = 500MB + 1MB × 평생 사용자 수.
저장용량 사용량은 각 키의 최신 버전의 압축 크기를 사용하여 측정됩니다. 데이터 저장소는 데이터를 저장하기 전에 자동으로 압축하므로, 스스로 압축하지 마세요. 미리 압축하면 불필요한 CPU 오버헤드를 추가하고 데이터 저장소의 기본 압축 효과를 감소시킬 수 있습니다. 압축되지 않은 데이터를 저장함으로써, Roblox의 압축 알고리즘과 향후 스키마 기반 최적화의 개선의 혜택을 누리게 됩니다.
각 키의 최신 버전만이 저장 용량 사용량에 포함됩니다. 삭제된 키와 대체 버전은 보존 기간 동안 버전 API를 통해 여전히 접근 가능하지만, 저장 용량 사용량에는 포함되지 않습니다. 그러나 Open Cloud DeleteDataStore 메서드를 통해 삭제된 데이터 저장소는 영구 삭제되기 전 30일 간 삭제 처리 기간 동안 저장 용량 사용량에 포함됩니다.