...

Właściwe wykorzystanie skryptów Lua w Redis do operacji atomowych

Skrypty Lua w Redis wykonują na serwerze w izolowanym środowisku szereg poleceń Redis wraz z warunkami. Dzięki temu podczas odczytu, sprawdzania i zapisu nie dochodzi do sprzecznych stanów pośrednich spowodowanych działaniem innych klientów. W tym kontekście „atomarny” nie oznacza automatycznego cofnięcia zmian: Dane wejściowe i ścieżki błędów należy starannie zaprojektować, zwłaszcza przed operacjami zapisu. Kluczowe znaczenie mają jasno zdefiniowane klucze, stabilne wartości zwracane, krótki czas wykonania oraz odpowiedni model – od natywnej komendy po funkcję Redis.

Klasyfikowanie skryptów Lua dla Redis

Skrypty Lua w Redis realizują logikę biznesową bezpośrednio na serwerze Redis. Podczas działania skryptu Redis nie przetwarza żadnych innych operacji serwerowych; zawarte w nim polecenia są zatem odizolowane od innych klientów. Dzięki temu można połączyć kilka prostych poleceń w jedno operacja atomowa połączyć, na przykład sprawdzenie limitu, po którym następuje aktualizacja licznika, lub pobranie opłaty tylko w przypadku wystarczającego salda.

Bez skryptu klient może najpierw odczytać licznik za pomocą żądania GET, sprawdzić limit w kodzie aplikacji, a następnie wysłać żądanie INCR. Jednak między tymi krokami inny klient może zmienić ten sam licznik. Skrypt natomiast odczytuje, sprawdza i zwiększa wartość bez tego zauważalnego stanu pośredniego. Rozwiązuje to problem sytuacji wyścigu (race condition) w regule złożonej, ale nie rozwiązuje automatycznie kwestii takich jak odpowiednie wartości graniczne, czasy wykonania czy formaty zwracanych danych.

„Absolutny” i „izolowany” nie oznacza, że Skrypty Lua dla Redis Transakcje bazodanowe z automatycznym cofaniem. Jeśli po wykonaniu operacji zapisu wystąpi błąd wykonania, poprzednie zmiany nie zostaną cofnięte w całości. Dlatego skrypty powinny sprawdzać dane wejściowe, typy danych i warunki biznesowe przed pierwszym zapisem; ścieżki błędów po wprowadzeniu zmian wymagają celowo zaprojektowanego sposobu postępowania.

Typowe reguły to: zezwalanie na dostęp tylko w ramach określonego limitu lub zmniejszanie stanu tylko wtedy, gdy ilość jest wystarczająca. Najpierw sprawdź, czy istniejące pojedyncze polecenie Redis już odzwierciedla całą regułę. Skrypt ma sens wtedy, gdy kilka operacji Redis, łącznie z ich warunkami, musi współdziałać w sposób atomowy.

Wzorzec Lua typu „porównaj i usuń” porównuje zapisaną wartość z przekazanym tokenem własności i usuwa ją tylko w przypadku zgodności. Dzięki temu proces uruchomiony z opóźnieniem nie może usunąć klucza, który w międzyczasie został ponownie przypisany, wyłącznie na podstawie swojego starego tokenu.

Ten model porównawczy opisuje wyłącznie bezpieczną sekwencję dla pojedynczego klucza Redis. Nie rozwiązuje on szerszych kwestii związanych z blokadami rozproszonymi, takich jak odpowiednie czasy trwania dzierżawy, przerwy w działaniu procesów, awarie czy koordynacja wielu instancji Redis. Atomowość polecenia lub skryptu obejmuje ponadto wyłącznie dane Redis, których to dotyczy, a nie płatności, bazy danych, wiadomości e-mail ani zewnętrznych interfejsów API.

Lua Sandbox i jasno określone granice

