[REDIS] 레디 스가 EVAL, SCAN 및 DEL 반환 사용하여 스크립트를 삭제 와일드 카드 "쓰기 명령을 비 결정적 명령 후 허용되지 않습니다"
REDIS레디 스가 EVAL, SCAN 및 DEL 반환 사용하여 스크립트를 삭제 와일드 카드 "쓰기 명령을 비 결정적 명령 후 허용되지 않습니다"
내가 사용하는이 패턴에 따라 키를 찾아 (원자)를 삭제합니다 스캔하는 루아 스크립트를 구축하기 위해 탐구에있어 그래서. 내가 먼저 다음 스크립트를 준비
local keys = {};
local done = false;
local cursor = "0"
repeat
local result = redis.call("SCAN", cursor, "match", ARGV[1], "count", ARGV[2])
cursor = result[1];
keys = result[2];
for i, key in ipairs(keys) do
redis.call("DEL", key);
end
if cursor == "0" then
done = true;
end
until done
return true;
"@user_script : ERR 9 : 쓰기 명령이 비 결정적 명령 후 허용되지 않습니다"다음 다시 침을 것이다 내가 조금 생각하고 다음 스크립트를 내놓았다 그래서 :
local all_keys = {};
local keys = {};
local done = false;
local cursor = "0"
repeat
local result = redis.call("SCAN", cursor, "match", ARGV[1], "count", ARGV[2])
cursor = result[1];
keys = result[2];
for i, key in ipairs(keys) do
all_keys[#all_keys+1] = key;
end
if cursor == "0" then
done = true;
end
until done
for i, key in ipairs(all_keys) do
redis.call("DEL", key);
end
return true;
이는 여전히 같은 오류 (@user_script : 17 : 비 결정적 명령 후 허용되지 쓰기 명령)를 반환합니다. 이 날 난처한 상황에 빠진 있습니다. 이 문제를 회피 할 수있는 방법이 있습니까?
스크립트는 phpredis하고 다음을 사용하여 실행되었다
$args_arr = [
0 => 'test*', //pattern
1 => 100, //count for SCAN
];
var_dump($redis->eval($script, $args_arr, 0));
해결법
-
==============================
1.업데이트 : 아래 3.2까지 레디 스 버전에 적용됩니다. 해당 버전에서 효과 기반 복제는 모든 베팅이 (에, 또는 오히려) 오프 그래서 비 결정론에 대한 금지를 담고있다.
업데이트 : 아래 3.2까지 레디 스 버전에 적용됩니다. 해당 버전에서 효과 기반 복제는 모든 베팅이 (에, 또는 오히려) 오프 그래서 비 결정론에 대한 금지를 담고있다.
당신은 할 수 없습니다 (그리고 안)의 이전 응답이 차례로 서버 프로세스에 고유 한 내부 레디 스 데이터 구조에 의존하기 때문에 스크립트에서 어떤 쓰기 명령을 사용하여 명령의 SCAN 가족을 섞는다. 다르게 말하면, 두 레디 스 프로세스 (예를 들어, 마스터와 슬레이브)가 같은 응답을 반환 보장 할 수 없습니다 (그래서 레디 스 복제 맥락에서 그것을 깰 것이라고 [동작 -하지만없는 문 기반]).
레디 스 그것이 임의의 명령 (예를 들어, SCAN 아니라 TIME, SRANDMEMBER 유사한) 후에 실행되는 경우 (예 DEL)을 어떤 기록 명령을 차단함으로써 이러한 경우에 대해 자신을 보호하기 위해 시도한다. 나는 확실히 그것을 극복 할 수있는 방법이있다 해요,하지만 당신은 그렇게할까요? 당신은 시스템의 동작은 정의되지 않은 미지의 영역으로 갈 것, 기억하십시오.
대신, 임의 읽기 및 쓰기 혼합, 즉 원자 방식으로 패턴에 따라 키의 무리를 삭제하여 문제를 해결하기위한 다른 방법을 생각하려고는 안된다는 사실을 받아 들인다.
당신은 요구 사항 중 하나를 휴식을 취할 수있는 경우 먼저 자신에게 물어. 그것은 원자 수 있습니까? 레디 스의 삭제 (에 관계없이 최종 구현)의 기간 동안 차단됩니다 및 작업의 길이가 삭제됩니다 키의 작업 (즉, 숫자의 크기에 따라 큰 세트를 삭제 그 내용은 [있음을 자성 수단 예를 들어 짧은 문자열을 삭제하는 것보다 더 비싼).
자성이 필수가 아닌 경우, 주기적으로 / 느리게 스캔 작은 일괄 삭제합니다. 이 필수 인 경우, 기본적으로 키 명령 악을 :) 모방하려는 것을 이해하지만 패턴의 사전 지식이 있다면 당신은 잘 할 수 있습니다.
패턴이 응용 프로그램의 런타임 동안 알려져 가정하면, 관련 키를 수집 (예 : 설정에서) 한 후 전체 키 스페이스에 걸쳐 진행에 비해 더 효율적 원자 및 복제 안전한 방법으로 삭제를 실현하기 위해 해당 모음을 사용할 수 있습니다 .
당신이 원 자성을 보장하면서 임시 패턴 매칭을 실행해야하는 경우, 가장 "어려운"문제입니다. 경우에 따라서,이 문제를 즉시 삭제하는 연속 (: 데이터베이스가 차단되는 동안 다시 강조) 뒤에 KEYSPACE의 필터링 별 패턴 스냅 샷을 얻기 귀결. 이 경우 당신은 매우 잘 (: P 당신이 매우 빠르게 SHUTDOWN NOSAVE에 의존 수 있지만 전체 잘 알고있는) 당신의 루아 스크립트 내 키와 최고의 희망을 ... 사용할 수 있습니다.
마지막 최적화는 인덱스에 키 스페이스 자체입니다. SCAN 및 키는 모두 기본적으로 전체 테이블 스캔이 무엇인지 우리가 인덱스 테이블 것이 있다면? 트랜잭션 중에 조회 할 수 있습니다 키의 이름에 인덱스를 유지하는 상상 - 당신은 아마도 패턴 매칭의 요구의 대부분을 멀리 할 수있는 소트 세트와 사전 편찬 범위 (HT @TwBert)를 사용할 수 있습니다. 그러나 상당한 비용 ...뿐만 아니라 당신은 (RAM 및 CPU의 각 키의 이름 비용 저장)을 두 번 부기를하고있을 것입니다, 당신은 응용 프로그램에 복잡성을 추가하도록 강요 할 것입니다. 왜 복잡성을 추가? 이러한 인덱스를 구현하기 때문에주의 깊게 또한 인덱스를 업데이트하는 트랜잭션 (transaction) 레디 스 각 쓰기 작업을 포장, (아마도 다른 모든 루아 스크립트 등) 응용 계층에서 스스로를 유지해야 할 것이다.
(적어도-등 레디 스, RAM 및 CPU, 스케일링에 대한 제한에 대한 쓰기 부하를 두 배로 ..., 버그의 복잡성의 잠재적 같은 계정으로 명백한 함정을 복용) 당신이에 자신을 두드려 수 있습니다 당신이 모든 것을 한 가정 어깨와 그것을 위해 설계되지 않았 음 방식으로 레디 스를 사용하여 자신을 축하드립니다. 레디 스의 향후 버전 (또는하지 않을 수 있습니다)이 문제에 대한 더 나은 솔루션을 포함 할 수 있지만 (@TwBert을 - 공동 RCP /있는 contrib을 다시 레디 스에게 조금 해킹 할),이를 시도하기 전에 정말 원래의 요구 사항을 재고 할 것을 촉구 당신이 제대로 레디 스를 사용하고 (즉, 데이터 액세스 요구에 따라 "스키마"설계) 있는지 확인합니다.
from https://stackoverflow.com/questions/27976255/redis-wildcard-delete-script-using-eval-scan-and-del-returns-write-commands-n by cc-by-sa and MIT license
'REDIS' 카테고리의 다른 글
[REDIS] 레디 스 / Jedis - 패턴에 의해 삭제 하시겠습니까? (0) | 2020.01.14 |
---|---|
[REDIS] 레디 스 목록에 값으로 항목의 인덱스를 가져옵니다 (0) | 2020.01.14 |
[REDIS] 레디 스 템플릿을 사용하여 레디 스에서 모든 키를 얻는 방법 (0) | 2020.01.14 |
[REDIS] 내 레디 스 키가 만료되지 않습니다 (0) | 2020.01.14 |
[REDIS] 어떻게 도커 작성을 사용하여 레디 스 용기에 연결? (0) | 2020.01.14 |