Redis
 sql >> Baza danych >  >> NoSQL >> Redis

Redis skrypt usuwania symboli wieloznacznych za pomocą EVAL, SCAN i DEL zwraca polecenia Write niedozwolone po poleceniach niedeterministycznych

AKTUALIZACJA: poniższe dotyczy wersji Redis do 3.2. Od tej wersji replikacja oparta na efektach znosi zakaz niedeterminizmu, więc wszystkie zakłady są wyłączone (a raczej włączone).

Nie możesz (i nie powinieneś) mieszać SCAN rodziny poleceń z dowolnym poleceniem zapisu w skrypcie, ponieważ odpowiedź tego pierwszego jest zależna od wewnętrznych struktur danych Redis, które z kolei są unikalne dla procesu serwera. Innymi słowy, dwa procesy Redis (np. nadrzędny i podrzędny) nie gwarantują, że zwrócą te same odpowiedzi (więc w kontekście replikacji Redis [który nie jest oparty na operacjach, ale na instrukcjach], który by go zepsuł).

Redis próbuje chronić się przed takimi przypadkami, blokując dowolne polecenie zapisu (takie jak DEL ), jeśli jest wykonywane po losowym poleceniu (np. SCAN ale także TIME , SRANDMEMBER i podobne). Jestem pewien, że można to obejść, ale czy chciałbyś to zrobić? Pamiętaj, że udasz się na nieznane terytorium, gdzie zachowanie systemu nie jest zdefiniowane.

Zamiast tego zaakceptuj fakt, że nie powinieneś mieszać losowych odczytów i zapisów, i spróbuj wymyślić inne podejście do rozwiązania problemu, a mianowicie usunięcie pęku kluczy według wzorca w sposób atomowy.

Najpierw zadaj sobie pytanie, czy możesz złagodzić którekolwiek z wymagań. Czy to musi być atomowe? Atomowość oznacza, że ​​Redis zostanie zablokowany na czas usuwania (niezależnie od ostatecznej implementacji) oraz że długość operacji zależy od rozmiaru zadania (tj. liczby usuwanych kluczy i ich zawartości [usunięcie dużego zestawu jest droższe niż na przykład usunięcie krótkiego ciągu znaków]).

Jeśli atomowość nie jest koniecznością, okresowo/leniwie SCAN i usuwaj w małych partiach. Jeśli to konieczne, zrozum, że zasadniczo próbujesz naśladować złe KEYS polecenie :) Ale możesz zrobić lepiej, jeśli masz wcześniejszą wiedzę o wzorcu.

Zakładając, że wzorzec jest znany w czasie wykonywania aplikacji, możesz zebrać odpowiednie klucze (np. w zestawie), a następnie użyć tej kolekcji do zaktualizowania usunięcia w sposób atomowy i bezpieczny dla replikacji, który jest bardziej wydajny w porównaniu z przechodzeniem przez całą przestrzeń kluczy .

Jednak najbardziej „trudnym” problemem jest to, że musisz uruchomić dopasowywanie wzorców ad hoc, zapewniając jednocześnie niepodzielność. Jeśli tak, problem sprowadza się do uzyskania przefiltrowanej według wzorców migawki obszaru kluczy, po której następuje seria usunięć (podkreślenie ponownie:podczas gdy baza danych jest zablokowana). W takim przypadku możesz bardzo dobrze użyć KEYS w swoim skrypcie Lua i miej nadzieję na najlepsze... (ale dobrze wiedząc, że możesz uciec się do SHUTDOWN NOSAVE dość szybko :P).

Ostatnia optymalizacja polega na indeksowaniu samego obszaru kluczy. Oba SCAN i KEYS są w zasadzie pełnymi skanami tabeli, więc co by było, gdybyśmy zindeksowali tę tabelę? Wyobraź sobie utrzymywanie indeksu nazw kluczy, o które można zapytać podczas transakcji — prawdopodobnie możesz użyć posortowanego zestawu i zakresów leksykograficznych (HT @TwBert ), aby pozbyć się większości potrzeb związanych z dopasowaniem wzorców. Ale przy znacznych kosztach… nie tylko będziesz prowadzić podwójną księgowość (przechowywanie kosztów nazw każdego klucza w pamięci RAM i procesorze), ale będziesz zmuszony zwiększyć złożoność swojej aplikacji. Po co dodawać złożoność? Ponieważ aby zaimplementować taki indeks, musiałbyś samodzielnie utrzymywać go w warstwie aplikacji (i prawdopodobnie wszystkich innych skryptach Lua), ostrożnie pakując każdą operację zapisu do Redis w transakcji, która również aktualizuje indeks.

Zakładając, że zrobiłeś to wszystko (i biorąc pod uwagę oczywiste pułapki, takie jak zwiększona złożoność potencjalnych błędów, co najmniej podwojone obciążenie zapisu na Redis, pamięć RAM i procesor, ograniczenia skalowania itd.), możesz poklepać się po ramię i pogratuluj sobie korzystania z Redis w sposób, do którego nie został zaprojektowany. Podczas gdy nadchodzące wersje Redis mogą (lub nie) zawierać lepsze rozwiązania dla tego wyzwania (@TwBert – chcesz zrobić wspólny RCP/wkład i ponownie trochę zhakować Redis? ), zanim spróbuję tego, naprawdę zachęcam do ponownego przemyślenia pierwotnych wymagań i sprawdzenia, czy poprawnie używasz Redis (tj. Projektując swój „schemat” zgodnie z potrzebami dostępu do danych).




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Laravel 4 :Wywołanie niezdefiniowanej metody Redis::connection()

  2. Konfigurowanie redis, aby najpierw konsekwentnie eksmitować starsze dane

  3. Jaka jest różnica między metodą HSET a HMSET w bazie danych redis

  4. Jak przenieść bazę danych redis z jednego serwera na drugi?

  5. Jak skalować SignalR przy użyciu roli Azure Worker i OWIN