Redis Open Source wykorzystuje Lua 5.1 do obsługi skryptów. Tego środowiska uruchomieniowego nie należy utożsamiać z lokalnie zainstalowaną lub aktualną główną wersją Lua: zakres dostępnych funkcji językowych oraz zasady bezpieczeństwa określa Redis. Osoby tworzące skrypty Redis w języku Lua powinny zatem sprawdzać je pod kątem faktycznie używanej wersji Redis i nie zakładać właściwości dowolnego zewnętrznego środowiska Lua.

Realizacja odbywa się w ramach jednej Piaskownica z celowo wąskimi ograniczeniami. Skrypt ma przetwarzać dane z Redis oraz przekazane argumenty, ale nie może korzystać ani z systemu plików, ani z sieci, ani z usług systemu operacyjnego. Zewnętrzne wywołania HTTP, wysyłanie wiadomości czy dostęp do plików lokalnych powinny zatem znajdować się w kodzie aplikacji lub w usłudze przeznaczonej do tego celu, a nie w skryptach pamięci podręcznej.

Redis udostępnia KEYS oraz ARGV jako globalne zmienne o zakresie działania. Natomiast do własnych wartości pośrednich i funkcji pomocniczych należy używać zmiennych lokalnych za pomocą local. Dzięki temu widać, które wartości dotyczą wyłącznie tego wywołania, a logika skryptu nie tworzy zbędnych zależności. Polecenia Redis wywołuje się w sposób ukierunkowany za pomocą redis.call lub redis.pcall na.

Środowisko testowe nie zastępuje planowania wydajności. Podczas standardowego wykonywania skrypt blokuje dostęp innych klientów do serwera, dlatego długie pętle, nieograniczone ilości danych i obliczenia wymagające dużej mocy obliczeniowej są nieodpowiednie. Ogranicz działanie do niewielkiej liczby, znanych z góry kluczy i prostych obliczeń. Obszerne analizy, całkowite stany oparte na SCAN lub komunikacja z systemami zewnętrznymi zwiększyłyby ryzyko operacyjne, nie rozszerzając w znaczący sposób atomowości.

Zrozumienie EVAL, KEYS i ARGV

Bezpośrednie wywołanie skryptu odbywa się w następujący sposób: EVAL script numkeys [key …] [arg …]. Zgodnie z kodem źródłowym parametr `numkeys` określa, ile z kolejnych parametrów stanowi klucze. Skrypt uzyskuje do nich dostęp poprzez KEYS z indeksowaniem od 1; wszystkie pozostałe wartości znajdują się w ARGV. To rozróżnienie ma zasadnicze znaczenie: klucze opisują dane Redis, natomiast argumenty – dane merytoryczne, takie jak wartość graniczna, kwota lub oczekiwany token.

Skrypt limitujący otrzymuje na przykład licznik jako KEYS[1], a wartość maksymalną jako ARGV[1]. Odczytuje aktualny stan, przekształca wartość graniczną za pomocą tonumber(ARGV[1]) przekształca ją na liczbę i porównuje obie wartości przed jej zwiększeniem. Przekształcenie to wyraźnie określa zamierzoną regułę obliczeniową, zamiast polegać na domyślnym traktowaniu wartości argumentów. W przypadku braku licznika skrypt może celowo potraktować odczytaną wartość jako zero.

Koncepcyjne rozdzielenie kluczy Redis i wartości argumentów w skrypcie Lua.
Klucze i argumenty merytoryczne trafiają różnymi ścieżkami do logiki po stronie serwera.

Każdy klucz, który skrypt odczytuje lub zapisuje, musi zostać wcześniej podany jako argument klucza. Tworzenie nazw kluczy w skrypcie poprzez łączenie prefiksów lub wyprowadzanie ich z zapisanych danych nie jest niezawodnym rozwiązaniem. W szczególności w przypadku Redis Open Source z włączoną funkcją klastrowania Redis nie jest w stanie przed wykonaniem skryptu ustalić, jakich danych skrypt potrzebuje. Dlatego znane klucze należy przekazywać w całości za pomocą polecenia KEYS, a zmienne wartości wyłącznie za pomocą ARGV.

