복붙노트

[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. ==============================

    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을 다시 레디 스에게 조금 해킹 할),이를 시도하기 전에 정말 원래의 요구 사항을 재고 할 것을 촉구 당신이 제대로 레디 스를 사용하고 (즉, 데이터 액세스 요구에 따라 "스키마"설계) 있는지 확인합니다.

  2. 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