{"id":21670,"date":"2026-09-24T06:24:12","date_gmt":"2026-09-24T04:24:12","guid":{"rendered":"https:\/\/webhosting.de\/?p=21670"},"modified":"2026-09-24T06:24:16","modified_gmt":"2026-09-24T04:24:16","slug":"skrypty-lua-w-redis-operacje-atomowe","status":"publish","type":"post","link":"https:\/\/webhosting.de\/pl\/redis-lua-scripts-atomare-operationen\/","title":{"rendered":"W\u0142a\u015bciwe wykorzystanie skrypt\u00f3w Lua w Redis do operacji atomowych"},"content":{"rendered":"\n<div class=\"wh-article\" data-wh-layout=\"2.1.2\" style=\"width:100%;max-width:820px;margin:0 auto;color:#263b4b;font-family:inherit;font-size:18px;line-height:1.8;text-align:start;overflow-wrap:break-word;box-sizing:border-box\"><p class=\"wh-lead\" style=\"font-size:20px;line-height:1.7;color:#233746;margin:0 0 1.1em\">Redis Lua Scripts f\u00fchren mehrere Redis-Befehle samt Bedingungen isoliert auf dem Server aus. So entsteht zwischen Lesen, Pr\u00fcfen und Schreiben kein widerspr\u00fcchlicher Zwischenstand durch andere Clients. <strong style=\"font-weight:700;color:inherit\">Atomar bedeutet dabei nicht automatisches Rollback<\/strong>: Eingaben und Fehlerpfade m\u00fcssen vor allem vor Schreiboperationen bewusst entworfen werden. Entscheidend sind klar deklarierte Keys, stabile R\u00fcckgabewerte, kurze Laufzeiten und ein passendes Modell \u2013 vom nativen Befehl bis zur Redis Function.   <\/p>\n<nav class=\"wh-toc\" aria-label=\"Inhalt dieses Artikels\" style=\"display:block;margin:28px 0 38px;padding:22px;border:1px solid #d9e4e8;border-radius:14px;background:#f4f8f8\"><p class=\"wh-toc-title\" style=\"font-size:13px;font-weight:700;letter-spacing:.08em;color:#49656b;margin:0 0 14px\">Direkt zum Abschnitt<\/p><div class=\"wh-toc-grid\" style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:10px\"><div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#atomicity\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Atomare Redis Lua Scripts einordnen<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#runtime\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Lua Sandbox und klare Grenzen<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#interfaces\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">EVAL, KEYS und ARGV verstehen<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#limitexample\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Fixed-Window-Z\u00e4hler atomar aktualisieren<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#mechanisms\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Passendes Atomizit\u00e4tsmodell ausw\u00e4hlen<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#clustererrors\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Cluster, Fehler und R\u00fcckgabevertr\u00e4ge<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#delivery\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Script-Auslieferung robust betreiben<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#operations\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Lange Scripts und Schreibfehler beherrschen<\/a><\/div>\n<div class=\"wh-toc-item\" style=\"display:block;min-width:0;margin:0;padding:0\"><a class=\"wh-toc-link\" href=\"#decisions\" style=\"display:block;height:100%;padding:12px 15px;border:1px solid #dce6e8;border-radius:9px;background:#fff;color:#18575b;font-size:14px;line-height:1.5;font-weight:600;text-decoration:none;box-sizing:border-box\">Geeignete Einsatzf\u00e4lle bewusst entscheiden<\/a><\/div>\n<\/div><\/nav><section class=\"wh-section\" aria-labelledby=\"atomicity\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"atomicity\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Atomare Redis Lua Scripts einordnen<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Redis Lua Scripts f\u00fchren fachliche Datenlogik direkt im Redis-Server aus. W\u00e4hrend ein Script l\u00e4uft, verarbeitet Redis keine anderen Serveraktivit\u00e4ten; die enthaltenen Befehle sind daher gegen\u00fcber anderen Clients isoliert. Damit lassen sich mehrere einfache Kommandos zu einer <strong style=\"font-weight:700;color:inherit\">atomaren Operation<\/strong> verbinden, etwa eine Limitpr\u00fcfung mit anschlie\u00dfendem Z\u00e4hler-Update oder eine Abbuchung nur bei ausreichendem Guthaben.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Ohne Script kann ein Client zun\u00e4chst mit GET einen Z\u00e4hler lesen, die Grenze im Anwendungscode pr\u00fcfen und danach INCR senden. Zwischen diesen Schritten kann jedoch ein anderer Client denselben Z\u00e4hler ver\u00e4ndern. Ein Script liest, pr\u00fcft und erh\u00f6ht dagegen ohne diesen beobachtbaren Zwischenzustand. Das l\u00f6st die Race Condition der zusammengesetzten Regel, nicht aber automatisch Fragen wie passende Grenzwerte, Ablaufzeiten oder R\u00fcckgabeformate.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Atomar und isoliert bedeutet nicht, dass <strong style=\"font-weight:700;color:inherit\">Redis Lua Scripts<\/strong> Datenbanktransaktionen mit automatischem Rollback sind. Tritt nach einer bereits erfolgten Schreiboperation ein Laufzeitfehler auf, werden vorherige \u00c4nderungen nicht pauschal zur\u00fcckgenommen. Deshalb sollten Scripts Eingaben, Datentypen und fachliche Voraussetzungen vor dem ersten Schreiben pr\u00fcfen; Fehlerpfade nach \u00c4nderungen brauchen eine bewusst entworfene Behandlung.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Typische Regeln sind: einen Zugriff nur innerhalb eines Limits zulassen oder einen Bestand nur bei ausreichender Menge reduzieren. Pr\u00fcfe zun\u00e4chst, ob ein vorhandener einzelner Redis-Befehl die gesamte Regel bereits ausdr\u00fcckt. Ein Script ist dann sinnvoll, wenn mehrere Redis-Operationen einschlie\u00dflich ihrer Bedingungen atomar zusammenwirken m\u00fcssen. <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Ein Lua-Muster f\u00fcr Vergleich-und-L\u00f6schen vergleicht den gespeicherten Wert mit einem \u00fcbergebenen Ownership-Token und l\u00f6scht nur bei Gleichheit. Dadurch kann ein versp\u00e4teter Prozess nicht allein wegen seines alten Tokens einen inzwischen neu belegten Key l\u00f6schen.<\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Dieses Vergleichsmuster beschreibt ausschlie\u00dflich die sichere Reihenfolge f\u00fcr einen einzelnen Redis-Key. Es l\u00f6st nicht die weitergehenden Fragen verteilter Sperren, etwa passende Lease-Dauern, Prozesspausen, Ausf\u00e4lle oder die Koordination mehrerer Redis-Instanzen. Die Atomizit\u00e4t eines Befehls oder Scripts umfasst zudem nur die beteiligten Redis-Daten, nicht Zahlung, Datenbank, E-Mail oder externe APIs.<\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"runtime\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"runtime\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Lua Sandbox und klare Grenzen<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Redis Open Source bettet f\u00fcr Scripts Lua 5.1 ein. Diese Laufzeit ist nicht mit einer lokal installierten oder aktuellen Lua-Hauptversion gleichzusetzen: Verf\u00fcgbarer Sprachumfang und Sicherheitsregeln bestimmt Redis. Wer redis lua scripts entwickelt, sollte sie deshalb gegen die tats\u00e4chlich eingesetzte Redis-Version pr\u00fcfen und nicht Eigenschaften einer beliebigen externen Lua-Umgebung voraussetzen.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Die Ausf\u00fchrung erfolgt in einer <strong style=\"font-weight:700;color:inherit\">Sandbox<\/strong> mit absichtlich engen Grenzen. Ein Script soll Redis-Daten und \u00fcbergebene Argumente verarbeiten, aber weder Dateisystem, Netzwerk noch Betriebssystemdienste nutzen. Externe HTTP-Aufrufe, das Versenden von Nachrichten oder der Zugriff auf lokale Dateien geh\u00f6ren daher in den Anwendungscode oder einen daf\u00fcr vorgesehenen Dienst, nicht in cache scripting.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Redis stellt <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">KEYS<\/code> und <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">ARGV<\/code> als globale Laufzeitvariablen bereit. F\u00fcr eigene Zwischenwerte und Hilfsfunktionen verwendest du dagegen lokale Variablen mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">local<\/code>. So bleibt erkennbar, welche Werte nur f\u00fcr diesen Aufruf gelten, und die Script-Logik erzeugt keine vermeidbaren Abh\u00e4ngigkeiten. Redis-Kommandos rufst du gezielt \u00fcber <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">redis.call<\/code> oder <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">redis.pcall<\/code> auf.   <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Die Sandbox ersetzt keine Kapazit\u00e4tsplanung. W\u00e4hrend regul\u00e4rer Ausf\u00fchrung blockiert ein Script andere Clients am Server, daher sind lange Schleifen, unbeschr\u00e4nkte Datenmengen und rechenintensive Auswertungen ungeeignet. Beschr\u00e4nke die Arbeit auf wenige, vorher bekannte Keys und kleine Berechnungen. Umfangreiche Analysen, SCAN-basierte Gesamtbest\u00e4nde oder Kommunikation mit Fremdsystemen w\u00fcrden die Betriebsrisiken erh\u00f6hen, ohne die Atomizit\u00e4t sinnvoll zu erweitern.  <\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"interfaces\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"interfaces\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">EVAL, KEYS und ARGV verstehen<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Der unmittelbare Aufruf eines Scripts verwendet die Form <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVAL script numkeys [key \u2026] [arg \u2026]<\/code>. Nach dem Quelltext legt numkeys fest, wie viele folgende Parameter Schl\u00fcssel sind. Das Script erreicht sie \u00fcber KEYS mit einsbasierter Indexierung; alle weiteren Werte stehen in ARGV. Diese Trennung ist wesentlich: Schl\u00fcssel beschreiben die Redis-Daten, Argumente die fachlichen Eingaben wie Grenzwert, Betrag oder erwarteten Token.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Ein Limit-Script erh\u00e4lt beispielsweise den Z\u00e4hler als KEYS[1] und den H\u00f6chstwert als ARGV[1]. Es liest den aktuellen Stand, wandelt den Grenzwert mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">tonumber(ARGV[1])<\/code> in eine Zahl um und vergleicht beide Werte, bevor es erh\u00f6ht. Die Umwandlung macht die beabsichtigte numerische Fachregel explizit, statt sich auf eine implizite Behandlung von Argumentwerten zu verlassen. Fehlt ein Z\u00e4hler, kann das Script den gelesenen Wert gezielt als null behandeln.  <\/p>\n<figure class=\"wp-block-image size-large wh-figure\" aria-describedby=\"wh-caption-detail1\" style=\"display:block;float:none;clear:both;width:100%;max-width:760px;margin:34px auto 40px;border:1px solid #dae5e9;border-radius:14px;overflow:hidden;background:#f5f8fa;box-shadow:0 10px 28px -17px rgba(24,47,60,.28);box-sizing:border-box\"><div class=\"wh-figure-media\" style=\"display:block;background:#eef3f5;line-height:0\"><img loading=\"lazy\" width=\"800\" height=\"534\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-keys-argv-d0a32bc8-detail1-7fda2b1843-1024x683.webp\" class=\"wp-image-21681\" alt=\"Konzeptionelle Trennung von Redis-Schl\u00fcsseln und Argumentwerten bei einem Lua Script.\" loading=\"lazy\" decoding=\"async\" srcset=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-keys-argv-d0a32bc8-detail1-7fda2b1843-1024x683.webp 1024w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-keys-argv-d0a32bc8-detail1-7fda2b1843-300x200.webp 300w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-keys-argv-d0a32bc8-detail1-7fda2b1843-768x512.webp 768w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-keys-argv-d0a32bc8-detail1-7fda2b1843-18x12.webp 18w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-keys-argv-d0a32bc8-detail1-7fda2b1843.webp 1536w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/ style=\"display:block;width:100%;max-width:100%;height:auto;margin:0;float:none\"><\/div><figcaption class=\"wh-caption\" id=\"wh-caption-detail1\" style=\"display:block;margin:0;padding:12px 18px 15px;border-top:1px solid #dce5e9;color:#506575;background:#f5f8fa;font-size:14px;line-height:1.55;text-align:start\">Keys und fachliche Argumente folgen getrennten Wegen in die serverseitige Logik.<\/figcaption><\/figure><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Jeder Key, den das Script liest oder schreibt, muss vorab als Key-Argument angegeben werden. Key-Namen im Script aus Pr\u00e4fixen zusammenzusetzen oder aus gespeicherten Daten abzuleiten, ist kein belastbares Muster. Redis kann dann insbesondere bei Redis Open Source mit aktiviertem Cluster nicht vor der Ausf\u00fchrung nachvollziehen, welche Daten das Script ben\u00f6tigt. \u00dcbergib daher bekannte Schl\u00fcssel vollst\u00e4ndig \u00fcber KEYS und variable Fachwerte ausschlie\u00dflich \u00fcber ARGV.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Bei Redis Open Source mit aktiviertem Cluster m\u00fcssen die einem Script \u00fcbergebenen Keys au\u00dferdem im selben Hash Slot liegen. Die vorherige Deklaration erm\u00f6glicht diese Pr\u00fcfung, ersetzt sie aber nicht. F\u00fcr zusammengeh\u00f6rige Daten kann ein bewusst gew\u00e4hlter Hash Tag helfen, etwa <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">account:{4711}:balance<\/code> und <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">account:{4711}:reservations<\/code>. Der Teil in geschweiften Klammern bestimmt hier die Slot-Zuordnung; dynamisch ermittelte Keys w\u00fcrden diese Planung unterlaufen.  <\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"limitexample\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"limitexample\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Fixed-Window-Z\u00e4hler atomar aktualisieren<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Das folgende Beispiel ist ein atomarer <strong style=\"font-weight:700;color:inherit\">Fixed-Window-Z\u00e4hler<\/strong> f\u00fcr eine lokale Testinstanz. Es pr\u00fcft Z\u00e4hlerstand und Grenze in einem Serverlauf und setzt die Ablaufzeit nur beim ersten erfolgreichen Zugriff des Zeitfensters. Damit entf\u00e4llt das Zeitfenster zwischen einem GET im Anwendungscode und einem sp\u00e4teren INCR, in dem ein anderer Client den Z\u00e4hler ver\u00e4ndern k\u00f6nnte.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Der Aufruf \u00fcbergibt den Z\u00e4hler-Key, das Limit und die Fensterdauer in Sekunden. Status 1 bedeutet zugelassen, Status 0 bedeutet Limit erreicht. Status 2 meldet eine von den Vorpr\u00fcfungen erkannte ung\u00fcltige Eingabe, einen dort abgelehnten String-Z\u00e4hlerwert oder einen vorhandenen String-Z\u00e4hler ohne TTL. Enth\u00e4lt der Key einen anderen Redis-Datentyp, scheitert bereits GET mit einem technischen Typfehler; das Script liefert dann keinen Status 2. Auch andere Redis-Laufzeitfehler sind vom fachlichen R\u00fcckgabestatus zu unterscheiden. Das Beispiel ist keine Vorlage f\u00fcr Zugangsdaten, produktive Limits oder Lasttests.<\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Vor jeder Schreiboperation validiert das Script alle Zahlen als endliche positive Ganzzahlen innerhalb einer bewusst kleinen Obergrenze. Das ist mehr als eine Pr\u00fcfung mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">tonumber<\/code>: Werte wie <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">1.5<\/code> oder <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">1e3<\/code> werden abgelehnt. Die Grenze von einer Million verhindert zudem, dass Lua-Zahlenpr\u00e4zision oder der von <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">INCR<\/code> erwartete Integer-String au\u00dferhalb des Beispielsbereichs relevant werden. Die maximale Fensterdauer von 86.400 Sekunden begrenzt auch die an <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EXPIRE<\/code> \u00fcbergebene Sekundenzahl.<\/p>\n<div class=\"wh-code-window\" data-wh-code style=\"margin:28px 0 34px;border:1px solid #2c4656;border-radius:12px;overflow:hidden;background:#132a3b;box-shadow:0 9px 25px -13px rgba(15,35,55,.2)\"><div class=\"wh-code-toolbar\" style=\"display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px;padding:11px 16px;background:#223e50;color:#edf5fa;font-size:13px;line-height:1.5;font-weight:600\"><span>Code<\/span><button type=\"button\" class=\"wh-code-copy\" data-wh-copy hidden style=\"padding:6px 11px;border:1px solid #7893a1;border-radius:6px;background:transparent;color:#fff;font-size:12px;line-height:1.5;font-weight:600;cursor:pointer\">Code kopieren<\/button><span class=\"wh-copy-status\" aria-live=\"polite\"><\/span><span data-wh-copy-success hidden>Kopiert<\/span><span data-wh-copy-fallback hidden>Code markiert \u2013 bitte kopieren<\/span><\/div><pre class=\"wh-code\" data-no-translation translate=\"no\" style=\"display:block;margin:0;padding:20px;max-width:100%;overflow-x:auto;color:#edf5fa;background:#132a3b;font:14px\/1.75 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre;direction:ltr;text-align:left\"><code class=\"language-redis-cli\" style=\"font:inherit;color:inherit;background:transparent;padding:0;border:0;white-space:inherit\">EVAL &quot;local max_counter = 1000000; local max_window = 86400; local function positive_integer(value, maximum) if type(value) ~= &#039;string&#039; or not string.match(value, &#039;^%d+$&#039;) then return nil; end; local number = tonumber(value); if not number or number ~= math.floor(number) or number &lt; 1 or number &gt; 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, &#039;invalid-arguments&#039;}; end; local raw = redis.call(&#039;GET&#039;, KEYS[1]); if raw and (type(raw) ~= &#039;string&#039; or not string.match(raw, &#039;^%d+$&#039;)) then return {2, &#039;invalid-counter&#039;}; end; local current = raw and tonumber(raw) or 0; if not current or current ~= math.floor(current) or current &lt; 0 or current &gt; max_counter then return {2, &#039;invalid-counter&#039;}; end; if raw and redis.call(&#039;TTL&#039;, KEYS[1]) == -1 then return {2, &#039;missing-ttl&#039;}; end; if current &gt;= limit then return {0, current}; end; local next = redis.call(&#039;INCR&#039;, KEYS[1]); if next == 1 then redis.call(&#039;EXPIRE&#039;, KEYS[1], window); end; return {1, next}&quot; 1 demo:rate-limit 3 60<\/code><\/pre><\/div><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Der regul\u00e4re Ausdruck akzeptiert nur dezimale Ziffern; anschlie\u00dfend pr\u00fcft die Hilfsfunktion den Zahlenwert, die Ganzzahligkeit und die Obergrenze. Ein bereits vorhandener Z\u00e4hler darf nur ein nichtnegativer Ganzzahlwert im selben begrenzten Bereich sein. Dadurch kann ein negativer, gebrochener oder \u00fcbergro\u00dfer Wert die Limitsemantik nicht unbemerkt ver\u00e4ndern. Erst nach diesen Pr\u00fcfungen folgt <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">INCR<\/code>.<\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Ist der Key nicht vorhanden, beginnt das Script bei 0. Existiert bereits ein g\u00fcltiger String-Z\u00e4hler ohne Ablaufzeit, liefert es Status 2 und schreibt nichts. Nach dem ersten <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">INCR<\/code> setzt <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EXPIRE<\/code> die zuvor vollst\u00e4ndig gepr\u00fcfte TTL. Bei sp\u00e4teren Treffern bleibt sie unver\u00e4ndert, sodass das Fenster nicht fortlaufend verl\u00e4ngert wird.   <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Der <strong style=\"font-weight:700;color:inherit\">R\u00fcckgabevertrag<\/strong> ist Teil der Schnittstelle: Das erste Array-Element beschreibt den Status, das zweite liefert je nach Status den Z\u00e4hlerstand oder eine Fehlerkennung. Der aufrufende Code sollte eine fachliche Ablehnung mit Status 0 anders behandeln als Status 2, der auf eine verletzte Voraussetzung hinweist. F\u00fcr weitere Informationen zur Wahl und Beobachtung von Ablaufzeiten ist der Artikel <a href=\"https:\/\/webhosting.de\/redis-key-expiration-performance-analysieren-optimieren-cache\/\">Redis Key Expiration analysieren und optimieren<\/a> eine erg\u00e4nzende Grundlage.<\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Die TTL wird hier bewusst nur beim ersten Treffer gesetzt. Ein Muster, das sie bei jedem Zugriff erneuert, h\u00e4tte eine andere Zeitsemantik und w\u00e4re kein Fixed Window mehr. <strong style=\"font-weight:700;color:inherit\">Lua-Atomizit\u00e4t<\/strong> beseitigt nur die Race Condition. Ob Fixed Window, Sliding Window oder Token Bucket zur gew\u00fcnschten Fairness und Lastverteilung passt, entscheidet der gew\u00e4hlte Algorithmus, nicht die Scriptsprache.  <\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"mechanisms\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"mechanisms\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Passendes Atomizit\u00e4tsmodell ausw\u00e4hlen<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Nicht jede zusammengesetzte Anforderung ben\u00f6tigt ein Script. Existiert ein einzelner Redis-Befehl, der die Fachregel bereits vollst\u00e4ndig ausdr\u00fcckt, ist er meist einfacher zu betreiben und zu pr\u00fcfen. F\u00fcr mehrstufige Regeln m\u00fcssen dagegen Bedingungen, Datentypen und R\u00fcckgabevertrag gemeinsam betrachtet werden. <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Ab Redis Open Source 8.4 gibt es native Compare-and-Set- und Compare-and-Delete-Operationen f\u00fcr einzelne String-Keys: <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">SET<\/code> unterst\u00fctzt die Vergleichsoptionen <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">IFEQ\/IFNE\/IFDEQ\/IFDNE<\/code>; <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">DELEX<\/code> \u00fcbernimmt bedingtes L\u00f6schen. F\u00fcr passende Einzel-Key-F\u00e4lle ist damit kein eigenes Vergleichsscript erforderlich. In Redis 8.2, 8.0 und 7.x stehen diese neuen SET-Optionen und DELEX nicht zur Verf\u00fcgung; dort bleiben passende WATCH- oder Lua-Muster relevant.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">F\u00fcr optimistisches Compare-and-Set kann WATCH vor MULTI und EXEC passend sein: \u00c4ndert ein beobachteter Key sich vor EXEC, wird die Transaktion abgebrochen, und der Client entscheidet \u00fcber einen erneuten Versuch. Auch Transaktionen bieten bei Fehlern w\u00e4hrend EXEC keinen allgemeinen Rollback. WATCH bleibt daher eine Option, wenn die notwendige Bedingung nicht durch einen einzelnen nativen Befehl abgebildet wird.  <\/p>\n<div class=\"wh-table-scroll\" tabindex=\"0\" role=\"region\" aria-label=\"Atomizit\u00e4tsmodelle f\u00fcr Redis-Operationen im Vergleich\" style=\"width:100%;max-width:100%;overflow-x:auto;margin:28px 0;border:1px solid #dce5e9;border-radius:14px;background:#fff;box-shadow:0 10px 28px -16px rgba(24,47,60,.32);box-sizing:border-box\"><table style=\"width:100%;min-width:580px;border-collapse:separate;border-spacing:0;border:0;margin:0;font-size:15px;line-height:1.6;background:#fff\"><caption style=\"padding:20px;text-align:start;font-size:17px;line-height:1.5;font-weight:700;color:#173246;background:#fff\">Atomizit\u00e4tsmodelle f\u00fcr Redis-Operationen im Vergleich<\/caption><thead><tr><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Modell<\/th><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Geeigneter Einsatzfall<\/th><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Code und Aufruf<\/th><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Nach Neustart oder Failover<\/th><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Client-Verhalten und Grenze<\/th><\/tr><\/thead><tbody><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Nativer Befehl<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Eine vorhandene Einzeloperation bildet die Regel ab<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Kein Programmcode; direkter Befehl<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Kein Script-Cache betroffen<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Keine Script-Nachladung; auf vorhandene Semantik begrenzt<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Native CAS\/CAD ab Redis Open Source 8.4<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Wertabh\u00e4ngiges Setzen oder L\u00f6schen eines einzelnen String-Keys<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">SET mit IFEQ\/IFNE\/IFDEQ\/IFDNE; DELEX mit Vergleichsbedingung<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Kein Script-Cache betroffen<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Versionsgrenze und Vergleichsbedingung pr\u00fcfen; keine zusammengesetzte Mehr-Key-Regel<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">MULTI\/EXEC mit WATCH<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Optimistisches Lesen, Pr\u00fcfen und Schreiben<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">WATCH, MULTI, EXEC<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Kein Programmspeicher<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Bei \u00c4nderung vor EXEC erneut lesen und entscheiden; kein Rollback bei EXEC-Fehlern<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">EVAL<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Kleines, unmittelbar aufgerufenes Script<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Quelltext bei jedem EVAL<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Script-Cache ist nicht dauerhaft<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Keine Digest-Nachladung; Quelltext wird wieder \u00fcbertragen<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">SCRIPT LOAD plus EVALSHA<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Wiederverwendetes Script mit bekanntem Digest<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Laden, danach Aufruf per SHA1-Digest<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Cache kann fehlen<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">NOSCRIPT behandeln und erneut laden; Pipeline-Fallback besonders planen<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Redis Functions ab 7.0<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Benannte, wiederverwendbare Datenlogik<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">FUNCTION LOAD, danach FCALL<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Bibliotheken werden repliziert und persistiert<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Versions- und Bereitstellungsprozess n\u00f6tig; nicht mit EVAL gleichsetzen<\/td><\/tr><\/tbody><\/table><\/div><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">EVAL-Scripts sind an den Script-Cache gebunden und erhalten ihre Eingaben \u00fcber KEYS und ARGV. <strong style=\"font-weight:700;color:inherit\">Redis Functions<\/strong> gibt es ab Redis 7.0 als benannte Bibliotheken: Sie werden mit FUNCTION LOAD registriert, mit FCALL aufgerufen sowie zusammen mit der Datenbank persistiert und repliziert. Ihre Schl\u00fcssel und Argumente erreichen die Funktion als Parameter; daraus folgt ein anderes Bereitstellungs- und Aufrufmodell als bei EVAL.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">F\u00fcr anwendungsnahe, kleine Logik ist EVAL daher ein direkter Einstieg. Mehrere Clients und langfristig gepflegte Datenlogik sprechen h\u00e4ufig f\u00fcr Functions, sofern die eingesetzte Redis-Open-Source-Version sie unterst\u00fctzt. Die Entscheidung sollte au\u00dferdem Deployment, Berechtigungen, Fehlerbehandlung und eine eindeutig dokumentierte R\u00fcckgabe ber\u00fccksichtigen, nicht nur die Zahl der Redis-Befehle.  <\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"clustererrors\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"clustererrors\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Cluster, Fehler und R\u00fcckgabevertr\u00e4ge<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Bei Redis Open Source mit aktiviertem Cluster m\u00fcssen die \u00fcbergebenen Keys eines Mehr-Key-Scripts im selben Hash Slot liegen. Hash Tags machen das steuerbar: Bei <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">account:{4711}:balance<\/code> und <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">account:{4711}:reservations<\/code> bestimmt der Inhalt zwischen geschweiften Klammern den Slot. Beide Keys k\u00f6nnen deshalb gemeinsam angesprochen werden. Die Same-Slot-Voraussetzung gilt dort auch f\u00fcr die hier betrachteten Mehrschl\u00fcsseloperationen und MULTI\/EXEC-Transaktionen. Andere Produkt- und Clusterkonfigurationen k\u00f6nnen bei einzelnen Befehlen abweichen. Daraus folgt keine allgemeine Cross-Slot-Freigabe f\u00fcr Lua: Die Mehrschl\u00fcssel-Dokumentation ordnet EVAL\/EVALSHA auch bei Redis Software mit aktiviertem Cluster und mit oder ohne OSS Cluster API als Single-Slot-Operation ein.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Alle verwendeten Schl\u00fcssel m\u00fcssen vor dem Aufruf als Key-Argumente deklariert werden. Ein Script darf Key-Namen nicht aus gespeicherten Werten ableiten oder dynamisch zusammensetzen. Diese Regel erm\u00f6glicht Redis die korrekte Slot-Pr\u00fcfung vor der Ausf\u00fchrung und verhindert verdeckte Abh\u00e4ngigkeiten, die in einer Standalone-Instanz unauff\u00e4llig bleiben, bei Redis Open Source mit aktiviertem Cluster aber scheitern.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">redis.call()<\/code> wird ein Fehler des aufgerufenen Redis-Kommandos als Scriptfehler an den Client weitergegeben. <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">redis.pcall()<\/code> liefert ihn dagegen an Lua zur\u00fcck, damit das Script ihn gezielt behandeln kann. pcall ist nur sinnvoll, wenn eine fachliche Reaktion definiert ist, etwa eine sauber strukturierte Fehlerantwort oder ein alternativer zul\u00e4ssiger Ablauf. Fehler still zu ignorieren verschleiert Daten- und Integrit\u00e4tsprobleme.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Ein <strong style=\"font-weight:700;color:inherit\">Fehlervertrag<\/strong> trennt technische Fehler von fachlichen Ergebnissen. WRONGTYPE bedeutet etwa, dass der gespeicherte Redis-Datentyp nicht zum erwarteten Befehl passt und untersucht werden muss. Eine abgelehnte Reservierung wegen fehlenden Bestands ist dagegen ein erwartetes Ergebnis und kann beispielsweise Status und Restbestand zur\u00fcckgeben. Anwendungen sollten diese Kategorien nicht gleich behandeln oder beide pauschal wiederholen.  <\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"delivery\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"delivery\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Script-Auslieferung robust betreiben<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVAL<\/code> eignet sich f\u00fcr unmittelbare Aufrufe: Der Client \u00fcbertr\u00e4gt den vollst\u00e4ndigen Lua-Quelltext zusammen mit Key- und Argumentwerten. F\u00fcr ein h\u00e4ufig verwendetes, unver\u00e4ndertes Script kann die Anwendung es stattdessen mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">SCRIPT LOAD<\/code> in den Script-Cache laden. Redis liefert daf\u00fcr einen SHA1-Digest zur\u00fcck; <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVALSHA<\/code> f\u00fchrt anschlie\u00dfend genau den dazugeh\u00f6rigen Quelltext aus. Das spart die wiederholte \u00dcbertragung, \u00e4ndert aber weder die Atomizit\u00e4t noch die fachliche Verantwortung des Scripts. <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Der <strong style=\"font-weight:700;color:inherit\">Script-Cache<\/strong> ist nicht dauerhaft. Nach einem Neustart, Failover oder <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">SCRIPT FLUSH<\/code> kann ein Aufruf per Digest mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">NOSCRIPT<\/code> scheitern. Die Anwendung sollte diesen Fall regul\u00e4r behandeln: Script erneut laden und den fachlich sicheren Aufruf wiederholen, sofern die eigene Retry-Logik das zul\u00e4sst. Ein Digest darf daher nicht als Zusage verstanden werden, dass das Script auf jedem Zielserver bereits vorhanden ist. <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Bei Pipelines ist dieser Fallback eingeschr\u00e4nkt. Sind mehrere Befehle bereits gemeinsam gesendet, kann die Anwendung einen darin auftretenden <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">NOSCRIPT<\/code>-Fehler nicht r\u00fcckwirkend durch Laden und erneutes Ausf\u00fchren an derselben Stelle ersetzen. Redis empfiehlt f\u00fcr solche F\u00e4lle parameterisiertes <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVAL<\/code> als Ausweichstrategie. Wer Replikation und Failover plant, sollte au\u00dferdem verstehen, welche Rolle der Replikationspuffer bei der Wiederanbindung einer Replica spielt: <a href=\"https:\/\/webhosting.de\/redis-replication-backlog-verstehen\/\">Redis Replication Backlog verstehen<\/a>. <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Variable Werte geh\u00f6ren nicht in den Lua-Quelltext, sondern in <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">ARGV<\/code>. Andernfalls erzeugt etwa jeder Grenzwert ein anderes Script und vergr\u00f6\u00dfert den Cache unn\u00f6tig. Seit Redis 7.4 k\u00f6nnen per <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVAL<\/code> oder <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVAL_RO<\/code> geladene Scripts bei einer Cache-Grenze nach LRU entfernt werden; das ersetzt weder Parametrisierung noch die Behandlung von <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">NOSCRIPT<\/code>. <\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"operations\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"operations\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Lange Scripts und Schreibfehler beherrschen<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Ein Lua-Script blockiert w\u00e4hrend seiner regul\u00e4ren Ausf\u00fchrung andere Serveraktivit\u00e4ten. Das schafft Isolation, wird bei langen Laufzeiten aber zum <strong style=\"font-weight:700;color:inherit\">Betriebsrisiko<\/strong>. \u00dcberschreitet ein Script den konfigurierten <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">busy-reply-threshold<\/code>, antwortet Redis auf normale Befehle mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">BUSY<\/code>; es beendet das Script nicht automatisch. Beschr\u00e4nke Scripts deshalb auf wenige bekannte Keys und kleine, begrenzte Berechnungen.  <\/p>\n<figure class=\"wp-block-image size-large wh-figure\" aria-describedby=\"wh-caption-detail2\" style=\"display:block;float:none;clear:both;width:100%;max-width:760px;margin:34px auto 40px;border:1px solid #dae5e9;border-radius:14px;overflow:hidden;background:#f5f8fa;box-shadow:0 10px 28px -17px rgba(24,47,60,.28);box-sizing:border-box\"><div class=\"wh-figure-media\" style=\"display:block;background:#eef3f5;line-height:0\"><img loading=\"lazy\" width=\"800\" height=\"534\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-lange-scripts-risiko-d0a32bc8-detail2-9444d828df-1024x683.webp\" class=\"wp-image-21682\" alt=\"Konzeptioneller Vergleich eines kurzen Redis Lua Scripts mit einem langen blockierenden Ablauf.\" loading=\"lazy\" decoding=\"async\" srcset=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-lange-scripts-risiko-d0a32bc8-detail2-9444d828df-1024x683.webp 1024w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-lange-scripts-risiko-d0a32bc8-detail2-9444d828df-300x200.webp 300w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-lange-scripts-risiko-d0a32bc8-detail2-9444d828df-768x512.webp 768w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-lange-scripts-risiko-d0a32bc8-detail2-9444d828df-18x12.webp 18w, https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/redis-lua-lange-scripts-risiko-d0a32bc8-detail2-9444d828df.webp 1536w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/ style=\"display:block;width:100%;max-width:100%;height:auto;margin:0;float:none\"><\/div><figcaption class=\"wh-caption\" id=\"wh-caption-detail2\" style=\"display:block;margin:0;padding:12px 18px 15px;border-top:1px solid #dce5e9;color:#506575;background:#f5f8fa;font-size:14px;line-height:1.55;text-align:start\">Kurze, begrenzte Script-Abl\u00e4ufe senken das Risiko blockierter Client-Anfragen.<\/figcaption><\/figure><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Schreiboperationen vor einem Fehler oder einer Endlosschleife sind besonders kritisch. Hat ein Script bereits Daten ver\u00e4ndert, kann <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">SCRIPT KILL<\/code> es nicht sicher beenden. Pr\u00fcfe Eingaben daher vor dem ersten Schreiben und vermeide unbeschr\u00e4nkte Schleifen sowie <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">SCAN<\/code> \u00fcber Gesamtbest\u00e4nde. Tests sollten Datenvolumen und Fehlerpfade des geplanten Einsatzes abbilden.  <\/p>\n<div class=\"wh-table-scroll\" tabindex=\"0\" role=\"region\" aria-label=\"Fehlerf\u00e4lle bei Redis Lua Scripts und sichere Reaktion der Anwendung\" style=\"width:100%;max-width:100%;overflow-x:auto;margin:28px 0;border:1px solid #dce5e9;border-radius:14px;background:#fff;box-shadow:0 10px 28px -16px rgba(24,47,60,.32);box-sizing:border-box\"><table style=\"width:100%;min-width:580px;border-collapse:separate;border-spacing:0;border:0;margin:0;font-size:15px;line-height:1.6;background:#fff\"><caption style=\"padding:20px;text-align:start;font-size:17px;line-height:1.5;font-weight:700;color:#173246;background:#fff\">Fehlerf\u00e4lle bei Redis Lua Scripts und sichere Reaktion der Anwendung<\/caption><thead><tr><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Fall<\/th><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Erkennbare Antwort<\/th><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Typische Ursache<\/th><th scope=\"col\" style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#19394d;color:#fff\">Sichere Konsequenz<\/th><\/tr><\/thead><tbody><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">NOSCRIPT<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Fehlerantwort NOSCRIPT<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Digest fehlt im fl\u00fcchtigen Script-Cache<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Script laden oder parameterisiertes EVAL verwenden; nur nach eigener Retry-Regel wiederholen.<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">CROSSSLOT<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">CROSSSLOT bei Redis Open Source mit aktiviertem Cluster<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Die \u00fcbergebenen Keys des Scripts liegen in verschiedenen Hash Slots<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Key-Design \u00e4ndern und alle erforderlichen Keys deklarieren.<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">WRONGTYPE<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Redis-Fehler WRONGTYPE<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Key besitzt einen unerwarteten Datentyp<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Datenmodell oder Script-Voraussetzung korrigieren; nicht als fachliche Ablehnung behandeln.<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Speicherdruck \u00fcber maxmemory<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Schreiboperation kann das Script abbrechen<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Redis liegt beim Start bereits \u00fcber dem Speicherlimit<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Nicht blind wiederholen; bei redis.pcall einen sicheren, dokumentierten Fehlerpfad vorsehen.<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">BUSY<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Fehlerantwort BUSY f\u00fcr andere Befehle<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Script \u00fcberschreitet den busy-reply-threshold<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#fff;color:#294252\">Last reduzieren und Script verkleinern; nach Schreibvorg\u00e4ngen nicht auf Killen bauen.<\/td><\/tr><tr><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Fachliche Ablehnung<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Dokumentierter Statuswert<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Etwa Limit erreicht oder Bestand zu niedrig<\/td><td style=\"padding:15px 18px;border:0;border-bottom:1px solid #e2e9ed;text-align:start;vertical-align:top;white-space:normal;font-size:15px;line-height:1.6;background:#f4f7f9;color:#294252\">Status auswerten und den Gesch\u00e4ftsvorgang geordnet ablehnen.<\/td><\/tr><\/tbody><\/table><\/div><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Bei <strong style=\"font-weight:700;color:inherit\">maxmemory<\/strong> h\u00e4ngt der Ablauf von der ersten Schreiboperation ab. Liegt Redis bereits \u00fcber dem Limit, kann ein speicherverbrauchender Befehl bei <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">redis.call<\/code> das Script abbrechen; <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">redis.pcall<\/code> liefert den Fehler an Lua zur\u00fcck und verlangt einen bewusst entworfenen Fehlerpfad. Bereits ausgef\u00fchrte \u00c4nderungen werden dadurch nicht repariert.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Eine erste Operation ohne zus\u00e4tzlichen Speicherbedarf, etwa <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">DEL<\/code> oder <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">LREM<\/code>, kann das Script dagegen weiterlaufen lassen; sp\u00e4tere Schreibvorg\u00e4nge k\u00f6nnen den Verbrauch \u00fcber <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">maxmemory<\/code> erh\u00f6hen. Technische Fehler wie <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">WRONGTYPE<\/code> oder <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">CROSSSLOT<\/code> bei Redis Open Source mit aktiviertem Cluster verlangen Korrekturen am Datenmodell beziehungsweise Key-Design, w\u00e4hrend nur das Script selbst eine fachliche Ablehnung als stabilen Status definieren kann.    <\/p>\n<\/section><section class=\"wh-section\" aria-labelledby=\"decisions\" style=\"display:block;margin:0 0 36px;min-width:0\"><h2 id=\"decisions\" style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Geeignete Einsatzf\u00e4lle bewusst entscheiden<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">F\u00fcr eine bedingte Reservierung kann ein Script Bestand pr\u00fcfen, einen zu kleinen Wert ablehnen und bei Erfolg den Restbestand zur\u00fcckgeben. Die <strong style=\"font-weight:700;color:inherit\">atomare Reservierung<\/strong> umfasst jedoch nur Redis. Zahlung, relationale Datenbank, E-Mail und externe APIs ben\u00f6tigen eine eigene Abstimmung und gegebenenfalls Ausgleichslogik.  <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Die Auswahl h\u00e4ngt von Redis-Version und Datenmodell ab. Ab Redis Open Source 8.4 k\u00f6nnen die Vergleichsoptionen von <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">SET<\/code> ein bedingtes Setzen und <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">DELEX<\/code> das Vergleich-und-L\u00f6schen eines einzelnen String-Keys \u00fcbernehmen. Vor Redis 8.4 oder bei einer komplexeren Bedingung ist <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">WATCH<\/code> mit <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">MULTI\/EXEC<\/code> eine Alternative: \u00c4ndert sich ein beobachteter Key vor EXEC, bricht die Transaktion ab und der Client entscheidet \u00fcber erneutes Lesen und Wiederholen. Ein kurzes Lua-Script passt, wenn mehrere Befehle oder Datenstrukturen einschlie\u00dflich ihrer Fachregel serverseitig zusammenwirken m\u00fcssen.   <\/p>\n<p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">F\u00fcr verteilte Sperren gen\u00fcgt weder der einzelne Befehl noch das Lua-Muster als Gesamtkonzept. Lease-Dauer, Prozesspausen, Ausf\u00e4lle, Wiederholungen, Failover und Mehrinstanzenszenarien bleiben separat zu bewerten. Bevorzuge einen nativen Befehl, wenn die betriebene Version und seine Semantik die gesamte Regel abdecken. Andernfalls sind <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">WATCH<\/code> und ein kurzes Script je nach Fehlervertrag und Ort der Fachlogik abzuw\u00e4gen. F\u00fcr wiederverwendbare serverseitige Logik kann eine Redis Function passen. <strong style=\"font-weight:700;color:inherit\">Read-only-Scripts<\/strong> d\u00fcrfen ab Redis 7.0 \u00fcber <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVAL_RO<\/code> oder <code data-no-translation style=\"font:600 .87em\/1.5 ui-monospace,monospace;color:#235063;background:#edf3f5;border-radius:4px;padding:.1em .3em\">EVALSHA_RO<\/code> laufen, aber nur bei garantiert schreibfreier Logik.   <\/p>\n<\/section><section class=\"wh-sources\" style=\"margin:40px 0 0;padding:24px 0 0;border-top:1px solid #dce5e9;color:#596b7b;font-size:14px;line-height:1.65\"><h2 style=\"margin:38px 0 18px;color:#172f41;font-size:clamp(24px,1.25rem + 1vw,30px);font-weight:700;line-height:1.3;scroll-margin-top:115px\">Quellen und fachlicher Stand<\/h2><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Recherche-Stand: <time datetime=\"2026-09-23\">2026-09-23<\/time><\/p><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\">Recherche- und Versionsstand: 23. September 2026. Der Artikel behandelt Redis Open Source und unterscheidet EVAL-Scripts von Redis Functions ab Redis 7.0. Versionsgrenzen und verf\u00fcgbare Befehle vor dem Einsatz gegen die konkret betriebene Redis-Version pr\u00fcfen.<\/p><div class=\"wh-source-urls\"><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><span class=\"wh-source-url\" data-no-translation dir=\"ltr\" style=\"overflow-wrap:anywhere;font:12px\/1.6 ui-monospace,monospace;direction:ltr\">https:\/\/redis.io\/docs\/latest\/develop\/programmability\/eval-intro\/<\/span><\/p><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><span class=\"wh-source-url\" data-no-translation dir=\"ltr\" style=\"overflow-wrap:anywhere;font:12px\/1.6 ui-monospace,monospace;direction:ltr\">https:\/\/redis.io\/docs\/latest\/develop\/programmability\/<\/span><\/p><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><span class=\"wh-source-url\" data-no-translation dir=\"ltr\" style=\"overflow-wrap:anywhere;font:12px\/1.6 ui-monospace,monospace;direction:ltr\">https:\/\/redis.io\/docs\/latest\/commands\/eval\/<\/span><\/p><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><span class=\"wh-source-url\" data-no-translation dir=\"ltr\" style=\"overflow-wrap:anywhere;font:12px\/1.6 ui-monospace,monospace;direction:ltr\">https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/multi-key-operations\/<\/span><\/p><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><span class=\"wh-source-url\" data-no-translation dir=\"ltr\" style=\"overflow-wrap:anywhere;font:12px\/1.6 ui-monospace,monospace;direction:ltr\">https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/transactions\/<\/span><\/p><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><span class=\"wh-source-url\" data-no-translation dir=\"ltr\" style=\"overflow-wrap:anywhere;font:12px\/1.6 ui-monospace,monospace;direction:ltr\">https:\/\/redis.io\/docs\/latest\/develop\/programmability\/functions-intro\/<\/span><\/p><p style=\"margin:0 0 1.1em;font-size:inherit;line-height:inherit\"><span class=\"wh-source-url\" data-no-translation dir=\"ltr\" style=\"overflow-wrap:anywhere;font:12px\/1.6 ui-monospace,monospace;direction:ltr\">https:\/\/redis.io\/docs\/latest\/commands\/evalsha_ro\/<\/span><\/p><\/div><\/section><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Skrypty Lua w Redis \u0142\u0105cz\u0105 odczyt, sprawdzanie i zapis w jedn\u0105 izolowan\u0105 operacj\u0119 serwera. Artyku\u0142 wyja\u015bnia poj\u0119cia KEYS i ARGV, EVAL i funkcje, ograniczenia klastra, umowy dotycz\u0105ce b\u0142\u0119d\u00f3w, a tak\u017ce bezpieczne wzorce dotycz\u0105ce limit\u00f3w i rezerwacji.<\/p>","protected":false},"author":1,"featured_media":21680,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[781],"tags":[],"class_list":["post-21670","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-datenbanken-administration-anleitungen"],"acf":[],"_wp_attached_file":null,"_wp_attachment_metadata":null,"surfer_file_name":null,"surfer_file_original_url":null,"_wp_attachment_image_alt":null,"litespeed-optimize-set":null,"litespeed-optimize-size":null,"_oembed_b5e1eb923ad3b086e579b1befcd4075c":null,"_elementor_source_image_hash":null,"stockpack_author_name":null,"stockpack_author_url":null,"stockpack_provider":null,"stockpack_image_url":null,"stockpack_license":null,"stockpack_license_url":null,"stockpack_modification":null,"color":null,"original_id":null,"original_url":null,"original_link":null,"unsplash_location":null,"unsplash_sponsor":null,"unsplash_exif":null,"unsplash_attachment_metadata":null,"_elementor_is_screenshot":null,"_source_url":null,"_elementor_migrations_state_8b2d":null,"envato_tk_source_kit":null,"envato_tk_source_index":null,"envato_tk_manifest":null,"envato_tk_folder_name":null,"envato_tk_builder":null,"envato_elements_download_event":null,"_menu_item_type":null,"_menu_item_menu_item_parent":null,"_menu_item_object_id":null,"_menu_item_object":null,"_menu_item_target":null,"_menu_item_classes":null,"_menu_item_xfn":null,"_menu_item_url":null,"_trp_menu_languages":null,"rank_math_primary_category":"781","_wh_make_key":"wh_d0a32bc890a88f7177d90d38456c834e","rank_math_internal_links_processed":"1","_wh_make_topic":"Redis Lua Scripts f\u00fcr atomare Operationen","_wh_make_input_keywords":["redis lua scripts","redis automation","cache scripting"],"_wh_make_config":{"research_model":"gpt-5.6-terra","writer_model":"gpt-5.6-terra","review_model":"gpt-5.6-sol","image_model":"gpt-image-2.5-flare","image_quality":"medium","image_format":"webp","final_status":"draft","charts_enabled":true},"_wh_make_links":{"I1":{"id":"I1","post_id":21633,"url":"https:\/\/webhosting.de\/redis-replication-backlog-verstehen\/","title":"Zrozumienie zaleg\u0142o\u015bci replikacji w Redis: PSYNC, rozmiar i ograniczenia dotycz\u0105ce wysokiej dost\u0119pno\u015bci","excerpt":"Bufor replikacji Redis ma wp\u0142yw na to, czy po zerwaniu po\u0142\u0105czenia replika pobierze jedynie brakuj\u0105ce zmiany, czy te\u017c otrzyma ponownie ca\u0142y zbi\u00f3r danych. Dostosowuj\u0105c rozmiar bufora do rzeczywistej obj\u0119to\u015bci replikacji, mo\u017cna unikn\u0105\u0107 niepotrzebnych pe\u0142nych synchronizacji. Wymaga to jednak sp\u00f3jno\u015bci historii replikacji, bud\u017cetu pami\u0119ci i proces\u00f3w operacyjnych: du\u017cy backlog nie zast\u0119puje ani trwa\u0142o\u015bci danych, ani niezawodnej koncepcji prze\u0142\u0105czania awaryjnego. Przejd\u017a bezpo\u015brednio do sekcji: Co faktycznie przechowuje bufor zaleg\u0142o\u015bci? Kiedy wystarczy PSYNC, a kiedy konieczna jest pe\u0142na resynchronizacja? Pomiar cz\u0119stotliwo\u015bci replikacji zamiast szacowania rozmiaru bazy danych. Przejrzyste obliczanie rozmiaru bufora zaleg\u0142o\u015bci. Zrozumia\u0142e i kontrolowane zmiany w konfiguracji Redis. Monitorowanie: Kt\u00f3re warto\u015bci s\u0105 ze sob\u0105 powi\u0105zane Prawid\u0142owe klasyfikowanie bud\u017cetu pami\u0119ci i wolnych replik Dlaczego du\u017cy backlog nie gwarantuje jeszcze wysokiej dost\u0119pno\u015bci Testowanie zmian i zaw\u0119\u017canie powtarzaj\u0105cych si\u0119 problem\u00f3w Co faktycznie przechowuje backlog W przypadku replikacji Redis serwer g\u0142\u00f3wny przetwarza zmiany w zbiorze danych i przesy\u0142a ci\u0105g\u0142y strumie\u0144 polece\u0144 do swoich replik. Obejmuje to nie tylko warto\u015bci zapisywane bezpo\u015brednio przez klient\u00f3w. R\u00f3wnie\u017c wygas\u0142e lub wypchni\u0119te klucze mog\u0105 wywo\u0142ywa\u0107 zmiany, kt\u00f3re musz\u0105 zosta\u0107 przekazane. Backlog przechowuje w pami\u0119ci operacyjnej ograniczony, najnowszy fragment tego strumienia replikacji. Dlatego nie zawiera on dodatkowej pe\u0142nej kopii bazy danych ani nie jest archiwum operacji zapisu o dowolnym wieku. Podczas bezawaryjnej pracy repliki pod\u0105\u017caj\u0105 za bie\u017c\u0105cym strumieniem. Je\u015bli po\u0142\u0105czenie zostanie przerwane, historia na serwerze g\u0142\u00f3wnym nadal si\u0119 wyd\u0142u\u017ca. Po ponownym nawi\u0105zaniu po\u0142\u0105czenia replika pr\u00f3buje pod\u0142\u0105czy\u0107 si\u0119 do dotychczasowego stanu. Decyduj\u0105ce znaczenie ma wtedy to, czy wymagane bajty s\u0105 nadal przechowywane. Je\u015bli tak jest i historia replikacji jest zgodna, Redis mo\u017ce uzupe\u0142ni\u0107 brakuj\u0105ce dane. Ju\u017c istniej\u0105ce"},"I2":{"id":"I2","post_id":21597,"url":"https:\/\/webhosting.de\/redis-key-expiration-performance-analysieren-optimieren-cache\/","title":"Analiza i optymalizacja wydajno\u015bci wygasania kluczy w Redis","excerpt":"Dok\u0142adnie analizuj\u0119 wydajno\u015b\u0107 funkcji wygasania kluczy w Redis i optymalizuj\u0119 j\u0105 za pomoc\u0105 jasnych, mierzalnych krok\u00f3w. W ten spos\u00f3b zmniejszam op\u00f3\u017anienia, wyr\u00f3wnuj\u0119 szczyty obci\u0105\u017cenia i kontroluj\u0119 zu\u017cycie pami\u0119ci bez nara\u017cania przepustowo\u015bci. Kluczowe kwestie Podsumowuj\u0119 najwa\u017cniejsze aspekty wydajno\u015bci wygasania kluczy w taki spos\u00f3b, aby pocz\u0105tkuj\u0105cy mogli od razu rozpocz\u0105\u0107 prac\u0119, a zaawansowani u\u017cytkownicy mogli przeprowadzi\u0107 precyzyjne dostrojenie. Poni\u017csze punkty dotycz\u0105 najskuteczniejszych element\u00f3w regulacyjnych i wskazuj\u0105, gdzie powstaj\u0105 typowe w\u0105skie gard\u0142a. Skupiam si\u0119 przy tym na strategiach TTL, aktywnym i pasywnym czyszczeniu oraz zachowaniu mechanizmu eviction. Dodatkowo przedstawiam wska\u017aniki monitorowania, kt\u00f3re pozwalaj\u0105 wcze\u015bnie wykrywa\u0107 problemy. Dzi\u0119ki temu mo\u017cna systematycznie ocenia\u0107 wydajno\u015b\u0107 i trwale j\u0105 kontrolowa\u0107. Wygasanie leniwe a aktywne: zrozumienie i pomiar wzajemnego oddzia\u0142ywania Rozproszenie TTL: przesuni\u0119cia czasowe w celu unikni\u0119cia jednoczesnego wyga\u015bni\u0119cia Optymalizacja cz\u0119stotliwo\u015bci: R\u00f3wnowa\u017cenie cz\u0119stotliwo\u015bci cykli w tle Polityka usuwania: allkeys-lru a warianty volatile Monitorowanie: obserwacja warto\u015bci wyga\u015bni\u0119cia, usuwania i op\u00f3\u017anie\u0144 Stawiam na sp\u00f3jne warto\u015bci TTL, adaptacyjne czyszczenie i jasno okre\u015blone progi. W ten spos\u00f3b rozk\u0142adam momenty wyga\u015bni\u0119cia, zapobiegam niepotrzebnym usuni\u0119ciom i niezawodnie utrzymuj\u0119 niskie czasy odpowiedzi. Dodatkowo korzystam z metryk, kt\u00f3re natychmiast sygnalizuj\u0105 nietypowe fazy i umo\u017cliwiaj\u0105 podj\u0119cie precyzyjnych dzia\u0142a\u0144 zaradczych. Wygasanie kluczy w Redis: zasada dzia\u0142ania i wp\u0142yw na op\u00f3\u017anienie Redis \u0142\u0105czy wygasanie leniwe (lazy) i aktywne (active), aby po\u0142\u0105czy\u0107 wysok\u0105 wydajno\u015b\u0107 z ograniczonym obci\u0105\u017ceniem procesora. W przypadku wygasania leniwego serwer usuwa klucze dopiero podczas dost\u0119pu, gdy up\u0142ynie czas TTL. Dzi\u0119ki temu nie powstaj\u0105 \u017cadne dodatkowe operacje w tle dotycz\u0105ce danych, kt\u00f3re i tak s\u0105 regularnie odczytywane. Wygasanie aktywne uzupe\u0142nia ten model poprzez kr\u00f3tkie, cz\u0119ste skanowanie kluczy, kt\u00f3rych wa\u017cno\u015b\u0107 dobiega ko\u0144ca, w celu usuni\u0119cia zapomnianych wpis\u00f3w. Architektura ta utrzymuje niskie op\u00f3\u017anienia i zwalnia pami\u0119\u0107 bez kosztownych, sta\u0142ych skanowa\u0144. Odczuwalne op\u00f3\u017anienia pojawiaj\u0105 si\u0119 przede wszystkim wtedy, gdy bardzo wiele wpis\u00f3w wygasa w kr\u00f3tkim przedziale czasowym. W\u00f3wczas Redis przeznacza wi\u0119cej mocy procesora na aktywne czyszczenie, co tymczasowo ogranicza przepustowo\u015b\u0107 dla operacji klient\u00f3w. Dodatkowe obci\u0105\u017cenie pami\u0119ci v"},"I3":{"id":"I3","post_id":21547,"url":"https:\/\/webhosting.de\/redis-expire-strategien-grosse-cache-systeme-cache-architektur\/","title":"Strategie wygasania w Redis dla du\u017cych system\u00f3w pami\u0119ci podr\u0119cznej: praktyczny przewodnik po optymalizacji wydajno\u015bci","excerpt":"Du\u017ce klastry pami\u0119ci podr\u0119cznej, bez przemy\u015blanych strategii wygasania danych w Redis, szybko prowadz\u0105 do ogranicze\u0144 pami\u0119ci i zmiennych op\u00f3\u017anie\u0144; poka\u017c\u0119 Ci, jak po\u0142\u0105czy\u0107 TTL, eviction i uniewa\u017cnianie danych tak, aby unikn\u0105\u0107 szczyt\u00f3w obci\u0105\u017cenia. Przedstawi\u0119 konkretne najlepsze praktyki dotycz\u0105ce projektowania kluczy, czas\u00f3w wyga\u015bni\u0119cia i monitorowania, kt\u00f3re niezawodnie sprawdzaj\u0105 si\u0119 w instalacjach produkcyjnych. Kluczowe punkty: konsekwentne zrozumienie i konfiguracja rozdzielenia wyga\u015bni\u0119cia i usuwania; ustawianie TTL wsz\u0119dzie oraz po\u0142\u0105czenie jittera z uniewa\u017cnianiem w celu przeciwdzia\u0142ania efektowi \u201ethundering herd\u201c: Delete-on-write, tagi, wersjonowanie \u015awiadomy wyb\u00f3r polityki eviccji i testowanie z parametrem maxmemory Skierowanie monitoringu na klucze wygas\u0142e\/usuni\u0119te, wska\u017anik trafie\u0144 (hit rate) oraz op\u00f3\u017anienia Wygasanie a eviccja: Jak Redis usuwa dane W moim planowaniu zawsze wyra\u017anie rozr\u00f3\u017cniam wyga\u015bni\u0119cie i usuni\u0119cie, poniewa\u017c oba procesy maj\u0105 r\u00f3\u017cne cele. Wyga\u015bni\u0119cie usuwa klucze po up\u0142ywie TTL, podczas gdy usuni\u0119cie ma zastosowanie tylko wtedy, gdy wyczerpana zostanie skonfigurowana przestrze\u0144 pami\u0119ci. Przy ka\u017cdym dost\u0119pie Redis sprawdza za pomoc\u0105 mechanizmu Lazy-Expiration, czy klucz jest przeterminowany, a dodatkowo aktywnie czy\u015bci losowo wybrane wpisy w okre\u015blonych odst\u0119pach czasu. Ta metoda mieszana zapobiega obci\u0105\u017ceniu zwi\u0105zanemu z timerem dla ka\u017cdego klucza i ogranicza nak\u0142ad pracy zwi\u0105zany z zarz\u0105dzaniem. Kto rozumie t\u0119 mechanik\u0119, mo\u017ce precyzyjnie kontrolowa\u0107, ile \u201emartwej\u201d pami\u0119ci jest tolerowane w kr\u00f3tkim okresie, nie powoduj\u0105c przy tym nieoczekiwanych brak\u00f3w w pami\u0119ci podr\u0119cznej. Projektowanie TTL: czasy, wahania i warstwowanie Ka\u017cdemu kluczowi w pami\u0119ci podr\u0119cznej nadaj\u0119 TTL, nawet je\u015bli stosuj\u0119 jawne uniewa\u017cnianie, poniewa\u017c czas wyga\u015bni\u0119cia stanowi wa\u017cn\u0105 siatk\u0119 bezpiecze\u0144stwa. W przypadku danych zwi\u0105zanych z u\u017cytkownikami cz\u0119sto zaczynam od 5\u201315 minut, ale dostosowuj\u0119 ten interwa\u0142 do cz\u0119stotliwo\u015bci zmian i tolerancji na nieaktualne odczyty. Sesje otrzymuj\u0105 kr\u00f3tkie czasy wa\u017cno\u015bci, szczeg\u00f3\u0142y produkt\u00f3w raczej d\u0142u\u017csze, a konfiguracje maj\u0105 jeszcze wi\u0119kszy margines; w ten spos\u00f3b rozk\u0142adam ryzyko i wyr\u00f3wnuj\u0119 obci\u0105\u017cenie. Dodatkowo wprowadzam niewielkie wahania, np. \u00b110 %, aby tysi\u0105ce kluczy nie wygasa\u0142y jednocze\u015bnie. W wielowarstwowych pami\u0119ciach podr\u0119cznych pozwalam pami\u0119ci aplikacji dzia\u0142a\u0107 w sekundach, Redisowi pracowa\u0107 w minutach lub godzinach, a warstwom wy\u017cszego poziomu utrzymywa\u0107 dane d\u0142u\u017cej, aby unikn\u0105\u0107 kosztownych rekonstrukcji. Wyra\u017ane uniewa\u017cnianie bez efekt\u00f3w ubocznych T"}},"_wh_make_stage":"entwurf","_wh_make_research_date":"2026-09-23","_wh_make_sitemap_info":{"index":"https:\/\/webhosting.de\/sitemap_index.xml","sitemaps":["https:\/\/webhosting.de\/post-sitemap1.xml","https:\/\/webhosting.de\/post-sitemap2.xml","https:\/\/webhosting.de\/post-sitemap3.xml","https:\/\/webhosting.de\/post-sitemap4.xml"],"url_count":3094,"fetched_at":"2026-09-23T18:48:56+00:00","selected_ids":[21633,21597,21547]},"_wh_make_draft_hash":"d76d8afe3f2377274abfbdbf3d69266f89d1d96728719e11663c89002501a09d","_wh_make_work":{"version":"2.1","identity":{"sheet_ref":"1VMjxV8Q73i0Q1HO6s-u4jNHVRF0snliGCeg97intLPs","sheet_name":"Tabellenblatt1","external_id":"1389","topic":"Redis Lua Scripts f\u00fcr atomare Operationen","keywords":["redis lua scripts","redis automation","cache scripting"],"category_input":"781"},"config":{"research_model":"gpt-5.6-terra","writer_model":"gpt-5.6-terra","review_model":"gpt-5.6-sol","image_model":"gpt-image-2.5-flare","image_quality":"medium","image_format":"webp","final_status":"draft","charts_enabled":true},"phase":"done","pending":null,"receipts":{"b5554817e53b841238fb360bbe8725c4":"d0d3afd5b6c62ce085fc33e6971e65c7cc4cfc40812654cbadd175844a3d9415","8627810c5aa7feb327768a8f910d8a68":"f9d7caefe9191e3e2dc238fc6c4869b8d2e7112ade9bceb78eabf5ee5730bdd5","0de78a5a540e8df01c179a96a5ffbe17":"daf682315ce3152459ac407bb0a065ec0fbd16310f568be627c72e932fb69356","e2f3fdef76c7f764376f4f794b3cbb3b":"dfed56617fcfb71e6316163bd1fabdc155d06b424e98d4309a3886be30423851","d9bbb93d9939c21e60299a77b057d58a":"9970e3023d402cc93715440f9c4e689786ad0424d57d07811d2250b41e64d857","6841beb7a86e91b1325b9a70626bc509":"1ae76137b46534ecda8f56599feecfab095268f06ef4b1a563bdc8f07f6fb65c","adb48a82cc0b8363c621b6410b740f3f":"55a5adf2799ed2d48a83d04ce9f2cae813d042400a4d7c01d65e4e8a5d7b9cac","7e77e60f12e58cda3b5f9c9fb95ecf91":"50db8a4fc3125e1215d07348b2784ad7d42ceae9ec3a4b402cca4ddc3d981ab1","633d289a3c4c6d06aac2919c9c1acf1c":"249b1a6da203d2bdebe070befda7d86e89637f620768d06baf20e1f8ce27a88d","1ce1086638e127b1cc6ffba4dae32a53":"86e748848590439c5f26c22eab0110b9d958a83b15087f29b03c1121b2ff4962","43182097b851b3995fedaa691c31f905":"ecdaca3fc8a9e98244657bc2807d711e815d45ab974e9f8c2d4fe3b5f10437d9","cb18726e194ed659071b6601ce6a2579":"fac69a120115c9ccbe1f7f4ded5799e2ed5657a687a3c1c6cad86a3087a19a04","1a51d75b2f895d36892e8c570b2afe52":"f48a0e099863795c162e0f2139120763e7c82d376dee916eef1406c9c0309d8f","e18a70d2ef91520a9c00a18b45151d94":"b49245c917f5b0eb26cd9687f9a89088fbb9437268f45d558bc0e80c70a68435","50175b27e719435cdd7828873f198273":"79e1921a134fe08aba7a8e6d43eaa9b2dc419c16239e0644e87a09e262cdc752","912ee0ff270341909d5a880d4bd94335":"15a262746f916322c6c85ce6d45410016c59449ba48be5485067bc070e3ec82e","aa41f5e1284d9d0fd1ed178e2be0100a":"a84fa4b1691848239715930beb4aed3b2ea3dda780dc56ec8bdba2daf7b3fe4f","1d0466fd937f58078298105bed83ca4b":"de44792a23d6372007d9880592c68b14ae29ef22149039ef761f0f620006d74d","f097c4e28d86086bd5fba23175fe8c72":"96730713f29d838049fba1c99f2bafa603cb3c793acbdf6e315382341a4e5613","97ea7d36ab99e7e3451c9b3f81823729":"90d551643508d303b1371abf0f551297fbf53d01f12863c4aaeee0bceca56177"},"parts":{"1":[{"id":"atomicity","heading":"Atomare Redis Lua Scripts einordnen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Redis Lua Scripts f\u00fchren fachliche Datenlogik direkt im Redis-Server aus. W\u00e4hrend ein Script l\u00e4uft, verarbeitet Redis keine anderen Serveraktivit\u00e4ten; die enthaltenen Befehle sind daher gegen\u00fcber anderen Clients isoliert. Damit lassen sich mehrere einfache Kommandos zu einer ","ref":""},{"kind":"strong","text":"atomaren Operation","ref":""},{"kind":"text","text":" verbinden, etwa eine Limitpr\u00fcfung mit anschlie\u00dfendem Z\u00e4hler-Update oder eine Abbuchung nur bei ausreichendem Guthaben. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ohne Script kann ein Client zun\u00e4chst mit GET einen Z\u00e4hler lesen, die Grenze im Anwendungscode pr\u00fcfen und danach INCR senden. Zwischen diesen Schritten kann jedoch ein anderer Client denselben Z\u00e4hler ver\u00e4ndern. Ein Script liest, pr\u00fcft und erh\u00f6ht dagegen ohne diesen beobachtbaren Zwischenzustand. Das l\u00f6st die Race Condition der zusammengesetzten Regel, nicht aber automatisch Fragen wie passende Grenzwerte, Ablaufzeiten oder R\u00fcckgabeformate. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Atomar und isoliert bedeutet nicht, dass Redis Lua Scripts Datenbanktransaktionen mit automatischem Rollback sind. Tritt nach einer bereits erfolgten Schreiboperation ein Laufzeitfehler auf, werden vorherige \u00c4nderungen nicht pauschal zur\u00fcckgenommen. Deshalb sollten Scripts Eingaben, Datentypen und fachliche Voraussetzungen vor dem ersten Schreiben pr\u00fcfen; Fehlerpfade nach \u00c4nderungen brauchen eine bewusst entworfene Behandlung. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Typische Regeln sind: einen Zugriff nur innerhalb eines Limits zulassen, einen Bestand nur bei ausreichender Menge reduzieren oder einen Sperr-Key nur l\u00f6schen, wenn sein gespeicherter Token dem \u00fcbergebenen Ownership-Token entspricht. Bei der Token-L\u00f6schung verhindert der Vergleich, dass ein versp\u00e4teter Prozess eine sp\u00e4ter von einem anderen Prozess erworbene Sperre entfernt. Die Atomizit\u00e4t umfasst dabei ausschlie\u00dflich die beteiligten Redis-Daten. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]}]},{"id":"runtime","heading":"Lua Sandbox und klare Grenzen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Redis Open Source bettet f\u00fcr Scripts Lua 5.1 ein. Diese Laufzeit ist nicht mit einer lokal installierten oder aktuellen Lua-Hauptversion gleichzusetzen: Verf\u00fcgbarer Sprachumfang und Sicherheitsregeln bestimmt Redis. Wer redis lua scripts entwickelt, sollte sie deshalb gegen die tats\u00e4chlich eingesetzte Redis-Version pr\u00fcfen und nicht Eigenschaften einer beliebigen externen Lua-Umgebung voraussetzen. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Die Ausf\u00fchrung erfolgt in einer ","ref":""},{"kind":"strong","text":"Sandbox","ref":""},{"kind":"text","text":" mit absichtlich engen Grenzen. Ein Script soll Redis-Daten und \u00fcbergebene Argumente verarbeiten, aber weder Dateisystem, Netzwerk noch Betriebssystemdienste nutzen. Auch require steht nicht zur Verf\u00fcgung. Externe HTTP-Aufrufe, das Versenden von Nachrichten oder der Zugriff auf lokale Dateien geh\u00f6ren daher in den Anwendungscode oder einen daf\u00fcr vorgesehenen Dienst, nicht in cache scripting. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Globale Lua-Variablen und globale Funktionen sind in der Script-Umgebung gesperrt. Verwende stattdessen lokale Variablen mit local und kapsle wiederkehrende, kleine Berechnungen in lokalen Funktionen. Das verhindert unbeabsichtigte Abh\u00e4ngigkeiten und macht klar, welche Werte nur f\u00fcr diesen Script-Aufruf gelten. Redis-Kommandos werden gezielt \u00fcber redis.call oder redis.pcall aus dem Script heraus aufgerufen. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Die Sandbox ersetzt keine Kapazit\u00e4tsplanung. W\u00e4hrend regul\u00e4rer Ausf\u00fchrung blockiert ein Script andere Clients am Server, daher sind lange Schleifen, unbeschr\u00e4nkte Datenmengen und rechenintensive Auswertungen ungeeignet. Beschr\u00e4nke die Arbeit auf wenige, vorher bekannte Keys und kleine Berechnungen. Umfangreiche Analysen, SCAN-basierte Gesamtbest\u00e4nde oder Kommunikation mit Fremdsystemen w\u00fcrden die Betriebsrisiken erh\u00f6hen, ohne die Atomizit\u00e4t sinnvoll zu erweitern. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]}]},{"id":"interfaces","heading":"EVAL, KEYS und ARGV verstehen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Der unmittelbare Aufruf eines Scripts verwendet die Form ","ref":""},{"kind":"code","text":"EVAL script numkeys [key \u2026] [arg \u2026]","ref":""},{"kind":"text","text":". Nach dem Quelltext legt numkeys fest, wie viele folgende Parameter Schl\u00fcssel sind. Das Script erreicht sie \u00fcber KEYS mit einsbasierter Indexierung; alle weiteren Werte stehen in ARGV. Diese Trennung ist wesentlich: Schl\u00fcssel beschreiben die Redis-Daten, Argumente die fachlichen Eingaben wie Grenzwert, Betrag oder erwarteten Token. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ein Limit-Script erh\u00e4lt beispielsweise den Z\u00e4hler als KEYS[1] und den H\u00f6chstwert als ARGV[1]. Es liest den aktuellen Stand, wandelt den Grenzwert mit ","ref":""},{"kind":"code","text":"tonumber(ARGV[1])","ref":""},{"kind":"text","text":" in eine Zahl um und vergleicht beide Werte, bevor es erh\u00f6ht. Die Umwandlung macht die beabsichtigte numerische Fachregel explizit, statt sich auf eine implizite Behandlung von Argumentwerten zu verlassen. Fehlt ein Z\u00e4hler, kann das Script den gelesenen Wert gezielt als null behandeln. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Jeder Key, den das Script liest oder schreibt, muss vorab als Key-Argument angegeben werden. Key-Namen im Script aus Pr\u00e4fixen zusammenzusetzen oder aus gespeicherten Daten abzuleiten, ist kein belastbares Muster. Redis kann dann insbesondere im Cluster nicht vor der Ausf\u00fchrung nachvollziehen, welche Daten das Script ben\u00f6tigt. \u00dcbergib daher bekannte Schl\u00fcssel vollst\u00e4ndig \u00fcber KEYS und variable Fachwerte ausschlie\u00dflich \u00fcber ARGV. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Im Redis Cluster m\u00fcssen mehrere von einem Script verwendete Keys au\u00dferdem im selben Hash Slot liegen. Die vorherige Deklaration erm\u00f6glicht diese Pr\u00fcfung, ersetzt sie aber nicht. F\u00fcr zusammengeh\u00f6rige Daten kann ein bewusst gew\u00e4hlter Hash Tag helfen, etwa ","ref":""},{"kind":"code","text":"account:{4711}:balance","ref":""},{"kind":"text","text":" und ","ref":""},{"kind":"code","text":"account:{4711}:reservations","ref":""},{"kind":"text","text":". Der Teil in geschweiften Klammern bestimmt hier die Slot-Zuordnung; dynamisch ermittelte Keys w\u00fcrden diese Planung unterlaufen. ","ref":""},{"kind":"citation","text":"","ref":"S6"}]}]}],"2":[{"id":"limitexample","heading":"Rate Limit atomar implementieren","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr einen lokalen Test kann ein Script Z\u00e4hlerstand und Grenzwert in einem Serverlauf pr\u00fcfen. Damit entf\u00e4llt das Zeitfenster zwischen einem GET im Anwendungscode und einem sp\u00e4teren INCR, in dem ein anderer Client den Z\u00e4hler ver\u00e4ndern k\u00f6nnte. Das Beispiel verwendet bewusst nur einen Demo-Key und ist keine Vorlage f\u00fcr Zugangsdaten, produktive Limits oder Lasttests. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Der aktuelle Wert wird gelesen und mit ","ref":""},{"kind":"code","text":"tonumber","ref":""},{"kind":"text","text":" in einen numerischen Lua-Wert \u00fcberf\u00fchrt. Fehlt der Key, behandelt das Script ihn als null. Bei erreichtem Limit endet es ohne Schreibvorgang; andernfalls erh\u00f6ht ","ref":""},{"kind":"code","text":"INCR","ref":""},{"kind":"text","text":" den Z\u00e4hler. Schl\u00fcssel steht in ","ref":""},{"kind":"code","text":"KEYS[1]","ref":""},{"kind":"text","text":", der fachliche Grenzwert in ","ref":""},{"kind":"code","text":"ARGV[1]","ref":""},{"kind":"text","text":". ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"code","language":"redis-cli","code":"EVAL \"local current = tonumber(redis.call('GET', KEYS[1]) or '0'); local limit = tonumber(ARGV[1]); if current >= limit then return {0, current}; end; local next = redis.call('INCR', KEYS[1]); return {1, next}\" 1 demo:rate-limit 3","source_ids":["S1","S3"]},{"type":"paragraph","runs":[{"kind":"text","text":"Der ","ref":""},{"kind":"strong","text":"R\u00fcckgabevertrag","ref":""},{"kind":"text","text":" ist Teil der Schnittstelle: Das erste Array-Element bedeutet 1 f\u00fcr erlaubt oder 0 f\u00fcr abgelehnt, das zweite liefert den vorhandenen beziehungsweise neuen Stand. Der aufrufende Code sollte beide F\u00e4lle fachlich auswerten, statt eine Ablehnung als technischen Fehler zu behandeln. F\u00fcr weitere Informationen zur Wahl und Beobachtung von Ablaufzeiten ist der Artikel ","ref":""},{"kind":"internal_link","text":"Redis Key Expiration analysieren und optimieren","ref":"I2"},{"kind":"text","text":" eine erg\u00e4nzende Grundlage.","ref":""}]},{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr ein Fixed Window muss die TTL-Entscheidung ebenfalls zur kontrollierten Operation geh\u00f6ren. Es ist vorab festzulegen, ob die Ablaufzeit nur beim ersten Treffer gesetzt wird oder jeder Treffer sie verl\u00e4ngert; beides erzeugt andere Regeln. ","ref":""},{"kind":"strong","text":"Lua-Atomizit\u00e4t","ref":""},{"kind":"text","text":" beseitigt dabei nur die Race Condition. Ob Fixed Window, Sliding Window oder Token Bucket zur gew\u00fcnschten Fairness und Zeitsemantik passt, entscheidet der gew\u00e4hlte Algorithmus, nicht die Scriptsprache. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]}]},{"id":"mechanisms","heading":"Passendes Atomizit\u00e4tsmodell ausw\u00e4hlen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Nicht jede zusammengesetzte Anforderung ben\u00f6tigt ein Script. Existiert ein einzelner Redis-Befehl, der die Fachregel bereits ausdr\u00fcckt, ist er meist einfacher zu betreiben und zu pr\u00fcfen. F\u00fcr optimistisches Compare-and-Set kann WATCH vor MULTI und EXEC passend sein: \u00c4ndert ein beobachteter Key sich zuvor, wird EXEC abgebrochen, und der Client entscheidet \u00fcber einen erneuten Versuch. Auch Transaktionen bieten bei Fehlern w\u00e4hrend EXEC keinen allgemeinen Rollback. ","ref":""},{"kind":"citation","text":"","ref":"S4"}]},{"type":"table","caption":"Atomizit\u00e4tsmodelle f\u00fcr Redis-Operationen im Vergleich","headers":["Modell","Geeigneter Einsatzfall","Code und Aufruf","Nach Neustart oder Failover","Client-Verhalten und Grenze"],"rows":[["Nativer Befehl","Eine vorhandene Einzeloperation bildet die Regel ab","Kein Programmcode; direkter Befehl","Kein Script-Cache betroffen","Keine Script-Nachladung; auf vorhandene Semantik begrenzt"],["MULTI\/EXEC mit WATCH","Optimistisches Lesen, Pr\u00fcfen und Schreiben","WATCH, MULTI, EXEC","Kein Programmspeicher","Bei \u00c4nderung vor EXEC erneut lesen und entscheiden; kein Rollback bei EXEC-Fehlern"],["EVAL","Kleines, unmittelbar aufgerufenes Script","Quelltext bei jedem EVAL","Script-Cache ist nicht dauerhaft","Keine Digest-Nachladung; Quelltext wird wieder \u00fcbertragen"],["SCRIPT LOAD plus EVALSHA","Wiederverwendetes Script mit bekanntem Digest","Laden, danach Aufruf per SHA1-Digest","Cache kann fehlen","NOSCRIPT behandeln und erneut laden; Pipeline-Fallback besonders planen"],["Redis Functions ab 7.0","Benannte, wiederverwendbare Datenlogik","FUNCTION LOAD, danach FCALL","Bibliotheken werden repliziert und persistiert","Versions- und Bereitstellungsprozess n\u00f6tig; nicht mit EVAL gleichsetzen"]],"source_ids":["S1","S4","S5"]},{"type":"paragraph","runs":[{"kind":"text","text":"EVAL-Scripts sind an den Script-Cache gebunden und erhalten ihre Eingaben \u00fcber KEYS und ARGV. ","ref":""},{"kind":"strong","text":"Redis Functions","ref":""},{"kind":"text","text":" gibt es ab Redis 7.0 als benannte Bibliotheken: Sie werden mit FUNCTION LOAD registriert, mit FCALL aufgerufen sowie zusammen mit der Datenbank persistiert und repliziert. Ihre Schl\u00fcssel und Argumente erreichen die Funktion als Parameter; daraus folgt ein anderes Bereitstellungs- und Aufrufmodell als bei EVAL. ","ref":""},{"kind":"citation","text":"","ref":"S5"}]},{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr anwendungsnahe, kleine Logik ist EVAL daher ein direkter Einstieg. Mehrere Clients und langfristig gepflegte Datenlogik sprechen h\u00e4ufig f\u00fcr Functions, sofern die eingesetzte Redis-Open-Source-Version sie unterst\u00fctzt. Die Entscheidung sollte au\u00dferdem Deployment, Berechtigungen, Fehlerbehandlung und eine eindeutig dokumentierte R\u00fcckgabe ber\u00fccksichtigen, nicht nur die Zahl der Redis-Befehle. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]}]},{"id":"clustererrors","heading":"Cluster, Fehler und R\u00fcckgabevertr\u00e4ge","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"In Redis Cluster m\u00fcssen alle Keys, die ein Mehr-Key-Script verwendet, im selben Hash Slot liegen. Hash Tags machen das steuerbar: Bei ","ref":""},{"kind":"code","text":"account:{4711}:balance","ref":""},{"kind":"text","text":" und ","ref":""},{"kind":"code","text":"account:{4711}:reservations","ref":""},{"kind":"text","text":" bestimmt der Inhalt zwischen geschweiften Klammern den Slot. Beide Keys k\u00f6nnen deshalb gemeinsam angesprochen werden. Das gilt im Cluster nicht nur f\u00fcr Lua, sondern grunds\u00e4tzlich f\u00fcr Multi-Key-Befehle und Transaktionen. ","ref":""},{"kind":"citation","text":"","ref":"S6"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Alle verwendeten Schl\u00fcssel m\u00fcssen vor dem Aufruf als Key-Argumente deklariert werden. Ein Script darf Key-Namen nicht aus gespeicherten Werten ableiten oder dynamisch zusammensetzen. Diese Regel erm\u00f6glicht Redis die korrekte Slot-Pr\u00fcfung vor der Ausf\u00fchrung und verhindert verdeckte Abh\u00e4ngigkeiten, die in einer Standalone-Instanz unauff\u00e4llig bleiben, im Cluster aber scheitern. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Mit ","ref":""},{"kind":"code","text":"redis.call()","ref":""},{"kind":"text","text":" wird ein Fehler des aufgerufenen Redis-Kommandos als Scriptfehler an den Client weitergegeben. ","ref":""},{"kind":"code","text":"redis.pcall()","ref":""},{"kind":"text","text":" liefert ihn dagegen an Lua zur\u00fcck, damit das Script ihn gezielt behandeln kann. pcall ist nur sinnvoll, wenn eine fachliche Reaktion definiert ist, etwa eine sauber strukturierte Fehlerantwort oder ein alternativer zul\u00e4ssiger Ablauf. Fehler still zu ignorieren verschleiert Daten- und Integrit\u00e4tsprobleme. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ein ","ref":""},{"kind":"strong","text":"Fehlervertrag","ref":""},{"kind":"text","text":" trennt technische Fehler von fachlichen Ergebnissen. WRONGTYPE bedeutet etwa, dass der gespeicherte Redis-Datentyp nicht zum erwarteten Befehl passt und untersucht werden muss. Eine abgelehnte Reservierung wegen fehlenden Bestands ist dagegen ein erwartetes Ergebnis und kann beispielsweise Status und Restbestand zur\u00fcckgeben. Anwendungen sollten diese Kategorien nicht gleich behandeln oder beide pauschal wiederholen. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]}]}],"3":[{"id":"delivery","heading":"Script-Auslieferung robust betreiben","blocks":[{"type":"paragraph","runs":[{"kind":"code","text":"EVAL","ref":""},{"kind":"text","text":" eignet sich f\u00fcr unmittelbare Aufrufe: Der Client \u00fcbertr\u00e4gt den vollst\u00e4ndigen Lua-Quelltext zusammen mit Key- und Argumentwerten. F\u00fcr ein h\u00e4ufig verwendetes, unver\u00e4ndertes Script kann die Anwendung es stattdessen mit ","ref":""},{"kind":"code","text":"SCRIPT LOAD","ref":""},{"kind":"text","text":" in den Script-Cache laden. Redis liefert daf\u00fcr einen SHA1-Digest zur\u00fcck; ","ref":""},{"kind":"code","text":"EVALSHA","ref":""},{"kind":"text","text":" f\u00fchrt anschlie\u00dfend genau den dazugeh\u00f6rigen Quelltext aus. Das spart die wiederholte \u00dcbertragung, \u00e4ndert aber weder die Atomizit\u00e4t noch die fachliche Verantwortung des Scripts.","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Der ","ref":""},{"kind":"strong","text":"Script-Cache","ref":""},{"kind":"text","text":" ist nicht dauerhaft. Nach einem Neustart, Failover oder ","ref":""},{"kind":"code","text":"SCRIPT FLUSH","ref":""},{"kind":"text","text":" kann ein Aufruf per Digest mit ","ref":""},{"kind":"code","text":"NOSCRIPT","ref":""},{"kind":"text","text":" scheitern. Die Anwendung sollte diesen Fall regul\u00e4r behandeln: Script erneut laden und den fachlich sicheren Aufruf wiederholen, sofern die eigene Retry-Logik das zul\u00e4sst. Ein Digest darf daher nicht als Zusage verstanden werden, dass das Script auf jedem Zielserver bereits vorhanden ist.","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Bei Pipelines ist dieser Fallback eingeschr\u00e4nkt. Sind mehrere Befehle bereits gemeinsam gesendet, kann die Anwendung einen darin auftretenden ","ref":""},{"kind":"code","text":"NOSCRIPT","ref":""},{"kind":"text","text":"-Fehler nicht r\u00fcckwirkend durch Laden und erneutes Ausf\u00fchren an derselben Stelle ersetzen. Redis empfiehlt f\u00fcr solche F\u00e4lle parameterisiertes ","ref":""},{"kind":"code","text":"EVAL","ref":""},{"kind":"text","text":" als Ausweichstrategie. Wer Replikation und Failover plant, sollte au\u00dferdem verstehen, welche Rolle der Replikationspuffer bei der Wiederanbindung einer Replica spielt: ","ref":""},{"kind":"internal_link","text":"Redis Replication Backlog verstehen","ref":"I1"},{"kind":"text","text":".","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Variable Werte geh\u00f6ren nicht in den Lua-Quelltext, sondern in ","ref":""},{"kind":"code","text":"ARGV","ref":""},{"kind":"text","text":". Andernfalls erzeugt etwa jeder Grenzwert ein anderes Script und vergr\u00f6\u00dfert den Cache unn\u00f6tig. Seit Redis 7.4 k\u00f6nnen per ","ref":""},{"kind":"code","text":"EVAL","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"EVAL_RO","ref":""},{"kind":"text","text":" geladene Scripts bei einer Cache-Grenze nach LRU entfernt werden; das ersetzt weder Parametrisierung noch die Behandlung von ","ref":""},{"kind":"code","text":"NOSCRIPT","ref":""},{"kind":"text","text":".","ref":""},{"kind":"citation","text":"","ref":"S3"}]}]},{"id":"operations","heading":"Lange Scripts und Schreibfehler beherrschen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Ein Lua-Script blockiert w\u00e4hrend seiner regul\u00e4ren Ausf\u00fchrung andere Serveraktivit\u00e4ten. Das ist die Grundlage seiner Isolation, wird bei langen Laufzeiten jedoch zum ","ref":""},{"kind":"strong","text":"Betriebsrisiko","ref":""},{"kind":"text","text":": Wartende Clients erhalten keine normale Bearbeitung. \u00dcberschreitet ein Script den konfigurierten ","ref":""},{"kind":"code","text":"busy-reply-threshold","ref":""},{"kind":"text","text":", antwortet Redis auf normale Befehle mit ","ref":""},{"kind":"code","text":"BUSY","ref":""},{"kind":"text","text":"; das Script endet dadurch nicht automatisch.","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Besonders kritisch sind Schreiboperationen vor einem Fehler oder einer Endlosschleife. Hat ein Script bereits Daten ver\u00e4ndert, kann ","ref":""},{"kind":"code","text":"SCRIPT KILL","ref":""},{"kind":"text","text":" es nicht sicher beenden. Entwirf deshalb kurze Abl\u00e4ufe, pr\u00fcfe Eingaben vor dem ersten Schreiben und verarbeite keine unbeschr\u00e4nkten Mengen per Schleife oder ","ref":""},{"kind":"code","text":"SCAN","ref":""},{"kind":"text","text":". Tests geh\u00f6ren in eine Umgebung, deren Datenvolumen und Fehlerpfade zum geplanten Einsatz passen.","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"table","caption":"Fehlerf\u00e4lle bei Redis Lua Scripts und sichere Reaktion der Anwendung","headers":["Fall","Erkennbare Antwort","Typische Ursache","Sichere Konsequenz"],"rows":[["NOSCRIPT","Fehlerantwort NOSCRIPT","Digest ist im fl\u00fcchtigen Script-Cache nicht vorhanden","Script laden oder mit parameterisiertem EVAL ausweichen; Aufruf nur nach eigener Retry-Regel wiederholen."],["CROSSSLOT","Cluster-Fehler CROSSSLOT","Mehrere Keys liegen in verschiedenen Hash Slots","Key-Design \u00e4ndern und erforderliche Keys vorab deklarieren; keine Ausf\u00fchrung erzwingen."],["WRONGTYPE","Redis-Fehler WRONGTYPE","Ein Key besitzt einen anderen Datentyp als erwartet","Datenmodell oder Script-Voraussetzung korrigieren; nicht als fachliche Ablehnung behandeln."],["Speicherdruck","Fehlerantwort, abh\u00e4ngig von Konfiguration und Schreibvorgang","F\u00fcr eine \u00c4nderung steht kein zul\u00e4ssiger Speicher bereit","Keine Erfolgsmeldung ableiten; Kapazit\u00e4t, Eviction-Regeln und Wiederholung getrennt bewerten."],["BUSY","Fehlerantwort BUSY f\u00fcr andere Befehle","Ein Script \u00fcberschreitet den busy-reply-threshold","Last reduzieren und Script verkleinern; nicht auf sofortiges Killen nach Schreibvorg\u00e4ngen bauen."],["Fachliche Ablehnung","Dokumentierter Statuswert des Scripts","Etwa Limit erreicht oder Bestand zu niedrig","Keinen technischen Fehler vort\u00e4uschen; Status auswerten und den Gesch\u00e4ftsvorgang geordnet ablehnen."]],"source_ids":["S2","S3","S6"]},{"type":"paragraph","runs":[{"kind":"text","text":"Die Tabelle trennt technische Fehler von einer bewusst zur\u00fcckgegebenen Fachentscheidung. Nur das Script selbst kann beispielsweise \u201eReservierung abgelehnt\u201c als stabilen Status definieren. Ein ","ref":""},{"kind":"code","text":"WRONGTYPE","ref":""},{"kind":"text","text":"-Fehler ist dagegen ein verletztes Datenmodell; ","ref":""},{"kind":"code","text":"CROSSSLOT","ref":""},{"kind":"text","text":" weist im Cluster auf eine unpassende Key-Verteilung hin. Beide F\u00e4lle verlangen Korrekturen statt einer stillen Gleichbehandlung mit \u201enicht verf\u00fcgbar\u201c.","ref":""},{"kind":"citation","text":"","ref":"S3"},{"kind":"citation","text":"","ref":"S6"}]}]},{"id":"decisions","heading":"Geeignete Einsatzf\u00e4lle bewusst entscheiden","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr eine bedingte Reservierung kann ein Script Bestand lesen, einen zu kleinen Wert ablehnen und bei Erfolg den Restbestand zur\u00fcckgeben. Damit bleiben Pr\u00fcfung und Reduzierung zusammen, etwa bei Gutscheinen oder freien Pl\u00e4tzen. Die ","ref":""},{"kind":"strong","text":"atomare Reservierung","ref":""},{"kind":"text","text":" umfasst aber nur Redis: Zahlung, relationale Datenbank, E-Mail und externe API sind davon nicht eingeschlossen und ben\u00f6tigen eigene Abstimmung sowie Ausgleichslogik.","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Beim Vergleich-und-L\u00f6schen liest das Script einen gespeicherten Ownership-Token und l\u00f6scht den Key nur bei Gleichheit mit dem \u00fcbergebenen Token. So entfernt ein versp\u00e4teter Prozess nicht versehentlich eine sp\u00e4ter von einem anderen Prozess erworbene Sperre. Daraus folgt keine allgemeine Empfehlung f\u00fcr selbst gebaute verteilte Locks: Lease-Dauer, Prozesspausen, Ausf\u00e4lle, Wiederholungen und Mehrinstanzenszenarien m\u00fcssen gesondert bewertet werden.","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Auch mehrere Redis-Strukturen k\u00f6nnen eine Script-Regel rechtfertigen, beispielsweise wenn ein Z\u00e4hler und die Mitgliedschaft in einem Set gemeinsam aktualisiert werden m\u00fcssen. Pr\u00fcfe aber zuerst, ob ein einzelner nativer Befehl die gew\u00fcnschte Semantik bereits anbietet. Ist ein Vergleich durch den Client unvermeidbar, kann ","ref":""},{"kind":"code","text":"WATCH","ref":""},{"kind":"text","text":" mit ","ref":""},{"kind":"code","text":"MULTI\/EXEC","ref":""},{"kind":"text","text":" passen; bei zwischenzeitlicher \u00c4nderung wird ","ref":""},{"kind":"code","text":"EXEC","ref":""},{"kind":"text","text":" abgebrochen und der Client entscheidet \u00fcber eine Wiederholung.","ref":""},{"kind":"citation","text":"","ref":"S4"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Eine praktikable Reihenfolge lautet daher: passenden nativen Befehl bevorzugen, danach optimistisches Compare-and-Set mit ","ref":""},{"kind":"code","text":"WATCH","ref":""},{"kind":"text","text":" pr\u00fcfen, dann ein kleines Script und f\u00fcr wiederverwendbare serverseitige Logik eine Redis Function w\u00e4hlen. ","ref":""},{"kind":"strong","text":"Read-only-Scripts","ref":""},{"kind":"text","text":" d\u00fcrfen ab Redis 7.0 \u00fcber ","ref":""},{"kind":"code","text":"EVAL_RO","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"EVALSHA_RO","ref":""},{"kind":"text","text":" laufen, jedoch ausschlie\u00dflich, wenn die gesamte Logik garantiert nicht schreibt.","ref":""},{"kind":"citation","text":"","ref":"S7"}]}]}]},"plan":{"reader_question":"Wie lassen sich mehrere Redis-Befehle mit Bedingungen so ausf\u00fchren, dass zwischen Lesen, Pr\u00fcfen und Schreiben kein anderer Client einen widerspr\u00fcchlichen Zwischenstand erzeugt?","sections":[{"id":"atomicity","heading":"Atomare Redis Lua Scripts einordnen","part":1,"target_words":270,"purpose":"Erkl\u00e4rt Redis Lua Scripts als serverseitige Datenlogik und die Isolation w\u00e4hrend der Ausf\u00fchrung. Ein Absatz kontrastiert das klassische GET-Pr\u00fcfen-INCR-Rennen mit einer zusammengesetzten Operation; ein zweiter grenzt Atomizit\u00e4t von Transaktionen mit automatischem Rollback ab. Konkrete F\u00e4lle: Limitpr\u00fcfung, bedingte Abbuchung und Token-L\u00f6schung.","source_ids":["S1","S2"],"internal_link_ids":[]},{"id":"runtime","heading":"Lua Sandbox und klare Grenzen","part":1,"target_words":260,"purpose":"Beschreibt Redis Open Source mit eingebettetem Lua 5.1 statt beliebiger lokaler Lua-Versionen. Erl\u00e4utert Sandbox-Grenzen f\u00fcr Dateisystem, Netzwerk, Betriebssystem, globale Variablen und require; anschlie\u00dfend lokale Variablen und kleine lokale Hilfsfunktionen als Stilregel. Macht deutlich, dass externe APIs und lange Berechnungen nicht in cache scripting geh\u00f6ren.","source_ids":["S3","S2"],"internal_link_ids":[]},{"id":"interfaces","heading":"EVAL, KEYS und ARGV verstehen","part":1,"target_words":270,"purpose":"Erkl\u00e4rt die Signatur EVAL script numkeys [key \u2026] [arg \u2026] und trennt Schl\u00fcssel in KEYS von Fachwerten in ARGV. Ein kompaktes Ablaufbeispiel zeigt, warum Grenzwerte mit tonumber verarbeitet werden und warum alle angesprochenen Keys vorab angegeben werden m\u00fcssen. Grenzen dynamisch zusammengesetzter Key-Namen abgrenzen, einschlie\u00dflich der Relevanz f\u00fcr Redis Cluster.","source_ids":["S3","S6"],"internal_link_ids":[]},{"id":"limitexample","heading":"Rate Limit atomar implementieren","part":2,"target_words":300,"purpose":"F\u00fchrt ein begrenztes redis-cli-Beispiel f\u00fcr lokalen Testbetrieb ein: Z\u00e4hler lesen, Grenzwert pr\u00fcfen, bei Erfolg erh\u00f6hen und ein zweigeteiltes R\u00fcckgabeprotokoll liefern. Die Erkl\u00e4rung gliedert sich in Script-Logik, R\u00fcckgabewerte und TTL-Entscheidung. Sie grenzt Fixed Window von Sliding Window und Token Bucket ab: Lua l\u00f6st die Race Condition, w\u00e4hlt aber keinen Algorithmus aus.","source_ids":["S1","S3"],"internal_link_ids":["I2"]},{"id":"mechanisms","heading":"Passendes Atomizit\u00e4tsmodell ausw\u00e4hlen","part":2,"target_words":300,"purpose":"Enth\u00e4lt eine informative Vergleichstabelle f\u00fcr einzelne native Befehle, MULTI\/EXEC mit WATCH, EVAL, SCRIPT LOAD plus EVALSHA und Redis Functions. Verglichen werden Einsatzfall, Code-Persistenz, Aufruf, Verhalten nach Neustart oder Failover, clientseitige Wiederholung und zentrale Grenze. Der Text erkl\u00e4rt Redis Functions ab 7.0 als benannte, persistierte Bibliotheken und trennt sie pr\u00e4zise von EVAL-Scripts.","source_ids":["S1","S4","S5"],"internal_link_ids":[]},{"id":"clustererrors","heading":"Cluster, Fehler und R\u00fcckgabevertr\u00e4ge","part":2,"target_words":280,"purpose":"Verbindet korrekte Key-Deklaration mit der Hash-Slot-Regel: Mehrere Script-Keys m\u00fcssen im Cluster denselben Slot nutzen; Hash Tags werden an account:{4711}:balance und account:{4711}:reservations erkl\u00e4rt. Ein zweiter Strukturwechsel behandelt redis.call() gegen\u00fcber redis.pcall() und fordert fachlich dokumentierte Status- und Fehlerwerte. Grenzen: pcall-Fehler nicht still ignorieren, WRONGTYPE und fachliche Ablehnung unterscheiden.","source_ids":["S1","S3","S6"],"internal_link_ids":[]},{"id":"delivery","heading":"Script-Auslieferung robust betreiben","part":3,"target_words":280,"purpose":"Erkl\u00e4rt EVAL f\u00fcr unmittelbare Aufrufe sowie SCRIPT LOAD und EVALSHA f\u00fcr wiederverwendeten Quelltext. Beschreibt NOSCRIPT nach Neustart, Failover oder SCRIPT FLUSH als regul\u00e4r zu behandelnden Fall und erl\u00e4utert die besondere Einschr\u00e4nkung in Pipelines. Erg\u00e4nzt das Anti-Pattern variabler Werte im Quelltext, die Verwendung von ARGV und die ab Redis 7.4 m\u00f6gliche LRU-Entfernung von per EVAL geladenen Scripts.","source_ids":["S1","S3"],"internal_link_ids":["I1"]},{"id":"operations","heading":"Lange Scripts und Schreibfehler beherrschen","part":3,"target_words":270,"purpose":"Ordnet die Blockierung anderer Serveraktivit\u00e4ten als Betriebsrisiko ein und erkl\u00e4rt busy-reply-threshold, BUSY sowie die Grenze von SCRIPT KILL nach Schreiboperationen. Danach folgt eine Fehlerfall-Tabelle mit NOSCRIPT, CROSSSLOT, WRONGTYPE, Speicherdruck, BUSY und fachlicher Ablehnung: erkennbare Antwort, Ursache und sichere Anwendungskonsequenz. Keine Last- oder Latenzversprechen; stattdessen kleine Scripts, begrenzte Datenmengen und Tests in passender Umgebung.","source_ids":["S2","S3","S6"],"internal_link_ids":[]},{"id":"decisions","heading":"Geeignete Einsatzf\u00e4lle bewusst entscheiden","part":3,"target_words":260,"purpose":"Leitet eine Entscheidung f\u00fcr bedingte Reservierungen, Vergleich-und-L\u00f6schen von Ownership-Tokens und konsistente Aktualisierung mehrerer Redis-Strukturen ab. Stellt jeweils Grenzen heraus: Redis atomarisiert weder Zahlung noch Datenbank, E-Mail oder externe API; selbst gebaute verteilte Locks brauchen eine gesonderte Ausfall- und Lease-Bewertung. Schlie\u00dft mit einer knappen Entscheidungsreihenfolge: nativer Befehl, WATCH, Script oder Function; Read-only-Varianten EVAL_RO und EVALSHA_RO nur bei garantiert schreibfreier Logik.","source_ids":["S4","S7","S2"],"internal_link_ids":[]}]},"repairs":4,"reviews":6,"issues":[],"guard":{"content_md5":"fd52d6dfbe40e10e736d67fc569e8a60","title":"W\u0142a\u015bciwe wykorzystanie skrypt\u00f3w Lua w Redis do operacji atomowych","slug":"skrypty-lua-w-redis-operacje-atomowe","excerpt":"Skrypty Lua w Redis \u0142\u0105cz\u0105 odczyt, sprawdzanie i zapis w jedn\u0105 izolowan\u0105 operacj\u0119 serwera. Artyku\u0142 wyja\u015bnia poj\u0119cia KEYS i ARGV, EVAL i funkcje, ograniczenia klastra, umowy dotycz\u0105ce b\u0142\u0119d\u00f3w, a tak\u017ce bezpieczne wzorce dotycz\u0105ce limit\u00f3w i rezerwacji.","status":"draft","featured_media":21680},"verify":{"content_md5":"fd52d6dfbe40e10e736d67fc569e8a60","title":"W\u0142a\u015bciwe wykorzystanie skrypt\u00f3w Lua w Redis do operacji atomowych","slug":"skrypty-lua-w-redis-operacje-atomowe","excerpt":"Skrypty Lua w Redis \u0142\u0105cz\u0105 odczyt, sprawdzanie i zapis w jedn\u0105 izolowan\u0105 operacj\u0119 serwera. Artyku\u0142 wyja\u015bnia poj\u0119cia KEYS i ARGV, EVAL i funkcje, ograniczenia klastra, umowy dotycz\u0105ce b\u0142\u0119d\u00f3w, a tak\u017ce bezpieczne wzorce dotycz\u0105ce limit\u00f3w i rezerwacji.","status":"draft","featured_media":21680},"row_number":1883,"created_at":"2026-09-23T18:48:56+00:00","updated_at":"2026-09-23T21:43:26+00:00","editorial_reopen_213":{"reason":"legacy_source_pairing","baseline_repairs":2,"additional_repairs":2,"at":"2026-09-23T19:40:45+00:00","user_id":1,"original_fingerprint":"2fd5e451ae766f72f13e03f761d2d5ee6880ffca45a8a8e6427b7b63e8db46b4"},"manual_correction_receipt_214":{"correction_id":"job1389-editorial-correction-214-20260923","request_hash":"d2d35882786d50c13f25fc7f3d44f244c4b8f50c1901252d741002ba3bdcb217","before_fingerprint":"e49f0a9024d898e80bb9d49d2a22d4615d3f84af577935dac519d229648f8cb2","after_doc_hash":"28c97ee685cad92e2a9129a0b1abfabc61cfefbeb4550f1f81e98f75fba18676"},"editorial_revision_receipts_215":[{"revision":1,"revision_id":"job1389-editorial-revision-215-20260923-1","request_hash":"68ed315510da2ff7751e9060441ebcc3ddcea804dd5b983a98f4119f8bef0c6d","before_fingerprint":"945a4ae34847d725ad09b4708be3cba1e2362093e0b68ea5041700423166c051","before_doc_hash":"28c97ee685cad92e2a9129a0b1abfabc61cfefbeb4550f1f81e98f75fba18676","after_doc_hash":"67582c463fdae7fec9f4fcb2567143022e43f24b4ce6ad2eb0025678409c4c52","parent_receipt_hash":"8a13695d53c158e9a81126556fb40ff4bcd092b4c9bcbde51f16551e6ca3f4ba","backup_hash":"963acf82b4b7d6d5f7d45c6a85faa9304d139076a3036b5ce4048d7227cb08bd","commit_hash":"79bf62f151d086ac2d08a2d21dd7ae246812cfe8df3d886fe0181eab503c00bf"}],"retired_image_tokens":{"e460f981c0bbbfc8db9f7d91da192f43":{"reason":"explicit_regeneration_authorized","slot":"hero","at":"2026-09-23T21:34:33+00:00"}},"image_regenerations":{"hero":1},"verified_at":"2026-09-23T21:42:08+00:00"},"_wh_make_research":"Briefing f\u00fcr den Fachartikel: Redis Lua Scripts f\u00fcr atomare Operationen\n\nRecherche- und Versionsstand: 23. September 2026. Der sp\u00e4tere Artikel sollte Redis Lua Scripts als Funktion von Redis Open Source behandeln und Funktionen klar von Redis Functions ab Redis 7.0 abgrenzen. Die Herstellerdokumentation wird fortlaufend aktualisiert; Aussagen zu Versionsgrenzen m\u00fcssen deshalb immer gegen die tats\u00e4chlich eingesetzte Redis-Version gepr\u00fcft werden. Die hier belegten Grundlagen beziehen sich nicht auf Entwicklungszweige wie main oder unstable. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/programmability\/eval-intro\/?utm_source=openai))\n\nLeserfrage und Artikelziel\n\nDie Kernfrage lautet: Wie lassen sich mehrere Redis-Befehle inklusive Bedingungen so ausf\u00fchren, dass kein anderer Client zwischen Lesen, Pr\u00fcfen und Schreiben einen widerspr\u00fcchlichen Zwischenstand erzeugen kann?\n\nDer Artikel sollte erkl\u00e4ren, dass ein Lua Script Logik direkt auf dem Redis-Server ausf\u00fchrt. W\u00e4hrend der Ausf\u00fchrung blockiert Redis andere Serveraktivit\u00e4ten; das Script ist damit gegen\u00fcber anderen Clients isoliert. Praktisch eignet sich das f\u00fcr zusammengesetzte Operationen wie \u201enur abbuchen, wenn Guthaben vorhanden ist\u201c, \u201eLimit pr\u00fcfen und Z\u00e4hler erh\u00f6hen\u201c oder \u201eToken nur l\u00f6schen, wenn sein Wert \u00fcbereinstimmt\u201c. Redis nennt dabei zwei zentrale Vorteile: die Datenlogik l\u00e4uft dort, wo die Daten liegen, und mehrere einfache Redis-Kommandos lassen sich zu einer atomaren Operation kombinieren. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/programmability\/eval-intro\/?utm_source=openai))\n\nWichtig ist die pr\u00e4zise Begrifflichkeit: Atomar und isoliert bedeutet nicht automatisch, dass Redis bei jedem Lua-Laufzeitfehler s\u00e4mtliche vorherigen \u00c4nderungen zur\u00fcckrollt. Bei langen Scripts, die bereits geschrieben haben, kann ein Abbruch gerade deshalb problematisch sein, weil ein halb ver\u00e4nderter Datenbestand entstehen k\u00f6nnte; Redis beendet solche Scripts nicht automatisch. Der Fachartikel darf Lua Scripts daher nicht als allgemeines Ersatzmodell f\u00fcr Datenbanktransaktionen mit Rollback darstellen. Vor Schreiboperationen sollten Eingaben und Voraussetzungen gepr\u00fcft werden; Fehlerpfade nach ersten \u00c4nderungen m\u00fcssen bewusst entworfen werden. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/programmability\/?utm_source=openai))\n\nVoraussetzungen und technische Einordnung\n\nVorausgesetzt werden Grundkenntnisse \u00fcber Redis-Keys, Datentypen und Befehle wie GET, SET, INCR, HGET sowie \u00fcber eine lokale Entwicklungs- oder Testinstanz. Leser sollten au\u00dferdem verstehen, dass Redis Lua 5.1 einbettet. Das ist nicht identisch mit einer beliebigen lokalen Lua-Laufzeit oder aktuellen Lua-Hauptversionen. Scripts laufen in einer eingeschr\u00e4nkten Sandbox: Sie sollen ausschlie\u00dflich Redis-Daten und \u00fcbergebene Argumente verwenden, nicht auf Dateisystem, Netzwerk oder Betriebssystemdienste zugreifen. Globale Lua-Variablen und -Funktionen sind gesperrt; lokale Variablen und lokale Funktionen sind der korrekte Stil. Auch require steht in der Sandbox nicht zur Verf\u00fcgung. ([redis.io](https:\/\/redis.io\/docs\/latest\/commands\/eval\/?utm_source=openai))\n\nDie grundlegende Aufrufsignatur lautet EVAL script numkeys [key \u2026] [arg \u2026]. Schl\u00fcssel werden getrennt von normalen Argumenten \u00fcbergeben: im Script \u00fcber KEYS, sonstige Werte \u00fcber ARGV. Alle Schl\u00fcssel, die ein Script anspricht, m\u00fcssen ausdr\u00fccklich als Key-Argumente genannt werden. Redis r\u00e4t ausdr\u00fccklich davon ab, Key-Namen im Script dynamisch zusammenzusetzen oder aus gespeicherten Daten abzuleiten. Das ist besonders f\u00fcr korrekte Ausf\u00fchrung in Redis Cluster entscheidend. ([redis.io](https:\/\/redis.io\/docs\/latest\/commands\/eval\/?utm_source=openai))\n\nGesicherte Funktionsweise\n\nDer Artikel sollte zun\u00e4chst ein kurzes, sicheres Muster erkl\u00e4ren: Ein Script erh\u00e4lt einen Key und einen Grenzwert. Es liest den aktuellen Z\u00e4hlerstand, pr\u00fcft die Grenze und erh\u00f6ht nur bei Erfolg. Das vermeidet den klassischen Race Condition zwischen einem GET im Anwendungscode und einem sp\u00e4teren INCR.\n\nRedis-CLI, ausschlie\u00dflich f\u00fcr eine lokale Testinstanz:\n\nEVAL \"local current = tonumber(redis.call('GET', KEYS[1]) or '0'); local limit = tonumber(ARGV[1]); if current >= limit then return {0, current}; end; local next = redis.call('INCR', KEYS[1]); return {1, next}\" 1 demo:rate-limit 3\n\nDas Beispiel ist absichtlich begrenzt: Es zeigt keinen produktiven Schl\u00fcssel, keine Zugangsdaten und keine Lastpr\u00fcfung. Der Artikel sollte erl\u00e4utern, dass tonumber n\u00f6tig ist, weil Redis-Antworten und ARGV-Werte im Lua-Kontext nicht automatisch als gew\u00fcnschte numerische Fachwerte behandelt werden sollten. Zudem muss das Script beide R\u00fcckgabef\u00e4lle dokumentieren: etwa 1 f\u00fcr erlaubt und 0 f\u00fcr abgelehnt. Leser brauchen ein stabiles R\u00fcckgabeprotokoll, nicht nur \u201eirgendeine\u201c Lua-R\u00fcckgabe.\n\nredis.call() leitet Fehler eines aufgerufenen Redis-Kommandos als Scriptfehler an den Client weiter. redis.pcall() gibt den Fehler dagegen an den Lua-Kontext zur\u00fcck, damit das Script ihn gezielt auswerten kann. Ein guter Artikel sollte den Unterschied anhand einer Entscheidung erl\u00e4utern: redis.call() f\u00fcr Befehle, deren Fehlschlag den Script-Aufruf eindeutig scheitern lassen soll; redis.pcall() nur dann, wenn der Fehlerfall fachlich behandelt wird. Fehler mit pcall still zu ignorieren, w\u00e4re kein robustes Muster. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/programmability\/eval-intro\/?utm_source=openai))\n\nRelevante Praxisf\u00e4lle\n\nErstens: Rate Limiting. Ein Script pr\u00fcft und erh\u00f6ht einen Z\u00e4hler in einem Durchlauf. Der Artikel sollte klar abgrenzen, dass die Wahl des Algorithmus \u2013 Fixed Window, Sliding Window oder Token Bucket \u2013 unabh\u00e4ngig von der Atomizit\u00e4t ist. Lua kann die Race Condition l\u00f6sen, aber nicht automatisch ein ungeeignetes Limitierungsmodell korrigieren. F\u00fcr einen festen Zeitraum geh\u00f6rt au\u00dferdem die TTL-Logik in dieselbe kontrollierte Operation. Dabei muss das Script genau definieren, ob die Ablaufzeit nur beim ersten Treffer gesetzt oder bei jedem Treffer verl\u00e4ngert wird.\n\nZweitens: Bedingte Reservierung. Beispiele sind begrenzte Gutscheinkontingente, freie Pl\u00e4tze oder Lagerbestand. Ein Script liest den Bestand, lehnt bei zu niedrigem Wert ab und reduziert andernfalls. Empfehlenswert ist ein R\u00fcckgabewert mit Status und neuem Restbestand. Nicht behaupten sollte der Artikel, Redis k\u00f6nne damit allein eine vollst\u00e4ndige Bestellabwicklung garantieren: Zahlung, Datenbank, E-Mail und externe APIs sind nicht Teil der Redis-Atomizit\u00e4t.\n\nDrittens: Vergleich-und-L\u00f6schen f\u00fcr Sperr- oder Ownership-Tokens. Das Script liest den gespeicherten Token und l\u00f6scht den Key nur bei \u00dcbereinstimmung mit dem \u00fcbergebenen Token. Das vermeidet, dass ein versp\u00e4teter Prozess eine zwischenzeitlich neu erworbene Sperre eines anderen Prozesses l\u00f6scht. Der Artikel sollte allerdings keine pauschale Empfehlung \u201everteilte Locks immer selbst mit Lua bauen\u201c geben. Anforderungen an Lease-Zeit, Ausf\u00e4lle, Wiederholungen und Mehrinstanzenszenarien sind gesondert zu bewerten.\n\nViertens: Konsistente Aktualisierung mehrerer Datenstrukturen, etwa Z\u00e4hler plus Set-Mitgliedschaft oder Hash plus Ablaufsteuerung. Lua ist sinnvoll, wenn die Fachregel mehrere Redis-Kommandos zwingend zusammenbindet. Wenn Redis bereits einen einzelnen passenden Befehl bietet, ist dieser meist leichter zu betreiben und zu pr\u00fcfen. Als Alternative geh\u00f6ren native Kommandos, MULTI\/EXEC mit WATCH f\u00fcr optimistisches Compare-and-Set sowie seit Redis 8.4 die dokumentierten Compare-and-Set- beziehungsweise Compare-and-Delete-M\u00f6glichkeiten f\u00fcr String-Keys in die Entscheidungsmatrix. Redis-Transaktionen serialisieren Befehle, bieten aber keine Rollbacks bei Fehlern w\u00e4hrend EXEC; WATCH f\u00fchrt bei zwischenzeitlichen \u00c4nderungen zu einem abgebrochenen EXEC, das der Client wiederholen muss. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/transactions\/?utm_source=openai))\n\nEVAL, EVALSHA und Redis Functions differenzieren\n\nF\u00fcr einmalige oder kleine anwendungsnahe Scripts ist EVAL der unmittelbare Einstieg. EVAL \u00fcbertr\u00e4gt jedoch bei jedem Aufruf den Script-Quelltext. SCRIPT LOAD speichert ein Script im Script-Cache und liefert dessen SHA1-Digest; EVALSHA f\u00fchrt es anschlie\u00dfend per Digest aus. Die Anwendung muss den Fall NOSCRIPT behandeln: Der Cache ist fl\u00fcchtig und kann etwa nach Neustart, Failover oder SCRIPT FLUSH fehlen. F\u00fcr Pipelines ist der Fallback anspruchsvoller, weil ein NOSCRIPT innerhalb der bereits gesendeten Pipeline nicht nachtr\u00e4glich behandelt werden kann; Redis empfiehlt dort parameterisiertes EVAL als Fallback-Strategie. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/programmability\/eval-intro\/?utm_source=openai))\n\nAb Redis 7.0 existieren Redis Functions als weiterentwickeltes Modell. Functions werden als benannte Bibliotheken geladen, repliziert und zusammen mit der Datenbank persistiert; sie sind daher nicht blo\u00df ein fl\u00fcchtiger Client-Cache wie EVAL-Scripts. F\u00fcr wiederverwendbare, versionierte Datenlogik oder mehrere Clients ist das oft die bessere Architektur. Dennoch sollte der Artikel Redis Functions nicht mit \u201eLua Scripts\u201c gleichsetzen: Functions werden mit FUNCTION LOAD registriert und mit FCALL aufgerufen; EVAL-Scripts verwenden KEYS und ARGV, w\u00e4hrend Functions ihre Schl\u00fcssel und Argumente \u00fcber Funktionsparameter erhalten. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/programmability\/functions-intro\/?utm_source=openai))\n\nCluster, Performance und Betriebsgrenzen\n\nIn Redis Cluster m\u00fcssen alle von einem Script verwendeten Keys im selben Hash Slot liegen. Praktisch k\u00f6nnen Hash Tags helfen, etwa account:{4711}:balance und account:{4711}:reservations. Der Teil in geschweiften Klammern steuert die Slot-Zuordnung. Das ist ein wichtiger Tabellenpunkt: Standalone kann Mehr-Key-Operationen ohne Cluster-Slot-Grenze ausf\u00fchren; im Cluster gilt dieselbe Hash-Slot-Anforderung f\u00fcr Multi-Key-Befehle, Transaktionen und Lua Scripts. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/multi-key-operations\/?utm_source=openai))\n\nScripts m\u00fcssen kurz sein. Sie blockieren w\u00e4hrend ihrer regul\u00e4ren Ausf\u00fchrung andere Clients. \u00dcberschreitet ein Script den konfigurierten busy-reply-threshold, beendet Redis es nicht automatisch: Normale Befehle erhalten BUSY, und ein Script mit bereits erfolgten Schreiboperationen kann nicht sicher per SCRIPT KILL beendet werden. Das ist ein Betriebsrisiko, kein Performance-Detail. Der Artikel sollte deshalb keine Schleifen \u00fcber unbeschr\u00e4nkte Datenmengen, kein SCAN-basierendes Massenscannen und keine komplexen Berechnungen im Script empfehlen. ([redis.io](https:\/\/redis.io\/docs\/latest\/develop\/programmability\/?utm_source=openai))\n\nTypische Fehler und klare Gegenma\u00dfnahmen\n\nEin h\u00e4ufiger Fehler ist, variable Werte direkt in den Lua-Quelltext einzubauen. Dadurch entsteht pro Aufruf ein anderes Script; Redis dokumentiert dies als Anti-Pattern, weil der Script-Cache unn\u00f6tig w\u00e4chst. Werte geh\u00f6ren in ARGV, Key-Namen in KEYS. Ab Redis 7.4 werden per EVAL oder EVAL_RO geladene Scripts bei Erreichen einer Cache-Grenze nach dem Least-Recently-Used-Prinzip entfernt; das ersetzt aber keine saubere Parametrisierung und keine NOSCRIPT-Behandlung. ([redis.io](https:\/\/redis.io\/docs\/latest\/commands\/eval\/?utm_source=openai))\n\nWeitere Fehler: nicht deklarierte Cluster-Keys, fehlende Typpr\u00fcfung, unklare R\u00fcckgabewerte, Annahmen \u00fcber implizite TTLs, fehlende Fehlerbehandlung bei Script-Cache-Verlust und der Einsatz von Lua f\u00fcr externe Kommunikation. Auch Read-only-Scripts verdienen eine eigene Abgrenzung: EVAL_RO und EVALSHA_RO sind ab Redis 7.0 vorhanden; passende no-writes-Flags beeinflussen unter anderem Ausf\u00fchrung auf Replikas und Verhalten bei Speicherdruck. Diese Varianten d\u00fcrfen nur verwendet werden, wenn das Script tats\u00e4chlich nicht schreibt. ([redis.io](https:\/\/redis.io\/docs\/latest\/commands\/evalsha_ro\/?utm_source=openai))\n\nEmpfohlene Tabelleninformationen f\u00fcr den sp\u00e4teren Artikel\n\nEine Vergleichstabelle sollte EVAL, SCRIPT LOAD plus EVALSHA, Redis Functions, MULTI\/EXEC mit WATCH und einzelne native Redis-Kommandos gegen\u00fcberstellen. Sinnvolle Spalten: Einsatzfall, Persistenz des Programmcodes, Aufrufart, Verhalten nach Neustart oder Failover, Wiederholungslogik beim Client, Cluster-Anforderung, zentrale Grenze.\n\nEine zweite Tabelle sollte typische Fehlerf\u00e4lle abbilden: NOSCRIPT, CROSSSLOT, WRONGTYPE, OOM beziehungsweise Speicherdruck, BUSY durch lange Scripts sowie fachlich abgelehnte Operationen. F\u00fcr jeden Fall: erkennbare Antwort, Ursache, sichere Anwendungskonsequenz. Ohne eigene reproduzierbare Messdaten sollte der Artikel keine Latenz-, Durchsatz- oder Kostencharts vorschlagen.","_wh_make_sources":{"S1":{"id":"S1","url":"https:\/\/redis.io\/docs\/latest\/develop\/programmability\/eval-intro\/?utm_source=openai","title":"https:\/\/redis.io\/docs\/latest\/develop\/programmability\/eval-intro\/?utm_source=openai"},"S2":{"id":"S2","url":"https:\/\/redis.io\/docs\/latest\/develop\/programmability\/?utm_source=openai","title":"https:\/\/redis.io\/docs\/latest\/develop\/programmability\/?utm_source=openai"},"S3":{"id":"S3","url":"https:\/\/redis.io\/docs\/latest\/commands\/eval\/?utm_source=openai","title":"https:\/\/redis.io\/docs\/latest\/commands\/eval\/?utm_source=openai"},"S4":{"id":"S4","url":"https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/transactions\/?utm_source=openai","title":"https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/transactions\/?utm_source=openai"},"S5":{"id":"S5","url":"https:\/\/redis.io\/docs\/latest\/develop\/programmability\/functions-intro\/?utm_source=openai","title":"https:\/\/redis.io\/docs\/latest\/develop\/programmability\/functions-intro\/?utm_source=openai"},"S6":{"id":"S6","url":"https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/multi-key-operations\/?utm_source=openai","title":"https:\/\/redis.io\/docs\/latest\/develop\/using-commands\/multi-key-operations\/?utm_source=openai"},"S7":{"id":"S7","url":"https:\/\/redis.io\/docs\/latest\/commands\/evalsha_ro\/?utm_source=openai","title":"https:\/\/redis.io\/docs\/latest\/commands\/evalsha_ro\/?utm_source=openai"}},"_wh_make_usage":{"research":{"input_tokens":27867,"output_tokens":3851,"response_id":"resp_0878a4c8ee8e955a016ab41f1c17b087d2bfdb8cbc0fa1b3f7","model":"gpt-5.6-terra","search_calls":3},"plan_8627810c5aa7feb327768a8f910d8a68":{"input_tokens":5666,"output_tokens":1315,"response_id":"resp_05dc6f17dcebe49e016ab41f5cacac87d2837b1daec8fa09d3","model":"gpt-5.6-terra","search_calls":0},"part1_0de78a5a540e8df01c179a96a5ffbe17":{"input_tokens":8005,"output_tokens":1666,"response_id":"resp_014dac9f82884676016ab41f70ddb087d2922fa7dd84f2ae3a","model":"gpt-5.6-terra","search_calls":0},"part2_e2f3fdef76c7f764376f4f794b3cbb3b":{"input_tokens":8062,"output_tokens":2145,"response_id":"resp_07e48251ab987316016ab41f8a090c87d299254a095faa98e4","model":"gpt-5.6-terra","search_calls":0},"part3_d9bbb93d9939c21e60299a77b057d58a":{"input_tokens":8117,"output_tokens":2413,"response_id":"resp_0f8553b19f4605f8016ab41fa9718487d2a9b9eb26d9228269","model":"gpt-5.6-terra","search_calls":0},"package_6841beb7a86e91b1325b9a70626bc509":{"input_tokens":12896,"output_tokens":1310,"response_id":"resp_0028728c476f931e016ab41fcaa34087d2aedbcab1e4fa6c63","model":"gpt-5.6-terra","search_calls":0},"review_adb48a82cc0b8363c621b6410b740f3f":{"input_tokens":44196,"output_tokens":1800,"response_id":"resp_0055a83594b7f425016ab41fdef1b887d2bf86248f35148d51","model":"gpt-5.6-sol","search_calls":3},"repair_7e77e60f12e58cda3b5f9c9fb95ecf91":{"input_tokens":38335,"output_tokens":5234,"response_id":"resp_041e0be732630984016ab42003cce487d29c9f0cc127857048","model":"gpt-5.6-terra","search_calls":2},"review_633d289a3c4c6d06aac2919c9c1acf1c":{"input_tokens":50964,"output_tokens":1789,"response_id":"resp_0a0f925395ff2dce016ab4203d9fb887d2be6b931d3d76fc38","model":"gpt-5.6-sol","search_calls":4},"repair_1ce1086638e127b1cc6ffba4dae32a53":{"input_tokens":31234,"output_tokens":2986,"response_id":"resp_0abfe10e3fa69209016ab42060626487d28d5559d73235fa4e","model":"gpt-5.6-terra","search_calls":1},"review_43182097b851b3995fedaa691c31f905":{"input_tokens":53425,"output_tokens":2077,"response_id":"resp_0c2ee3d59c2b27ba016ab420818d3887d2b9711c01e6c1b6b0","model":"gpt-5.6-sol","search_calls":4},"repair_cb18726e194ed659071b6601ce6a2579":{"input_tokens":37409,"output_tokens":6147,"response_id":"resp_030cb486f9408f92016ab42bdb414087d2a2f9172b37d26519","model":"gpt-5.6-terra","search_calls":2},"repair_1a51d75b2f895d36892e8c570b2afe52":{"input_tokens":31399,"output_tokens":2291,"response_id":"resp_0a12d8a086633cf7016ab42d3ce1c487d28cd7897295db72a5","model":"gpt-5.6-terra","search_calls":1},"review_e18a70d2ef91520a9c00a18b45151d94":{"input_tokens":61564,"output_tokens":2003,"response_id":"resp_07752347f2f7f866016ab42d9db98087d2978e5228bc60fa16","model":"gpt-5.6-sol","search_calls":6},"review_50175b27e719435cdd7828873f198273":{"input_tokens":46101,"output_tokens":1955,"response_id":"resp_05a272515a559d2a016ab4354597c487d2b17e7369b39d5beb","model":"gpt-5.6-sol","search_calls":3},"review_912ee0ff270341909d5a880d4bd94335":{"input_tokens":49391,"output_tokens":1329,"response_id":"resp_0ac6e4348308cd3e016ab43e06cecc87d28d0ef5129d8239ff","model":"gpt-5.6-sol","search_calls":3},"image_hero":{"input_tokens":120,"output_tokens":343,"response_id":"","model":"gpt-image-2.5-flare","search_calls":0},"image_detail1":{"input_tokens":110,"output_tokens":343,"response_id":"","model":"gpt-image-2.5-flare","search_calls":0},"image_detail2":{"input_tokens":108,"output_tokens":343,"response_id":"","model":"gpt-image-2.5-flare","search_calls":0}},"_wh_make_last_error":"","_wh_make_write_intent":{"before":{"content_md5":"5ad46b93e6e0561593a36e3f6a71f93f","title":"W\u0142a\u015bciwe wykorzystanie skrypt\u00f3w Lua w Redis do operacji atomowych","slug":"skrypty-lua-w-redis-operacje-atomowe","excerpt":"Skrypty Lua w Redis \u0142\u0105cz\u0105 odczyt, sprawdzanie i zapis w jedn\u0105 izolowan\u0105 operacj\u0119 serwera. Artyku\u0142 wyja\u015bnia poj\u0119cia KEYS i ARGV, EVAL i funkcje, ograniczenia klastra, umowy dotycz\u0105ce b\u0142\u0119d\u00f3w, a tak\u017ce bezpieczne wzorce dotycz\u0105ce limit\u00f3w i rezerwacji.","status":"draft","featured_media":0},"expected":{"content_md5":"fd52d6dfbe40e10e736d67fc569e8a60","title":"W\u0142a\u015bciwe wykorzystanie skrypt\u00f3w Lua w Redis do operacji atomowych","slug":"skrypty-lua-w-redis-operacje-atomowe","excerpt":"Skrypty Lua w Redis \u0142\u0105cz\u0105 odczyt, sprawdzanie i zapis w jedn\u0105 izolowan\u0105 operacj\u0119 serwera. Artyku\u0142 wyja\u015bnia poj\u0119cia KEYS i ARGV, EVAL i funkcje, ograniczenia klastra, umowy dotycz\u0105ce b\u0142\u0119d\u00f3w, a tak\u017ce bezpieczne wzorce dotycz\u0105ce limit\u00f3w i rezerwacji.","status":"draft","featured_media":21680},"at":"2026-09-23T21:41:29+00:00"},"_wh_make_design_version":"2.1.5","rank_math_title":"Redis Lua Scripts f\u00fcr atomare Operationen","_wh_make_doc":{"title":"W\u0142a\u015bciwe wykorzystanie skrypt\u00f3w Lua w Redis do operacji atomowych","slug":"skrypty-lua-w-redis-operacje-atomowe","excerpt":"Skrypty Lua w Redis \u0142\u0105cz\u0105 odczyt, sprawdzanie i zapis w jedn\u0105 izolowan\u0105 operacj\u0119 serwera. Artyku\u0142 wyja\u015bnia poj\u0119cia KEYS i ARGV, EVAL i funkcje, ograniczenia klastra, umowy dotycz\u0105ce b\u0142\u0119d\u00f3w, a tak\u017ce bezpieczne wzorce dotycz\u0105ce limit\u00f3w i rezerwacji.","seo":{"title":"Skrypty Lua w Redis do operacji atomowych","description":"Atoarne stosowanie skrypt\u00f3w Lua w Redis: KEYS, ARGV, EVALSHA, funkcje, regu\u0142y klastrowania, obs\u0142uga b\u0142\u0119d\u00f3w i ograniczenia operacyjne \u2013 zrozumia\u0142e wyja\u015bnienia.","focus_keyword":"Redis Lua Scripts"},"lead":[{"kind":"text","text":"Redis Lua Scripts f\u00fchren mehrere Redis-Befehle samt Bedingungen isoliert auf dem Server aus. So entsteht zwischen Lesen, Pr\u00fcfen und Schreiben kein widerspr\u00fcchlicher Zwischenstand durch andere Clients. ","ref":""},{"kind":"strong","text":"Atomar bedeutet dabei nicht automatisches Rollback","ref":""},{"kind":"text","text":": Eingaben und Fehlerpfade m\u00fcssen vor allem vor Schreiboperationen bewusst entworfen werden. Entscheidend sind klar deklarierte Keys, stabile R\u00fcckgabewerte, kurze Laufzeiten und ein passendes Modell \u2013 vom nativen Befehl bis zur Redis Function. ","ref":""},{"kind":"citation","text":"","ref":"S1"},{"kind":"citation","text":"","ref":"S2"}],"images":{"hero":{"prompt":"Konzeptionelle technische Illustration zur atomaren Verarbeitung in Redis: links zwei konkurrierende Client-Anfragen, in der Mitte ein klar abgegrenzter Lua-Script-Ablauf mit Lesen, Pr\u00fcfen und Schreiben als ununterbrochene Sequenz, rechts ein konsistenter Key-Wert; ruhige dunkelblaue und t\u00fcrkisfarbene Farbgebung, klare Blickf\u00fchrung, viel Freiraum, keine Schrift, keine Zahlen, keine Logos.","alt":"Konzeptionelle Darstellung eines isolierten Redis Lua Script-Ablaufs zwischen mehreren Clients und einem konsistenten Schl\u00fcsselwert.","caption":"Die Illustration ordnet Lesen, Pr\u00fcfen und Schreiben als eine isolierte Serveroperation ein.","filename_base":"redis-lua-atomare-operationen","section_id":"","after_block":0},"detail1":{"prompt":"Konzeptionelle Illustration zur \u00dcbergabe von Redis Lua Script-Eingaben: zwei sauber getrennte Eingabekan\u00e4le f\u00fchren in ein kleines Script-Modul, einer f\u00fcr fest bekannte Schl\u00fcssel und einer f\u00fcr variable Fachwerte; danach gezielter Zugriff auf wenige Datenobjekte. Minimalistische technische Diagrammoptik in Blau und T\u00fcrkis, viel Freiraum, keine Schrift, keine Zahlen, keine Logos.","alt":"Konzeptionelle Trennung von Redis-Schl\u00fcsseln und Argumentwerten bei einem Lua Script.","caption":"Keys und fachliche Argumente folgen getrennten Wegen in die serverseitige Logik.","filename_base":"redis-lua-keys-argv","section_id":"interfaces","after_block":2},"detail2":{"prompt":"Konzeptionelle Illustration zu Betriebsgrenzen langer Redis Lua Scripts: ein kurzer kompakter Verarbeitungsweg h\u00e4lt den Server frei, daneben zeigt ein \u00fcberlanger verschlungener Ablauf wartende Client-Anfragen und ein Warnsignal; sachliche technische Infografik ohne Text, ohne Zahlen, ohne Logos, dunkelblaue Basis mit zur\u00fcckhaltenden orangefarbenen Akzenten, viel Freiraum.","alt":"Konzeptioneller Vergleich eines kurzen Redis Lua Scripts mit einem langen blockierenden Ablauf.","caption":"Kurze, begrenzte Script-Abl\u00e4ufe senken das Risiko blockierter Client-Anfragen.","filename_base":"redis-lua-lange-scripts-risiko","section_id":"operations","after_block":1}},"chart":null,"social":{"facebook":"Redis Lua Scripts verhindern Race Conditions bei zusammengesetzten Redis-Regeln. Der Fachartikel erkl\u00e4rt atomare Abl\u00e4ufe, KEYS und ARGV, Functions, Cluster-Grenzen sowie sichere Fehlerbehandlung.","instagram":"Lesen, pr\u00fcfen, schreiben \u2013 ohne Race Condition: Redis Lua Scripts b\u00fcndeln fachliche Regeln atomar auf dem Server. Wichtig bleiben kurze Laufzeiten, klare R\u00fcckgabewerte und kein falsches Rollback-Versprechen.","tiktok":"Redis Lua Scripts kurz erkl\u00e4rt: Sie machen mehrere Redis-Schritte atomar. Aber: Kein automatisches Rollback, keine langen Schleifen und im Cluster m\u00fcssen alle Keys in denselben Slot.","youtube":"Redis Lua Scripts f\u00fcr atomare Operationen: Wie EVAL, KEYS und ARGV funktionieren, wann Functions sinnvoll sind und welche Grenzen bei Cluster, Fehlern und langen Scripts gelten.","threads":"Lua Scripts k\u00f6nnen Redis-Operationen atomar verbinden. Sie ersetzen aber keine vollst\u00e4ndige Transaktion mit Rollback und keine Abstimmung mit externen Systemen.","x":"Redis Lua Scripts b\u00fcndeln Lesen, Pr\u00fcfen und Schreiben atomar auf dem Server. Entscheidend: KEYS und ARGV sauber trennen, R\u00fcckgabevertr\u00e4ge definieren, NOSCRIPT behandeln und Scripts kurz halten. Functions ab Redis 7.0 sind ein eigenes Bereitstellungsmodell."},"avatar_script":"Redis Lua Scripts sind sinnvoll, wenn eine Fachregel mehrere Redis-Befehle ohne Race Condition verbinden muss. Das Script l\u00e4uft isoliert auf dem Server: Andere Clients sehen keinen Zwischenstand zwischen Lesen, Pr\u00fcfen und Schreiben. Daraus wird aber keine Transaktion mit automatischem Rollback. Pr\u00fcfe Eingaben und Voraussetzungen deshalb vor der ersten \u00c4nderung. \u00dcbergib alle Schl\u00fcssel \u00fcber KEYS und variable Werte \u00fcber ARGV, besonders im Cluster. Halte die Logik kurz, denn lange Scripts blockieren andere Anfragen. F\u00fcr wiederverwendbare, versionierte Datenlogik k\u00f6nnen Redis Functions ab Version 7.0 geeigneter sein. Technische Fehler wie NOSCRIPT oder WRONGTYPE m\u00fcssen Anwendungen anders behandeln als eine fachlich erwartete Ablehnung.","version_note":"Recherche- und Versionsstand: 23. September 2026. Der Artikel behandelt Redis Open Source und unterscheidet EVAL-Scripts von Redis Functions ab Redis 7.0. Versionsgrenzen und verf\u00fcgbare Befehle vor dem Einsatz gegen die konkret betriebene Redis-Version pr\u00fcfen.","sections":[{"id":"atomicity","heading":"Atomare Redis Lua Scripts einordnen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Redis Lua Scripts f\u00fchren fachliche Datenlogik direkt im Redis-Server aus. W\u00e4hrend ein Script l\u00e4uft, verarbeitet Redis keine anderen Serveraktivit\u00e4ten; die enthaltenen Befehle sind daher gegen\u00fcber anderen Clients isoliert. Damit lassen sich mehrere einfache Kommandos zu einer ","ref":""},{"kind":"strong","text":"atomaren Operation","ref":""},{"kind":"text","text":" verbinden, etwa eine Limitpr\u00fcfung mit anschlie\u00dfendem Z\u00e4hler-Update oder eine Abbuchung nur bei ausreichendem Guthaben. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ohne Script kann ein Client zun\u00e4chst mit GET einen Z\u00e4hler lesen, die Grenze im Anwendungscode pr\u00fcfen und danach INCR senden. Zwischen diesen Schritten kann jedoch ein anderer Client denselben Z\u00e4hler ver\u00e4ndern. Ein Script liest, pr\u00fcft und erh\u00f6ht dagegen ohne diesen beobachtbaren Zwischenzustand. Das l\u00f6st die Race Condition der zusammengesetzten Regel, nicht aber automatisch Fragen wie passende Grenzwerte, Ablaufzeiten oder R\u00fcckgabeformate. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Atomar und isoliert bedeutet nicht, dass Redis Lua Scripts Datenbanktransaktionen mit automatischem Rollback sind. Tritt nach einer bereits erfolgten Schreiboperation ein Laufzeitfehler auf, werden vorherige \u00c4nderungen nicht pauschal zur\u00fcckgenommen. Deshalb sollten Scripts Eingaben, Datentypen und fachliche Voraussetzungen vor dem ersten Schreiben pr\u00fcfen; Fehlerpfade nach \u00c4nderungen brauchen eine bewusst entworfene Behandlung. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Typische Regeln sind: einen Zugriff nur innerhalb eines Limits zulassen oder einen Bestand nur bei ausreichender Menge reduzieren. Pr\u00fcfe zun\u00e4chst, ob ein vorhandener einzelner Redis-Befehl die gesamte Regel bereits ausdr\u00fcckt. Ein Script ist dann sinnvoll, wenn mehrere Redis-Operationen einschlie\u00dflich ihrer Bedingungen atomar zusammenwirken m\u00fcssen.","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ein Lua-Muster f\u00fcr Vergleich-und-L\u00f6schen vergleicht den gespeicherten Wert mit einem \u00fcbergebenen Ownership-Token und l\u00f6scht nur bei Gleichheit. Dadurch kann ein versp\u00e4teter Prozess nicht allein wegen seines alten Tokens einen inzwischen neu belegten Key l\u00f6schen.","ref":""}]},{"type":"paragraph","runs":[{"kind":"text","text":"Dieses Vergleichsmuster beschreibt ausschlie\u00dflich die sichere Reihenfolge f\u00fcr einen einzelnen Redis-Key. Es l\u00f6st nicht die weitergehenden Fragen verteilter Sperren, etwa passende Lease-Dauern, Prozesspausen, Ausf\u00e4lle oder die Koordination mehrerer Redis-Instanzen. Die Atomizit\u00e4t eines Befehls oder Scripts umfasst zudem nur die beteiligten Redis-Daten, nicht Zahlung, Datenbank, E-Mail oder externe APIs.","ref":""}]}]},{"id":"runtime","heading":"Lua Sandbox und klare Grenzen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Redis Open Source bettet f\u00fcr Scripts Lua 5.1 ein. Diese Laufzeit ist nicht mit einer lokal installierten oder aktuellen Lua-Hauptversion gleichzusetzen: Verf\u00fcgbarer Sprachumfang und Sicherheitsregeln bestimmt Redis. Wer redis lua scripts entwickelt, sollte sie deshalb gegen die tats\u00e4chlich eingesetzte Redis-Version pr\u00fcfen und nicht Eigenschaften einer beliebigen externen Lua-Umgebung voraussetzen. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Die Ausf\u00fchrung erfolgt in einer ","ref":""},{"kind":"strong","text":"Sandbox","ref":""},{"kind":"text","text":" mit absichtlich engen Grenzen. Ein Script soll Redis-Daten und \u00fcbergebene Argumente verarbeiten, aber weder Dateisystem, Netzwerk noch Betriebssystemdienste nutzen. Externe HTTP-Aufrufe, das Versenden von Nachrichten oder der Zugriff auf lokale Dateien geh\u00f6ren daher in den Anwendungscode oder einen daf\u00fcr vorgesehenen Dienst, nicht in cache scripting. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Redis stellt ","ref":""},{"kind":"code","text":"KEYS","ref":""},{"kind":"text","text":" und ","ref":""},{"kind":"code","text":"ARGV","ref":""},{"kind":"text","text":" als globale Laufzeitvariablen bereit. F\u00fcr eigene Zwischenwerte und Hilfsfunktionen verwendest du dagegen lokale Variablen mit ","ref":""},{"kind":"code","text":"local","ref":""},{"kind":"text","text":". So bleibt erkennbar, welche Werte nur f\u00fcr diesen Aufruf gelten, und die Script-Logik erzeugt keine vermeidbaren Abh\u00e4ngigkeiten. Redis-Kommandos rufst du gezielt \u00fcber ","ref":""},{"kind":"code","text":"redis.call","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"redis.pcall","ref":""},{"kind":"text","text":" auf. ","ref":""},{"kind":"citation","text":"","ref":"S1"},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Die Sandbox ersetzt keine Kapazit\u00e4tsplanung. W\u00e4hrend regul\u00e4rer Ausf\u00fchrung blockiert ein Script andere Clients am Server, daher sind lange Schleifen, unbeschr\u00e4nkte Datenmengen und rechenintensive Auswertungen ungeeignet. Beschr\u00e4nke die Arbeit auf wenige, vorher bekannte Keys und kleine Berechnungen. Umfangreiche Analysen, SCAN-basierte Gesamtbest\u00e4nde oder Kommunikation mit Fremdsystemen w\u00fcrden die Betriebsrisiken erh\u00f6hen, ohne die Atomizit\u00e4t sinnvoll zu erweitern. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]}]},{"id":"interfaces","heading":"EVAL, KEYS und ARGV verstehen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Der unmittelbare Aufruf eines Scripts verwendet die Form ","ref":""},{"kind":"code","text":"EVAL script numkeys [key \u2026] [arg \u2026]","ref":""},{"kind":"text","text":". Nach dem Quelltext legt numkeys fest, wie viele folgende Parameter Schl\u00fcssel sind. Das Script erreicht sie \u00fcber KEYS mit einsbasierter Indexierung; alle weiteren Werte stehen in ARGV. Diese Trennung ist wesentlich: Schl\u00fcssel beschreiben die Redis-Daten, Argumente die fachlichen Eingaben wie Grenzwert, Betrag oder erwarteten Token. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ein Limit-Script erh\u00e4lt beispielsweise den Z\u00e4hler als KEYS[1] und den H\u00f6chstwert als ARGV[1]. Es liest den aktuellen Stand, wandelt den Grenzwert mit ","ref":""},{"kind":"code","text":"tonumber(ARGV[1])","ref":""},{"kind":"text","text":" in eine Zahl um und vergleicht beide Werte, bevor es erh\u00f6ht. Die Umwandlung macht die beabsichtigte numerische Fachregel explizit, statt sich auf eine implizite Behandlung von Argumentwerten zu verlassen. Fehlt ein Z\u00e4hler, kann das Script den gelesenen Wert gezielt als null behandeln. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Jeder Key, den das Script liest oder schreibt, muss vorab als Key-Argument angegeben werden. Key-Namen im Script aus Pr\u00e4fixen zusammenzusetzen oder aus gespeicherten Daten abzuleiten, ist kein belastbares Muster. Redis kann dann insbesondere bei Redis Open Source mit aktiviertem Cluster nicht vor der Ausf\u00fchrung nachvollziehen, welche Daten das Script ben\u00f6tigt. \u00dcbergib daher bekannte Schl\u00fcssel vollst\u00e4ndig \u00fcber KEYS und variable Fachwerte ausschlie\u00dflich \u00fcber ARGV. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Bei Redis Open Source mit aktiviertem Cluster m\u00fcssen die einem Script \u00fcbergebenen Keys au\u00dferdem im selben Hash Slot liegen. Die vorherige Deklaration erm\u00f6glicht diese Pr\u00fcfung, ersetzt sie aber nicht. F\u00fcr zusammengeh\u00f6rige Daten kann ein bewusst gew\u00e4hlter Hash Tag helfen, etwa ","ref":""},{"kind":"code","text":"account:{4711}:balance","ref":""},{"kind":"text","text":" und ","ref":""},{"kind":"code","text":"account:{4711}:reservations","ref":""},{"kind":"text","text":". Der Teil in geschweiften Klammern bestimmt hier die Slot-Zuordnung; dynamisch ermittelte Keys w\u00fcrden diese Planung unterlaufen. ","ref":""},{"kind":"citation","text":"","ref":"S6"}]}]},{"id":"limitexample","heading":"Fixed-Window-Z\u00e4hler atomar aktualisieren","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Das folgende Beispiel ist ein atomarer ","ref":""},{"kind":"strong","text":"Fixed-Window-Z\u00e4hler","ref":""},{"kind":"text","text":" f\u00fcr eine lokale Testinstanz. Es pr\u00fcft Z\u00e4hlerstand und Grenze in einem Serverlauf und setzt die Ablaufzeit nur beim ersten erfolgreichen Zugriff des Zeitfensters. Damit entf\u00e4llt das Zeitfenster zwischen einem GET im Anwendungscode und einem sp\u00e4teren INCR, in dem ein anderer Client den Z\u00e4hler ver\u00e4ndern k\u00f6nnte. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Der Aufruf \u00fcbergibt den Z\u00e4hler-Key, das Limit und die Fensterdauer in Sekunden. Status 1 bedeutet zugelassen, Status 0 bedeutet Limit erreicht. Status 2 meldet eine von den Vorpr\u00fcfungen erkannte ung\u00fcltige Eingabe, einen dort abgelehnten String-Z\u00e4hlerwert oder einen vorhandenen String-Z\u00e4hler ohne TTL. Enth\u00e4lt der Key einen anderen Redis-Datentyp, scheitert bereits GET mit einem technischen Typfehler; das Script liefert dann keinen Status 2. Auch andere Redis-Laufzeitfehler sind vom fachlichen R\u00fcckgabestatus zu unterscheiden. Das Beispiel ist keine Vorlage f\u00fcr Zugangsdaten, produktive Limits oder Lasttests.","ref":""}]},{"type":"paragraph","runs":[{"kind":"text","text":"Vor jeder Schreiboperation validiert das Script alle Zahlen als endliche positive Ganzzahlen innerhalb einer bewusst kleinen Obergrenze. Das ist mehr als eine Pr\u00fcfung mit ","ref":""},{"kind":"code","text":"tonumber","ref":""},{"kind":"text","text":": Werte wie ","ref":""},{"kind":"code","text":"1.5","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"1e3","ref":""},{"kind":"text","text":" werden abgelehnt. Die Grenze von einer Million verhindert zudem, dass Lua-Zahlenpr\u00e4zision oder der von ","ref":""},{"kind":"code","text":"INCR","ref":""},{"kind":"text","text":" erwartete Integer-String au\u00dferhalb des Beispielsbereichs relevant werden. Die maximale Fensterdauer von 86.400 Sekunden begrenzt auch die an ","ref":""},{"kind":"code","text":"EXPIRE","ref":""},{"kind":"text","text":" \u00fcbergebene Sekundenzahl.","ref":""}]},{"type":"code","language":"redis-cli","code":"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","source_ids":["S1","S3"]},{"type":"paragraph","runs":[{"kind":"text","text":"Der regul\u00e4re Ausdruck akzeptiert nur dezimale Ziffern; anschlie\u00dfend pr\u00fcft die Hilfsfunktion den Zahlenwert, die Ganzzahligkeit und die Obergrenze. Ein bereits vorhandener Z\u00e4hler darf nur ein nichtnegativer Ganzzahlwert im selben begrenzten Bereich sein. Dadurch kann ein negativer, gebrochener oder \u00fcbergro\u00dfer Wert die Limitsemantik nicht unbemerkt ver\u00e4ndern. Erst nach diesen Pr\u00fcfungen folgt ","ref":""},{"kind":"code","text":"INCR","ref":""},{"kind":"text","text":".","ref":""}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ist der Key nicht vorhanden, beginnt das Script bei 0. Existiert bereits ein g\u00fcltiger String-Z\u00e4hler ohne Ablaufzeit, liefert es Status 2 und schreibt nichts. Nach dem ersten ","ref":""},{"kind":"code","text":"INCR","ref":""},{"kind":"text","text":" setzt ","ref":""},{"kind":"code","text":"EXPIRE","ref":""},{"kind":"text","text":" die zuvor vollst\u00e4ndig gepr\u00fcfte TTL. Bei sp\u00e4teren Treffern bleibt sie unver\u00e4ndert, sodass das Fenster nicht fortlaufend verl\u00e4ngert wird. ","ref":""},{"kind":"citation","text":"","ref":"S1"},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Der ","ref":""},{"kind":"strong","text":"R\u00fcckgabevertrag","ref":""},{"kind":"text","text":" ist Teil der Schnittstelle: Das erste Array-Element beschreibt den Status, das zweite liefert je nach Status den Z\u00e4hlerstand oder eine Fehlerkennung. Der aufrufende Code sollte eine fachliche Ablehnung mit Status 0 anders behandeln als Status 2, der auf eine verletzte Voraussetzung hinweist. F\u00fcr weitere Informationen zur Wahl und Beobachtung von Ablaufzeiten ist der Artikel ","ref":""},{"kind":"internal_link","text":"Redis Key Expiration analysieren und optimieren","ref":"I2"},{"kind":"text","text":" eine erg\u00e4nzende Grundlage.","ref":""}]},{"type":"paragraph","runs":[{"kind":"text","text":"Die TTL wird hier bewusst nur beim ersten Treffer gesetzt. Ein Muster, das sie bei jedem Zugriff erneuert, h\u00e4tte eine andere Zeitsemantik und w\u00e4re kein Fixed Window mehr. ","ref":""},{"kind":"strong","text":"Lua-Atomizit\u00e4t","ref":""},{"kind":"text","text":" beseitigt nur die Race Condition. Ob Fixed Window, Sliding Window oder Token Bucket zur gew\u00fcnschten Fairness und Lastverteilung passt, entscheidet der gew\u00e4hlte Algorithmus, nicht die Scriptsprache. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]}]},{"id":"mechanisms","heading":"Passendes Atomizit\u00e4tsmodell ausw\u00e4hlen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Nicht jede zusammengesetzte Anforderung ben\u00f6tigt ein Script. Existiert ein einzelner Redis-Befehl, der die Fachregel bereits vollst\u00e4ndig ausdr\u00fcckt, ist er meist einfacher zu betreiben und zu pr\u00fcfen. F\u00fcr mehrstufige Regeln m\u00fcssen dagegen Bedingungen, Datentypen und R\u00fcckgabevertrag gemeinsam betrachtet werden.","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ab Redis Open Source 8.4 gibt es native Compare-and-Set- und Compare-and-Delete-Operationen f\u00fcr einzelne String-Keys: ","ref":""},{"kind":"code","text":"SET","ref":""},{"kind":"text","text":" unterst\u00fctzt die Vergleichsoptionen ","ref":""},{"kind":"code","text":"IFEQ\/IFNE\/IFDEQ\/IFDNE","ref":""},{"kind":"text","text":"; ","ref":""},{"kind":"code","text":"DELEX","ref":""},{"kind":"text","text":" \u00fcbernimmt bedingtes L\u00f6schen. F\u00fcr passende Einzel-Key-F\u00e4lle ist damit kein eigenes Vergleichsscript erforderlich. In Redis 8.2, 8.0 und 7.x stehen diese neuen SET-Optionen und DELEX nicht zur Verf\u00fcgung; dort bleiben passende WATCH- oder Lua-Muster relevant. ","ref":""},{"kind":"citation","text":"","ref":"S4"}]},{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr optimistisches Compare-and-Set kann WATCH vor MULTI und EXEC passend sein: \u00c4ndert ein beobachteter Key sich vor EXEC, wird die Transaktion abgebrochen, und der Client entscheidet \u00fcber einen erneuten Versuch. Auch Transaktionen bieten bei Fehlern w\u00e4hrend EXEC keinen allgemeinen Rollback. WATCH bleibt daher eine Option, wenn die notwendige Bedingung nicht durch einen einzelnen nativen Befehl abgebildet wird. ","ref":""},{"kind":"citation","text":"","ref":"S4"}]},{"type":"table","caption":"Atomizit\u00e4tsmodelle f\u00fcr Redis-Operationen im Vergleich","headers":["Modell","Geeigneter Einsatzfall","Code und Aufruf","Nach Neustart oder Failover","Client-Verhalten und Grenze"],"rows":[["Nativer Befehl","Eine vorhandene Einzeloperation bildet die Regel ab","Kein Programmcode; direkter Befehl","Kein Script-Cache betroffen","Keine Script-Nachladung; auf vorhandene Semantik begrenzt"],["Native CAS\/CAD ab Redis Open Source 8.4","Wertabh\u00e4ngiges Setzen oder L\u00f6schen eines einzelnen String-Keys","SET mit IFEQ\/IFNE\/IFDEQ\/IFDNE; DELEX mit Vergleichsbedingung","Kein Script-Cache betroffen","Versionsgrenze und Vergleichsbedingung pr\u00fcfen; keine zusammengesetzte Mehr-Key-Regel"],["MULTI\/EXEC mit WATCH","Optimistisches Lesen, Pr\u00fcfen und Schreiben","WATCH, MULTI, EXEC","Kein Programmspeicher","Bei \u00c4nderung vor EXEC erneut lesen und entscheiden; kein Rollback bei EXEC-Fehlern"],["EVAL","Kleines, unmittelbar aufgerufenes Script","Quelltext bei jedem EVAL","Script-Cache ist nicht dauerhaft","Keine Digest-Nachladung; Quelltext wird wieder \u00fcbertragen"],["SCRIPT LOAD plus EVALSHA","Wiederverwendetes Script mit bekanntem Digest","Laden, danach Aufruf per SHA1-Digest","Cache kann fehlen","NOSCRIPT behandeln und erneut laden; Pipeline-Fallback besonders planen"],["Redis Functions ab 7.0","Benannte, wiederverwendbare Datenlogik","FUNCTION LOAD, danach FCALL","Bibliotheken werden repliziert und persistiert","Versions- und Bereitstellungsprozess n\u00f6tig; nicht mit EVAL gleichsetzen"]],"source_ids":["S1","S4","S5"]},{"type":"paragraph","runs":[{"kind":"text","text":"EVAL-Scripts sind an den Script-Cache gebunden und erhalten ihre Eingaben \u00fcber KEYS und ARGV. ","ref":""},{"kind":"strong","text":"Redis Functions","ref":""},{"kind":"text","text":" gibt es ab Redis 7.0 als benannte Bibliotheken: Sie werden mit FUNCTION LOAD registriert, mit FCALL aufgerufen sowie zusammen mit der Datenbank persistiert und repliziert. Ihre Schl\u00fcssel und Argumente erreichen die Funktion als Parameter; daraus folgt ein anderes Bereitstellungs- und Aufrufmodell als bei EVAL. ","ref":""},{"kind":"citation","text":"","ref":"S5"}]},{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr anwendungsnahe, kleine Logik ist EVAL daher ein direkter Einstieg. Mehrere Clients und langfristig gepflegte Datenlogik sprechen h\u00e4ufig f\u00fcr Functions, sofern die eingesetzte Redis-Open-Source-Version sie unterst\u00fctzt. Die Entscheidung sollte au\u00dferdem Deployment, Berechtigungen, Fehlerbehandlung und eine eindeutig dokumentierte R\u00fcckgabe ber\u00fccksichtigen, nicht nur die Zahl der Redis-Befehle. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]}]},{"id":"clustererrors","heading":"Cluster, Fehler und R\u00fcckgabevertr\u00e4ge","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Bei Redis Open Source mit aktiviertem Cluster m\u00fcssen die \u00fcbergebenen Keys eines Mehr-Key-Scripts im selben Hash Slot liegen. Hash Tags machen das steuerbar: Bei ","ref":""},{"kind":"code","text":"account:{4711}:balance","ref":""},{"kind":"text","text":" und ","ref":""},{"kind":"code","text":"account:{4711}:reservations","ref":""},{"kind":"text","text":" bestimmt der Inhalt zwischen geschweiften Klammern den Slot. Beide Keys k\u00f6nnen deshalb gemeinsam angesprochen werden. Die Same-Slot-Voraussetzung gilt dort auch f\u00fcr die hier betrachteten Mehrschl\u00fcsseloperationen und MULTI\/EXEC-Transaktionen. Andere Produkt- und Clusterkonfigurationen k\u00f6nnen bei einzelnen Befehlen abweichen. Daraus folgt keine allgemeine Cross-Slot-Freigabe f\u00fcr Lua: Die Mehrschl\u00fcssel-Dokumentation ordnet EVAL\/EVALSHA auch bei Redis Software mit aktiviertem Cluster und mit oder ohne OSS Cluster API als Single-Slot-Operation ein. ","ref":""},{"kind":"citation","text":"","ref":"S6"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Alle verwendeten Schl\u00fcssel m\u00fcssen vor dem Aufruf als Key-Argumente deklariert werden. Ein Script darf Key-Namen nicht aus gespeicherten Werten ableiten oder dynamisch zusammensetzen. Diese Regel erm\u00f6glicht Redis die korrekte Slot-Pr\u00fcfung vor der Ausf\u00fchrung und verhindert verdeckte Abh\u00e4ngigkeiten, die in einer Standalone-Instanz unauff\u00e4llig bleiben, bei Redis Open Source mit aktiviertem Cluster aber scheitern. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Mit ","ref":""},{"kind":"code","text":"redis.call()","ref":""},{"kind":"text","text":" wird ein Fehler des aufgerufenen Redis-Kommandos als Scriptfehler an den Client weitergegeben. ","ref":""},{"kind":"code","text":"redis.pcall()","ref":""},{"kind":"text","text":" liefert ihn dagegen an Lua zur\u00fcck, damit das Script ihn gezielt behandeln kann. pcall ist nur sinnvoll, wenn eine fachliche Reaktion definiert ist, etwa eine sauber strukturierte Fehlerantwort oder ein alternativer zul\u00e4ssiger Ablauf. Fehler still zu ignorieren verschleiert Daten- und Integrit\u00e4tsprobleme. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Ein ","ref":""},{"kind":"strong","text":"Fehlervertrag","ref":""},{"kind":"text","text":" trennt technische Fehler von fachlichen Ergebnissen. WRONGTYPE bedeutet etwa, dass der gespeicherte Redis-Datentyp nicht zum erwarteten Befehl passt und untersucht werden muss. Eine abgelehnte Reservierung wegen fehlenden Bestands ist dagegen ein erwartetes Ergebnis und kann beispielsweise Status und Restbestand zur\u00fcckgeben. Anwendungen sollten diese Kategorien nicht gleich behandeln oder beide pauschal wiederholen. ","ref":""},{"kind":"citation","text":"","ref":"S3"}]}]},{"id":"delivery","heading":"Script-Auslieferung robust betreiben","blocks":[{"type":"paragraph","runs":[{"kind":"code","text":"EVAL","ref":""},{"kind":"text","text":" eignet sich f\u00fcr unmittelbare Aufrufe: Der Client \u00fcbertr\u00e4gt den vollst\u00e4ndigen Lua-Quelltext zusammen mit Key- und Argumentwerten. F\u00fcr ein h\u00e4ufig verwendetes, unver\u00e4ndertes Script kann die Anwendung es stattdessen mit ","ref":""},{"kind":"code","text":"SCRIPT LOAD","ref":""},{"kind":"text","text":" in den Script-Cache laden. Redis liefert daf\u00fcr einen SHA1-Digest zur\u00fcck; ","ref":""},{"kind":"code","text":"EVALSHA","ref":""},{"kind":"text","text":" f\u00fchrt anschlie\u00dfend genau den dazugeh\u00f6rigen Quelltext aus. Das spart die wiederholte \u00dcbertragung, \u00e4ndert aber weder die Atomizit\u00e4t noch die fachliche Verantwortung des Scripts.","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Der ","ref":""},{"kind":"strong","text":"Script-Cache","ref":""},{"kind":"text","text":" ist nicht dauerhaft. Nach einem Neustart, Failover oder ","ref":""},{"kind":"code","text":"SCRIPT FLUSH","ref":""},{"kind":"text","text":" kann ein Aufruf per Digest mit ","ref":""},{"kind":"code","text":"NOSCRIPT","ref":""},{"kind":"text","text":" scheitern. Die Anwendung sollte diesen Fall regul\u00e4r behandeln: Script erneut laden und den fachlich sicheren Aufruf wiederholen, sofern die eigene Retry-Logik das zul\u00e4sst. Ein Digest darf daher nicht als Zusage verstanden werden, dass das Script auf jedem Zielserver bereits vorhanden ist.","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Bei Pipelines ist dieser Fallback eingeschr\u00e4nkt. Sind mehrere Befehle bereits gemeinsam gesendet, kann die Anwendung einen darin auftretenden ","ref":""},{"kind":"code","text":"NOSCRIPT","ref":""},{"kind":"text","text":"-Fehler nicht r\u00fcckwirkend durch Laden und erneutes Ausf\u00fchren an derselben Stelle ersetzen. Redis empfiehlt f\u00fcr solche F\u00e4lle parameterisiertes ","ref":""},{"kind":"code","text":"EVAL","ref":""},{"kind":"text","text":" als Ausweichstrategie. Wer Replikation und Failover plant, sollte au\u00dferdem verstehen, welche Rolle der Replikationspuffer bei der Wiederanbindung einer Replica spielt: ","ref":""},{"kind":"internal_link","text":"Redis Replication Backlog verstehen","ref":"I1"},{"kind":"text","text":".","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Variable Werte geh\u00f6ren nicht in den Lua-Quelltext, sondern in ","ref":""},{"kind":"code","text":"ARGV","ref":""},{"kind":"text","text":". Andernfalls erzeugt etwa jeder Grenzwert ein anderes Script und vergr\u00f6\u00dfert den Cache unn\u00f6tig. Seit Redis 7.4 k\u00f6nnen per ","ref":""},{"kind":"code","text":"EVAL","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"EVAL_RO","ref":""},{"kind":"text","text":" geladene Scripts bei einer Cache-Grenze nach LRU entfernt werden; das ersetzt weder Parametrisierung noch die Behandlung von ","ref":""},{"kind":"code","text":"NOSCRIPT","ref":""},{"kind":"text","text":".","ref":""},{"kind":"citation","text":"","ref":"S3"}]}]},{"id":"operations","heading":"Lange Scripts und Schreibfehler beherrschen","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"Ein Lua-Script blockiert w\u00e4hrend seiner regul\u00e4ren Ausf\u00fchrung andere Serveraktivit\u00e4ten. Das schafft Isolation, wird bei langen Laufzeiten aber zum ","ref":""},{"kind":"strong","text":"Betriebsrisiko","ref":""},{"kind":"text","text":". \u00dcberschreitet ein Script den konfigurierten ","ref":""},{"kind":"code","text":"busy-reply-threshold","ref":""},{"kind":"text","text":", antwortet Redis auf normale Befehle mit ","ref":""},{"kind":"code","text":"BUSY","ref":""},{"kind":"text","text":"; es beendet das Script nicht automatisch. Beschr\u00e4nke Scripts deshalb auf wenige bekannte Keys und kleine, begrenzte Berechnungen. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Schreiboperationen vor einem Fehler oder einer Endlosschleife sind besonders kritisch. Hat ein Script bereits Daten ver\u00e4ndert, kann ","ref":""},{"kind":"code","text":"SCRIPT KILL","ref":""},{"kind":"text","text":" es nicht sicher beenden. Pr\u00fcfe Eingaben daher vor dem ersten Schreiben und vermeide unbeschr\u00e4nkte Schleifen sowie ","ref":""},{"kind":"code","text":"SCAN","ref":""},{"kind":"text","text":" \u00fcber Gesamtbest\u00e4nde. Tests sollten Datenvolumen und Fehlerpfade des geplanten Einsatzes abbilden. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"table","caption":"Fehlerf\u00e4lle bei Redis Lua Scripts und sichere Reaktion der Anwendung","headers":["Fall","Erkennbare Antwort","Typische Ursache","Sichere Konsequenz"],"rows":[["NOSCRIPT","Fehlerantwort NOSCRIPT","Digest fehlt im fl\u00fcchtigen Script-Cache","Script laden oder parameterisiertes EVAL verwenden; nur nach eigener Retry-Regel wiederholen."],["CROSSSLOT","CROSSSLOT bei Redis Open Source mit aktiviertem Cluster","Die \u00fcbergebenen Keys des Scripts liegen in verschiedenen Hash Slots","Key-Design \u00e4ndern und alle erforderlichen Keys deklarieren."],["WRONGTYPE","Redis-Fehler WRONGTYPE","Key besitzt einen unerwarteten Datentyp","Datenmodell oder Script-Voraussetzung korrigieren; nicht als fachliche Ablehnung behandeln."],["Speicherdruck \u00fcber maxmemory","Schreiboperation kann das Script abbrechen","Redis liegt beim Start bereits \u00fcber dem Speicherlimit","Nicht blind wiederholen; bei redis.pcall einen sicheren, dokumentierten Fehlerpfad vorsehen."],["BUSY","Fehlerantwort BUSY f\u00fcr andere Befehle","Script \u00fcberschreitet den busy-reply-threshold","Last reduzieren und Script verkleinern; nach Schreibvorg\u00e4ngen nicht auf Killen bauen."],["Fachliche Ablehnung","Dokumentierter Statuswert","Etwa Limit erreicht oder Bestand zu niedrig","Status auswerten und den Gesch\u00e4ftsvorgang geordnet ablehnen."]],"source_ids":["S1","S2","S3","S6"]},{"type":"paragraph","runs":[{"kind":"text","text":"Bei ","ref":""},{"kind":"strong","text":"maxmemory","ref":""},{"kind":"text","text":" h\u00e4ngt der Ablauf von der ersten Schreiboperation ab. Liegt Redis bereits \u00fcber dem Limit, kann ein speicherverbrauchender Befehl bei ","ref":""},{"kind":"code","text":"redis.call","ref":""},{"kind":"text","text":" das Script abbrechen; ","ref":""},{"kind":"code","text":"redis.pcall","ref":""},{"kind":"text","text":" liefert den Fehler an Lua zur\u00fcck und verlangt einen bewusst entworfenen Fehlerpfad. Bereits ausgef\u00fchrte \u00c4nderungen werden dadurch nicht repariert. ","ref":""},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Eine erste Operation ohne zus\u00e4tzlichen Speicherbedarf, etwa ","ref":""},{"kind":"code","text":"DEL","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"LREM","ref":""},{"kind":"text","text":", kann das Script dagegen weiterlaufen lassen; sp\u00e4tere Schreibvorg\u00e4nge k\u00f6nnen den Verbrauch \u00fcber ","ref":""},{"kind":"code","text":"maxmemory","ref":""},{"kind":"text","text":" erh\u00f6hen. Technische Fehler wie ","ref":""},{"kind":"code","text":"WRONGTYPE","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"CROSSSLOT","ref":""},{"kind":"text","text":" bei Redis Open Source mit aktiviertem Cluster verlangen Korrekturen am Datenmodell beziehungsweise Key-Design, w\u00e4hrend nur das Script selbst eine fachliche Ablehnung als stabilen Status definieren kann. ","ref":""},{"kind":"citation","text":"","ref":"S1"},{"kind":"citation","text":"","ref":"S3"},{"kind":"citation","text":"","ref":"S6"}]}]},{"id":"decisions","heading":"Geeignete Einsatzf\u00e4lle bewusst entscheiden","blocks":[{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr eine bedingte Reservierung kann ein Script Bestand pr\u00fcfen, einen zu kleinen Wert ablehnen und bei Erfolg den Restbestand zur\u00fcckgeben. Die ","ref":""},{"kind":"strong","text":"atomare Reservierung","ref":""},{"kind":"text","text":" umfasst jedoch nur Redis. Zahlung, relationale Datenbank, E-Mail und externe APIs ben\u00f6tigen eine eigene Abstimmung und gegebenenfalls Ausgleichslogik. ","ref":""},{"kind":"citation","text":"","ref":"S2"}]},{"type":"paragraph","runs":[{"kind":"text","text":"Die Auswahl h\u00e4ngt von Redis-Version und Datenmodell ab. Ab Redis Open Source 8.4 k\u00f6nnen die Vergleichsoptionen von ","ref":""},{"kind":"code","text":"SET","ref":""},{"kind":"text","text":" ein bedingtes Setzen und ","ref":""},{"kind":"code","text":"DELEX","ref":""},{"kind":"text","text":" das Vergleich-und-L\u00f6schen eines einzelnen String-Keys \u00fcbernehmen. Vor Redis 8.4 oder bei einer komplexeren Bedingung ist ","ref":""},{"kind":"code","text":"WATCH","ref":""},{"kind":"text","text":" mit ","ref":""},{"kind":"code","text":"MULTI\/EXEC","ref":""},{"kind":"text","text":" eine Alternative: \u00c4ndert sich ein beobachteter Key vor EXEC, bricht die Transaktion ab und der Client entscheidet \u00fcber erneutes Lesen und Wiederholen. Ein kurzes Lua-Script passt, wenn mehrere Befehle oder Datenstrukturen einschlie\u00dflich ihrer Fachregel serverseitig zusammenwirken m\u00fcssen. ","ref":""},{"kind":"citation","text":"","ref":"S4"},{"kind":"citation","text":"","ref":"S1"}]},{"type":"paragraph","runs":[{"kind":"text","text":"F\u00fcr verteilte Sperren gen\u00fcgt weder der einzelne Befehl noch das Lua-Muster als Gesamtkonzept. Lease-Dauer, Prozesspausen, Ausf\u00e4lle, Wiederholungen, Failover und Mehrinstanzenszenarien bleiben separat zu bewerten. Bevorzuge einen nativen Befehl, wenn die betriebene Version und seine Semantik die gesamte Regel abdecken. Andernfalls sind ","ref":""},{"kind":"code","text":"WATCH","ref":""},{"kind":"text","text":" und ein kurzes Script je nach Fehlervertrag und Ort der Fachlogik abzuw\u00e4gen. F\u00fcr wiederverwendbare serverseitige Logik kann eine Redis Function passen. ","ref":""},{"kind":"strong","text":"Read-only-Scripts","ref":""},{"kind":"text","text":" d\u00fcrfen ab Redis 7.0 \u00fcber ","ref":""},{"kind":"code","text":"EVAL_RO","ref":""},{"kind":"text","text":" oder ","ref":""},{"kind":"code","text":"EVALSHA_RO","ref":""},{"kind":"text","text":" laufen, aber nur bei garantiert schreibfreier Logik. ","ref":""},{"kind":"citation","text":"","ref":"S4"},{"kind":"citation","text":"","ref":"S7"}]}]}]},"_wh_make_word_report":{"words":2694,"min":2000,"max":3000,"target":2500,"ok":true,"missing":0,"excess":0,"lead_words":63,"section_words":{"atomicity":293,"runtime":206,"interfaces":250,"limitexample":420,"mechanisms":420,"clustererrors":256,"delivery":238,"operations":346,"decisions":202}},"_wh_make_review":{"verdict":"pass","issues":[],"checked_source_ids":["S1","S2","S3","S4","S5","S6","S7"],"summary":"Der Artikel ist fachlich plausibel und wird von den gepr\u00fcften Redis-Dokumentationsseiten getragen. Atomizit\u00e4t und fehlender automatischer Rollback werden korrekt abgegrenzt; EVAL, EVALSHA, Redis Functions, WATCH\/MULTI\/EXEC und die nativen Vergleichsoperationen ab Redis Open Source 8.4 bleiben sauber getrennt. Versionsangaben zu Functions, Read-only-Scripts und Script-Cache-Eviction stimmen. Das Fixed-Window-Beispiel ist in sich konsistent, validiert Eingaben vor dem Schreiben und dokumentiert TTL- sowie R\u00fcckgabesemantik nachvollziehbar. Cluster- und Same-Slot-Regeln, NOSCRIPT-, WRONGTYPE-, BUSY- und maxmemory-F\u00e4lle sind angemessen eingeordnet. Tabellen, interne Links, Bildkonzepte und Versionshinweis enthalten keine erkennbaren fachlichen Freigabehindernisse; erfundene Messungen oder Testsiegerbehauptungen liegen nicht vor."},"_wh_make_review_doc_hash":"67582c463fdae7fec9f4fcb2567143022e43f24b4ce6ad2eb0025678409c4c52","_yoast_wpseo_primary_category":null,"rank_math_schema_blogposting":null,"rank_math_schema_videoobject":null,"_oembed_049c719bc4a9f89deaead66a7da9fddc":null,"_oembed_time_049c719bc4a9f89deaead66a7da9fddc":null,"_yoast_wpseo_focuskw":null,"inline_featured_image":null,"_yoast_wpseo_linkdex":null,"_eael_widget_elements":null,"_oembed_c3b0f6959478faf92a1f343d8f96b19e":null,"_oembed_27e3473bf8bec795fbeb3a9d38489348":null,"_trp_translated_slug_en_us":null,"_yoast_wpseo_title":null,"tldname":null,"tldpreis":null,"tldrubrik":null,"tldpolicylink":null,"tldsize":null,"tldregistrierungsdauer":null,"tldtransfer":null,"tldwhoisprivacy":null,"tldregistrarchange":null,"tldregistrantchange":null,"tldwhoisupdate":null,"tldnameserverupdate":null,"tlddeletesofort":null,"tlddeleteexpire":null,"tldumlaute":null,"tldrestore":null,"tldsubcategory":null,"tldbildname":null,"tldbildurl":null,"tldclean":null,"tldcategory":null,"tldpolicy":null,"tldbesonderheiten":null,"tld_bedeutung":null,"_oembed_d167040d816d8f94c072940c8009f5f8":null,"_oembed_b0a0fa59ef14f8870da2c63f2027d064":null,"_oembed_4792fa4dfb2a8f09ab950a73b7f313ba":null,"_oembed_33ceb1fe54a8ab775d9410abf699878d":null,"_oembed_fd7014d14d919b45ec004937c0db9335":null,"_oembed_21a029d076783ec3e8042698c351bd7e":null,"_oembed_be5ea8a0c7b18e658f08cc571a909452":null,"_oembed_a9ca7a298b19f9b48ec5914e010294d2":null,"_oembed_f8db6b27d08a2bb1f920e7647808899a":null,"_oembed_168ebde5096e77d8a89326519af9e022":null,"_oembed_cdb76f1b345b42743edfe25481b6f98f":null,"_oembed_87b0613611ae54e86e8864265404b0a1":null,"_oembed_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_oembed_time_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_tldname":null,"_tldclean":null,"_tldpreis":null,"_tldcategory":null,"_tldsubcategory":null,"_tldpolicy":null,"_tldpolicylink":null,"_tldsize":null,"_tldregistrierungsdauer":null,"_tldtransfer":null,"_tldwhoisprivacy":null,"_tldregistrarchange":null,"_tldregistrantchange":null,"_tldwhoisupdate":null,"_tldnameserverupdate":null,"_tlddeletesofort":null,"_tlddeleteexpire":null,"_tldumlaute":null,"_tldrestore":null,"_tldbildname":null,"_tldbildurl":null,"_tld_bedeutung":null,"_tldbesonderheiten":null,"_oembed_8357e2b8a2575c74ed5978f262a10126":null,"_oembed_ad96e4112edb9f8ffa35731d4098bc6b":null,"_oembed_3d5fea5103dd0d22ec5d6a33eff7f863":null,"_oembed_819a879e7da16dd629cfd15a97334c8a":null,"_oembed_time_819a879e7da16dd629cfd15a97334c8a":null,"_wh_make_writer_raw":null,"_wh_make_design_backup_204":null,"_wp_desired_post_slug":null,"_oembed_0d8a206f09633e3d62b95a15a4dd0487":null,"_oembed_time_0d8a206f09633e3d62b95a15a4dd0487":null,"_aioseo_description":null,"_eb_attr":null,"_eb_data_table":null,"_acf_changed":null,"_wpcode_auto_insert":null,"_edit_last":"1","_edit_lock":"1790251698:1","_oembed_e7b913c6c84084ed9702cb4feb012ddd":null,"_oembed_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_time_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_03514b67990db061d7c4672de26dc514":null,"_oembed_time_03514b67990db061d7c4672de26dc514":null,"rank_math_news_sitemap_robots":null,"rank_math_robots":null,"_eael_post_view_count":"108","_trp_automatically_translated_slug_ru_ru":null,"_trp_automatically_translated_slug_et":null,"_trp_automatically_translated_slug_lv":null,"_trp_automatically_translated_slug_fr_fr":null,"_trp_automatically_translated_slug_en_us":null,"_wp_old_slug":null,"_trp_automatically_translated_slug_da_dk":null,"_trp_automatically_translated_slug_pl_pl":null,"_trp_automatically_translated_slug_es_es":null,"_trp_automatically_translated_slug_hu_hu":null,"_trp_automatically_translated_slug_fi":null,"_trp_automatically_translated_slug_ja":null,"_trp_automatically_translated_slug_lt_lt":null,"_elementor_edit_mode":null,"_elementor_template_type":null,"_elementor_version":null,"_elementor_pro_version":null,"_wp_page_template":null,"_elementor_page_settings":null,"_elementor_data":null,"_elementor_css":null,"_elementor_conditions":null,"_happyaddons_elements_cache":null,"_oembed_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_time_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_time_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_59808117857ddf57e478a31d79f76e4d":null,"_oembed_time_59808117857ddf57e478a31d79f76e4d":null,"_oembed_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_time_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_81002f7ee3604f645db4ebcfd1912acf":null,"_oembed_time_81002f7ee3604f645db4ebcfd1912acf":null,"_elementor_screenshot":null,"_oembed_7ea3429961cf98fa85da9747683af827":null,"_oembed_time_7ea3429961cf98fa85da9747683af827":null,"_elementor_controls_usage":null,"_elementor_page_assets":[],"_elementor_screenshot_failed":null,"theplus_transient_widgets":null,"_eael_custom_js":null,"_wp_old_date":"2026-09-23","_trp_automatically_translated_slug_it_it":null,"_trp_automatically_translated_slug_pt_pt":null,"_trp_automatically_translated_slug_zh_cn":null,"_trp_automatically_translated_slug_nl_nl":null,"_trp_automatically_translated_slug_pt_br":null,"_trp_automatically_translated_slug_sv_se":null,"rank_math_analytic_object_id":null,"_trp_automatically_translated_slug_ro_ro":null,"_trp_automatically_translated_slug_sk_sk":null,"_trp_automatically_translated_slug_bg_bg":null,"_trp_automatically_translated_slug_sl_si":null,"litespeed_vpi_list":null,"litespeed_vpi_list_mobile":null,"rank_math_seo_score":"80","rank_math_contentai_score":null,"ilj_limitincominglinks":"","ilj_maxincominglinks":"1","ilj_limitoutgoinglinks":"","ilj_maxoutgoinglinks":"1","ilj_limitlinksperparagraph":"","ilj_linksperparagraph":"1","ilj_blacklistdefinition":[],"ilj_linkdefinition":[],"_eb_reusable_block_ids":null,"rank_math_focus_keyword":"Redis Lua Scripts","rank_math_og_content_image":null,"surfer_last_post_update":null,"surfer_last_post_update_direction":null,"surfer_keywords":null,"surfer_location":null,"surfer_draft_id":null,"surfer_permalink_hash":null,"surfer_scrape_ready":null,"_thumbnail_id":"21680","_yoast_wpseo_metadesc":null,"_yoast_wpseo_content_score":null,"_yoast_wpseo_focuskeywords":null,"_yoast_wpseo_keywordsynonyms":null,"_yoast_wpseo_estimated-reading-time-minutes":null,"rank_math_description":"Redis Lua Scripts atomar einsetzen: KEYS, ARGV, EVALSHA, Functions, Cluster-Regeln, Fehlerbehandlung und Betriebsgrenzen verst\u00e4ndlich erkl\u00e4rt.","footnotes":null,"_links":{"self":[{"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/posts\/21670","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/comments?post=21670"}],"version-history":[{"count":8,"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/posts\/21670\/revisions"}],"predecessor-version":[{"id":21683,"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/posts\/21670\/revisions\/21683"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/media\/21680"}],"wp:attachment":[{"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/media?parent=21670"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/categories?post=21670"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webhosting.de\/pl\/wp-json\/wp\/v2\/tags?post=21670"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}