W przypadku Redis Open Source z włączonym klastrem klucze przekazywane do skryptu muszą ponadto znajdować się w tym samym slocie hashowym. Powyższa deklaracja umożliwia przeprowadzenie tej weryfikacji, ale jej nie zastępuje. W przypadku powiązanych danych pomocny może być celowo wybrany tag hashowy, na przykład account:{4711}:balance oraz account:{4711}:reservations. Część w nawiasach falistych określa tutaj przypisanie slotów; klucze ustalane dynamicznie zakłóciłyby ten plan.

Atomowa aktualizacja licznika typu „Fixed Window”

Poniższy przykład to atomowy Licznik z ustalonym oknem dla lokalnej instancji testowej. Sprawdza stan licznika i limit w ramach jednego cyklu serwera i ustawia czas wygaśnięcia dopiero przy pierwszym pomyślnym dostępie w ramach okna czasowego. Dzięki temu eliminuje się okno czasowe między wywołaniem GET w kodzie aplikacji a późniejszym INCR, w którym inny klient mógłby zmienić stan licznika.

Wywołanie przekazuje klucz licznika, limit oraz czas trwania okna w sekundach. Status 1 oznacza, że operacja została dopuszczona, a status 0 – że limit został osiągnięty. Status 2 sygnalizuje nieprawidłowe dane wejściowe wykryte podczas wstępnej weryfikacji, odrzuconą wartość licznika typu string lub istnienie licznika typu string bez TTL. Jeśli klucz zawiera inny typ danych Redis, już samo wywołanie GET kończy się niepowodzeniem z powodu technicznego błędu typu; skrypt nie zwraca wówczas statusu 2. Należy również odróżnić inne błędy wykonania Redis od merytorycznego statusu zwracanego przez funkcję. Przykład ten nie stanowi wzorca dla danych dostępowych, limitów produkcyjnych ani testów obciążeniowych.

Przed każdą operacją zapisu skrypt sprawdza, czy wszystkie liczby są skończonymi dodatnimi liczbami całkowitymi mieszczącymi się w celowo niewielkim przedziale górnym. To coś więcej niż zwykła kontrola za pomocą tonumber: Wartości takie jak 1.5 lub 1e3 są odrzucane. Limit wynoszący milion uniemożliwia ponadto zachowanie precyzji liczbowej w Lua lub tej z INCR oczekiwany ciąg liczb całkowitych poza zakresem przykładu może mieć znaczenie. Maksymalny czas trwania okna wynoszący 86 400 sekund ogranicza również EXPIRE przekazana liczba sekund.

Kod
EVAL "local max_counter = 1000000; local max_window = 86400; local function positive_integer(value, maximum) if type(value) ~= 'string' or not string.match(value, '^%d+$') then return nil; end; local number = tonumber(value); if not number or number ~= math.floor(number) or number < 1 or number > maximum then return nil; end; return number; end; local limit = positive_integer(ARGV[1], max_counter); local window = positive_integer(ARGV[2], max_window); if not limit or not window then return {2, 'invalid-arguments'}; end; local raw = redis.call('GET', KEYS[1]); if raw and (type(raw) ~= 'string' or not string.match(raw, '^%d+$')) then return {2, 'invalid-counter'}; end; local current = raw and tonumber(raw) or 0; if not current or current ~= math.floor(current) or current < 0 or current > max_counter then return {2, 'invalid-counter'}; end; if raw and redis.call('TTL', KEYS[1]) == -1 then return {2, 'missing-ttl'}; end; if current >= limit then return {0, current}; end; local next = redis.call('INCR', KEYS[1]); if next == 1 then redis.call('EXPIRE', KEYS[1], window); end; return {1, next}" 1 demo:rate-limit 3 60

Wyrażenie regularne akceptuje wyłącznie cyfry dziesiętne; następnie funkcja pomocnicza sprawdza wartość liczbową, czy jest to liczba całkowita oraz czy nie przekracza górnej granicy. Istniejący już licznik może przyjmować wyłącznie nieujemną wartość całkowitą z tego samego ograniczonego zakresu. Dzięki temu żadna wartość ujemna, ułamkowa ani przekraczająca limit nie może niezauważalnie zmienić semantyki limitów. Dopiero po tych sprawdzaniach następuje INCR.

Jeśli klucz nie istnieje, skrypt zaczyna od 0. Jeśli istnieje już prawidłowy licznik typu string bez terminu wygaśnięcia, zwraca status 2 i nie zapisuje niczego. Po pierwszym INCR zestawy EXPIRE wcześniej w pełni zweryfikowana wartość TTL. W przypadku kolejnych trafień pozostaje ona niezmieniona, dzięki czemu okno nie jest stale przedłużane.

Der Umowa zwrotu stanowi część interfejsu: pierwszy element tablicy opisuje stan, drugi – w zależności od stanu – podaje stan licznika lub kod błędu. Kod wywołujący powinien traktować odrzucenie merytoryczne o statusie 0 inaczej niż status 2, który wskazuje na naruszenie warunku wstępnego. Więcej informacji na temat wyboru i monitorowania czasów wykonania można znaleźć w artykule Analiza i optymalizacja wygasania kluczy w Redis uzupełniająca podstawa.

W tym przypadku TTL jest celowo ustawiane tylko przy pierwszym trafieniu. Schemat, który odnawiałby je przy każdym dostępie, miałby inną semantykę czasową i nie byłby już „stałym oknem”. Atomowość w języku Lua Eliminuje jedynie sytuację wyścigu. To, czy model „Fixed Window”, „Sliding Window” czy „Token Bucket” zapewni pożądaną sprawiedliwość i rozkład obciążenia, zależy od wybranego algorytmu, a nie od języka skryptowego.

Wybierz odpowiedni model atomizacji

Nie każde złożone wymaganie wymaga skryptu. Jeśli istnieje pojedyncze polecenie Redis, które w pełni odzwierciedla regułę biznesową, zazwyczaj jest ono łatwiejsze w obsłudze i weryfikacji. Natomiast w przypadku reguł wieloetapowych należy wspólnie rozpatrywać warunki, typy danych i umowę zwrotu.

Począwszy od wersji Redis Open Source 8.4 dostępne są natywne operacje „Compare-and-Set” oraz „Compare-and-Delete” dla pojedynczych kluczy typu string: SET obsługuje opcje porównywania IFEQ/IFNE/IFDEQ/IFDNE; DELEX obsługuje warunkowe usuwanie. W przypadku odpowiednich pojedynczych kluczy nie jest zatem wymagany osobny skrypt porównawczy. W wersjach Redis 8.2, 8.0 i 7.x te nowe opcje SET oraz DELEX nie są dostępne; w tych wersjach nadal stosuje się odpowiednie wzorce WATCH lub Lua.

W przypadku optymistycznego trybu „Compare-and-Set” polecenie WATCH może być odpowiednie przed poleceniami MULTI i EXEC: jeśli obserwowany klucz ulegnie zmianie przed wykonaniem EXEC, transakcja zostanie przerwana, a klient zdecyduje o ponownej próbie. Również transakcje nie zapewniają ogólnego cofnięcia zmian w przypadku błędów podczas wykonywania polecenia EXEC. Dlatego WATCH pozostaje opcją, gdy niezbędnego warunku nie można odzwierciedlić za pomocą pojedynczego natywnego polecenia.

Porównanie modeli atomowości operacji Redis
ModelOdpowiednie zastosowanieKod i wywołaniePo ponownym uruchomieniu lub przełączeniu awaryjnymZachowanie klienta i granice
Polecenie natywneIstniejąca pojedyncza operacja odzwierciedla regułęBrak kodu programu; bezpośrednie polecenieNie ma to wpływu na pamięć podręczną skryptówBrak ponownego ładowania skryptów; ograniczenie do istniejącej semantyki
Natywne CAS/CAD od wersji Redis Open Source 8.4Ustawianie lub usuwanie pojedynczego klucza typu string w zależności od wartościZestaw z IFEQ/IFNE/IFDEQ/IFDNE; DELEX z warunkiem porównaniaNie ma to wpływu na pamięć podręczną skryptówSprawdź ograniczenie wersji i warunek porównania; brak złożonej reguły z wieloma kluczami
MULTI/EXEC z WATCHOptymistyczne czytanie, sprawdzanie i pisanieWATCH, MULTI, EXECBrak pamięci programowejW przypadku zmian przed wykonaniem polecenia EXEC należy ponownie odczytać dane i podjąć decyzję; brak cofania zmian w przypadku błędów podczas wykonywania polecenia EXEC
EVALMały skrypt uruchamiany bezpośrednioKod źródłowy przy każdym EVALPamięć podręczna skryptów nie jest trwałaBrak ponownego ładowania skrótu; kod źródłowy jest przesyłany ponownie
SCRIPT LOAD oraz EVALSHASkrypt ponownie wykorzystany ze znanym skrótemZaładowanie, a następnie wywołanie na podstawie skrótu SHA1Pamięć podręczna może nie być dostępnaZastosować NOSCRIPT i ponownie załadować stronę; szczególnie starannie zaplanować rozwiązanie awaryjne dla potoku
Funkcje Redis od wersji 7.0Nazwana, wielokrotnego użytku logika danychFUNCTION LOAD, a następnie FCALLBiblioteki są replikowane i zapisywane trwaleKonieczny jest proces tworzenia wersji i wdrażania; nie należy tego utożsamiać z wersją EVAL

Skrypty EVAL są powiązane z pamięcią podręczną skryptów i otrzymują dane wejściowe za pośrednictwem zmiennych KEYS i ARGV. Funkcje Redis W Redis 7.0 i nowszych wersjach są one dostępne jako biblioteki nazwane: rejestruje się je za pomocą polecenia FUNCTION LOAD, wywołuje za pomocą FCALL, a także są one zapisywane trwale i replikowane wraz z bazą danych. Klucze i argumenty są przekazywane do funkcji jako parametry; wynika z tego inny model udostępniania i wywoływania niż w przypadku EVAL.

W przypadku prostych, praktycznych logik EVAL stanowi zatem bezpośrednie rozwiązanie. W przypadku wielu klientów i logiki danych wymagającej długoterminowej konserwacji często wskazane jest stosowanie funkcji, o ile obsługuje je używana wersja open source Redis. Decyzja powinna ponadto uwzględniać wdrożenie, uprawnienia, obsługę błędów oraz jasno udokumentowaną wartość zwracaną, a nie tylko liczbę poleceń Redis.

Klastry, błędy i umowy zwrotu

W przypadku Redis Open Source z włączoną funkcją klastra klucze przekazane w skrypcie obsługującym wiele kluczy muszą znajdować się w tym samym slocie hashowym. Tagi hashowe pozwalają to kontrolować: W przypadku account:{4711}:balance oraz account:{4711}:reservations Zawartość między nawiasami klamrowymi określa slot. Dlatego też oba klucze można adresować jednocześnie. Warunek tego samego slota ma tam również zastosowanie do rozpatrywanych tutaj operacji wielokluczyowych oraz transakcji MULTI/EXEC. Inne konfiguracje produktów i klastrów mogą się różnić w przypadku poszczególnych poleceń. Nie oznacza to jednak ogólnego zezwolenia na operacje między slotami w języku Lua: dokumentacja dotycząca operacji wielokluczowych klasyfikuje EVAL/EVALSHA jako operacje jednoslotowe, nawet w przypadku oprogramowania Redis z włączonym klastrem oraz z lub bez interfejsu OSS Cluster API.

Wszystkie używane klucze muszą zostać zadeklarowane jako argumenty klucza przed wywołaniem. Skrypt nie może wywodzić nazw kluczy z zapisanych wartości ani tworzyć ich dynamicznie. Zasada ta umożliwia Redis prawidłową weryfikację slotów przed wykonaniem i zapobiega ukrytym zależnościom, które w instancji autonomicznej pozostają niezauważalne, ale w przypadku Redis Open Source z włączonym klastrem powodują błąd.

Z redis.call() błąd wywołanego polecenia Redis zostanie przekazany do klienta jako błąd skryptu. redis.pcall() zwraca go natomiast do Lua, aby skrypt mógł nim odpowiednio zarządzać. Funkcja `pcall` ma sens tylko wtedy, gdy zdefiniowano konkretną reakcję, na przykład przejrzystą, ustrukturyzowaną odpowiedź błędu lub alternatywny, dopuszczalny przebieg. Ciche ignorowanie błędów maskuje problemy związane z danymi i integralnością.

A Umowa wadliwa oddziela błędy techniczne od wyników merytorycznych. WRONGTYPE oznacza na przykład, że zapisany typ danych w Redis nie odpowiada oczekiwanej komendzie i należy to zbadać. Natomiast odrzucona rezerwacja z powodu braku zapasów jest natomiast oczekiwanym wynikiem i może na przykład zwracać status oraz pozostałą ilość. Aplikacje nie powinny traktować tych kategorii jednakowo ani powtarzać ich obu w sposób ogólny.

Niezawodne wdrażanie skryptów

EVAL nadaje się do bezpośredniego wywoływania: klient przesyła pełny kod źródłowy w języku Lua wraz z wartościami kluczy i argumentów. W przypadku często używanego, niezmienionego skryptu aplikacja może zamiast tego użyć SCRIPT LOAD załadować do pamięci podręcznej skryptów. Redis zwraca w tym celu skrót SHA1; EVALSHA następnie wykonuje dokładnie odpowiedni kod źródłowy. Pozwala to uniknąć wielokrotnego przesyłania, ale nie zmienia ani atomowości, ani merytorycznej odpowiedzialności skryptu.

Der Pamięć podręczna skryptów nie jest trwałe. Po ponownym uruchomieniu, przełączeniu awaryjnym lub SCRIPT FLUSH wywołanie za pomocą podsumowania można wykonać za pomocą NOSCRIPT nie powieść się. Aplikacja powinna standardowo obsłużyć ten przypadek: ponownie załadować skrypt i powtórzyć poprawne wywołanie, o ile pozwala na to własna logika ponownych prób. Digest nie może zatem być traktowany jako gwarancja, że skrypt jest już dostępny na każdym serwerze docelowym.

W przypadku potoków ta opcja awaryjna ma ograniczony zakres. Jeśli kilka poleceń zostało już wysłanych razem, aplikacja może napotkać w nich NOSCRIPT- Nie należy zastępować błędów z mocą wsteczną poprzez wczytanie i ponowne wykonanie w tym samym miejscu. Redis zaleca w takich przypadkach stosowanie sparametryzowanego EVAL jako strategię awaryjną. Osoby planujące replikację i przełączanie awaryjne powinny ponadto zrozumieć, jaką rolę odgrywa bufor replikacji podczas ponownego łączenia repliki: Zrozumienie zaległości replikacji w Redis.

Wartości zmienne nie powinny znajdować się w kodzie źródłowym Lua, lecz w ARGV. W przeciwnym razie każda wartość progowa generuje inny skrypt i niepotrzebnie powiększa pamięć podręczną. Od wersji Redis 7.4 można za pomocą EVAL lub EVAL_RO załadowane skrypty są usuwane po osiągnięciu limitu pamięci podręcznej według algorytmu LRU; nie zastępuje to ani parametryzacji, ani obsługi NOSCRIPT.

Opanowanie długich skryptów i błędów ortograficznych

Skrypt Lua blokuje inne operacje serwera podczas swojego normalnego działania. Zapewnia to izolację, ale w przypadku długiego czasu działania staje się Ryzyko operacyjne. Jeśli skrypt przekroczy skonfigurowaną busy-reply-threshold, Redis odpowiada na zwykłe polecenia za pomocą BUSY; nie powoduje to automatycznego zakończenia działania skryptu. Dlatego należy ograniczyć skrypty do kilku znanych kluczy oraz niewielkich, ograniczonych obliczeń.

Porównanie koncepcyjne krótkiego skryptu Redis w języku Lua z długim, blokującym procesem.
Krótkie, ograniczone sekwencje skryptów zmniejszają ryzyko zablokowania żądań klientów.

Operacje zapisu poprzedzające wystąpienie błędu lub pętli bez końca są szczególnie krytyczne. Jeśli skrypt już zmienił dane, to SCRIPT KILL nie zakończyć go poprawnie. Dlatego przed pierwszym zapisem sprawdź dane wejściowe i unikaj pętli o nieograniczonej długości, a także SCAN dotyczące całkowitych zasobów. Testy powinny odzwierciedlać objętość danych i ścieżki błędów w ramach planowanego wdrożenia.

Błędy w skryptach Lua dla Redis i bezpieczna reakcja aplikacji
PrzypadekWyraźna odpowiedźTypowa przyczynaPewna konsekwencja
NOSCRIPTKomunikat o błędzie NOSCRIPTW tymczasowej pamięci podręcznej skryptów brakuje pliku „Digest”Załaduj skrypt lub użyj funkcji EVAL z parametrami; powtórz operację dopiero zgodnie z własną regułą ponownej próby.
CROSSSLOTCROSSSLOT w Redis Open Source z włączonym klastremKlucze przekazane przez skrypt znajdują się w różnych slotach hashowychZmień projekt klucza i zadeklaruj wszystkie niezbędne klucze.
WRONGTYPEBłąd Redis: WRONGTYPEKey ma nieoczekiwany typ danychNależy skorygować model danych lub wymagania skryptu; nie traktować tego jako odrzucenia merytorycznego.
Ciśnienie w pamięci za pomocą funkcji maxmemoryOperacja zapisu może spowodować przerwanie działania skryptuW momencie uruchomienia Redis przekracza już limit pamięciNie powtarzaj tego na ślepo; w przypadku redis.pcall zapewnij bezpieczną, udokumentowaną ścieżkę obsługi błędów.
ZAJĘTYKomunikat o błędzie „BUSY” dla innych poleceńSkrypt przekracza próg busy-reply-thresholdZmniejsz obciążenie i skróć skrypt; po operacjach zapisu nie polegaj na funkcji „kill”.
Odrzucenie merytoryczneUdokumentowana wartość stanuNa przykład osiągnięto limit lub stan zapasów jest zbyt niskiOcenić status i odrzucić transakcję w sposób uporządkowany.

Na stronie maxmemory Przebieg procesu zależy od pierwszej operacji zapisu. Jeśli Redis przekroczył już limit, polecenie zajmujące dużo pamięci może spowodować redis.call przerwać działanie skryptu; redis.pcall zwraca błąd do języka Lua i wymaga specjalnie zaprojektowanej ścieżki obsługi błędów. Nie powoduje to przywrócenia wcześniej wprowadzonych zmian.

Pierwsza operacja, która nie wymaga dodatkowej pamięci, na przykład DEL lub LREM, można natomiast pozwolić, by skrypt nadal działał; późniejsze operacje zapisu mogą zwiększyć zużycie poprzez maxmemory zwiększyć. Błędy techniczne, takie jak WRONGTYPE lub CROSSSLOT W przypadku Redis Open Source z włączoną funkcją klastrowania konieczne są poprawki w modelu danych lub projekcie kluczy, podczas gdy jedynie sam skrypt może określić odrzucenie merytoryczne jako status stabilny.

Świadomy wybór odpowiednich zastosowań

W przypadku rezerwacji warunkowej skrypt może sprawdzić stan magazynowy, odrzucić zbyt małą wartość, a w przypadku powodzenia zwrócić pozostałą ilość. rezerwacja atomowa obejmuje jednak wyłącznie Redis. Płatności, relacyjna baza danych, poczta elektroniczna i zewnętrzne interfejsy API wymagają osobnego dostosowania, a w razie potrzeby – logiki kompensacyjnej.

Wybór zależy od wersji Redis i modelu danych. Począwszy od wersji Redis Open Source 8.4, opcje porównywania dostępne w SET warunkowe ustawienie oraz DELEX przeprowadzić porównanie i usunięcie pojedynczego klucza typu string. W wersjach Redis starszych niż 8.4 lub w przypadku bardziej złożonego warunku należy WATCH z MULTI/EXEC Alternatywa: jeśli obserwowany klucz ulegnie zmianie przed wykonaniem polecenia EXEC, transakcja zostaje przerwana, a klient decyduje o ponownym odczytaniu i powtórzeniu operacji. Krótki skrypt w języku Lua sprawdza się w sytuacji, gdy po stronie serwera musi nastąpić współdziałanie kilku poleceń lub struktur danych wraz z ich regułami biznesowymi.

W przypadku blokad rozproszonych ani pojedyncze polecenie, ani wzorzec Lua nie wystarczają jako całościowa koncepcja. Czas trwania dzierżawy, przerwy w działaniu procesów, awarie, powtórzenia, przełączanie awaryjne i scenariusze z wieloma instancjami należy oceniać osobno. Należy preferować polecenie natywne, jeśli używana wersja i jej semantyka obejmują całą regułę. W przeciwnym razie należy WATCH oraz rozważyć zastosowanie krótkiego skryptu w zależności od umowy dotyczącej błędów i miejsca, w którym znajduje się logika biznesowa. W przypadku logiki po stronie serwera, którą można ponownie wykorzystać, odpowiednim rozwiązaniem może być funkcja Redis. Skrypty tylko do odczytu od wersji Redis 7.0 można korzystać z EVAL_RO lub EVALSHA_RO działają, ale tylko wtedy, gdy logika gwarantuje brak operacji zapisu.

Źródła i aktualny stan wiedzy

Stan badań:

Stan badań i wersja: 23 września 2026 r. Artykuł dotyczy Redis Open Source i rozróżnia skrypty EVAL od funkcji Redis, wprowadzonych od wersji Redis 7.0. Przed użyciem należy sprawdzić ograniczenia dotyczące wersji oraz dostępne polecenia w odniesieniu do konkretnej wersji Redis, na której działa serwer.

https://redis.io/docs/latest/develop/programmability/eval-intro/

https://redis.io/docs/latest/develop/programmability/

https://redis.io/docs/latest/commands/eval/

https://redis.io/docs/latest/develop/using-commands/multi-key-operations/

https://redis.io/docs/latest/develop/using-commands/transactions/

https://redis.io/docs/latest/develop/programmability/functions-intro/

https://redis.io/docs/latest/commands/evalsha_ro/

Artykuły bieżące

Schemat koncepcyjny przedstawiający przebieg izolowanego skryptu Lua w Redis między kilkoma klientami a spójną parą klucz-wartość.
Bazy danych

Właściwe wykorzystanie skryptów Lua w Redis do operacji atomowych

Skrypty Lua w Redis łączą odczyt, sprawdzanie i zapis w jedną izolowaną operację serwera. Artykuł wyjaśnia pojęcia KEYS i ARGV, EVAL i funkcje, ograniczenia klastra, umowy dotyczące błędów, a także bezpieczne wzorce dotyczące limitów i rezerwacji.

Schemat koncepcyjny serwera proxy odwrotnego NGINX z pamięcią podręczną resolvera DNS i zmiennymi adresami serwerów zaplecza.
Serwer WWW Plesk

Prawidłowa konfiguracja pamięci podręcznej resolwera NGINX

Oto jak skonfigurować resolver NGINX dla dynamicznych backendów: jasne rozdzielenie parametrów DNS-TTL, valid, resolver_timeout, zmiennych miejsc docelowych proxy_pass oraz dynamicznych upstreamów.

Koncepcyjne przedstawienie stanów jądra, które są widoczne za pośrednictwem procfs.
Administracja

Linux procfs dla administratorów: przegląd najważniejszych plików

procfs zapewnia bezpośredni wgląd w działające jądro systemu Linux. Niniejszy przewodnik wyjaśnia znaczenie ważnych plików w katalogu /proc, opisuje liczniki i migawki oraz przedstawia bezpieczne metody diagnostyczne dotyczące obciążenia, pamięci, procesów, operacji wejścia/wyjścia oraz parametrów sysctl.