{"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":"scripts-lua-de-redis-operaciones-atomicas","status":"publish","type":"post","link":"https:\/\/webhosting.de\/es\/redis-lua-scripts-atomare-operationen\/","title":{"rendered":"C\u00f3mo utilizar correctamente los scripts de Lua de Redis para operaciones at\u00f3micas"},"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>Los scripts de Lua de Redis combinan la lectura, la comprobaci\u00f3n y la escritura en una \u00fanica operaci\u00f3n aislada del servidor. El art\u00edculo explica KEYS y ARGV, EVAL y las funciones, los l\u00edmites del cl\u00faster, los contratos de error, as\u00ed como patrones seguros para l\u00edmites y reservas.<\/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":"Entender el backlog de replicaci\u00f3n de Redis: PSYNC, tama\u00f1o y l\u00edmites de alta disponibilidad","excerpt":"El \u00abbacklog\u00bb de replicaci\u00f3n de Redis influye a la hora de determinar si, tras una interrupci\u00f3n de la conexi\u00f3n, una r\u00e9plica solo recupera los cambios que faltan o si se le vuelve a transferir todo el conjunto de datos. Si se dimensiona el b\u00fafer en funci\u00f3n del volumen real de replicaci\u00f3n, se pueden evitar sincronizaciones completas innecesarias. Sin embargo, para ello es necesario que el historial de replicaci\u00f3n, el presupuesto de almacenamiento y los procesos operativos est\u00e9n en consonancia: un backlog grande no sustituye ni a la persistencia ni a un concepto de conmutaci\u00f3n por error robusto. Ir directamente a la secci\u00f3n: Qu\u00e9 almacena realmente el backlog; cu\u00e1ndo basta con PSYNC y cu\u00e1ndo es necesaria una resincronizaci\u00f3n completa; medir la tasa de replicaci\u00f3n en lugar de estimar el tama\u00f1o de la base de datos; calcular de forma comprensible el tama\u00f1o del backlog; modificar la configuraci\u00f3n de Redis de forma clara y controlada; supervisi\u00f3n: Qu\u00e9 valores van juntos. Clasificar correctamente el presupuesto de almacenamiento y las r\u00e9plicas lentas. Por qu\u00e9 un backlog grande no garantiza por s\u00ed solo una alta disponibilidad. Probar los cambios y delimitar los problemas recurrentes. \u00bfQu\u00e9 almacena realmente el backlog? En la replicaci\u00f3n de Redis, el primario procesa los cambios en el conjunto de datos y transmite un flujo continuo de comandos a sus r\u00e9plicas. Esto no incluye \u00fanicamente los valores escritos directamente por los clientes. Las claves caducadas o sustituidas tambi\u00e9n pueden desencadenar cambios que deben transmitirse. El backlog mantiene en la memoria RAM una secci\u00f3n limitada y reciente de este flujo de replicaci\u00f3n. Por lo tanto, no contiene una copia completa adicional de la base de datos ni es un archivo de operaciones de escritura de cualquier antig\u00fcedad. En condiciones normales de funcionamiento, las r\u00e9plicas siguen el flujo en curso. Si se interrumpe una conexi\u00f3n, el historial sigue creciendo en el servidor primario. Tras restablecerse la conexi\u00f3n, la r\u00e9plica intenta reanudarse desde el punto en el que se encontraba. En ese momento, es fundamental que los bytes necesarios sigan estando disponibles. Si es as\u00ed y el historial de replicaci\u00f3n coincide, Redis puede completar el lapso que faltaba. Los datos ya existentes"},"I2":{"id":"I2","post_id":21597,"url":"https:\/\/webhosting.de\/redis-key-expiration-performance-analysieren-optimieren-cache\/","title":"Analizar y optimizar el rendimiento de la caducidad de claves en Redis","excerpt":"Analizo de forma espec\u00edfica el rendimiento de la caducidad de claves de Redis y lo optimizo mediante pasos claros y cuantificables. De este modo, reduzco la latencia, suavizo los picos de carga y mantengo bajo control el consumo de memoria, sin comprometer el rendimiento. Puntos clave: resumo los aspectos m\u00e1s importantes sobre el rendimiento de la caducidad de claves de manera que los principiantes puedan empezar directamente y los usuarios avanzados puedan realizar ajustes espec\u00edficos. Los siguientes puntos clave se centran en los ajustes m\u00e1s eficaces y muestran d\u00f3nde surgen los cuellos de botella t\u00edpicos. Para ello, me centro en las estrategias de TTL, la limpieza activa y pasiva, as\u00ed como en el comportamiento de expulsi\u00f3n. Adem\u00e1s, establezco indicadores de monitorizaci\u00f3n que permiten detectar los problemas de forma temprana. De este modo, se puede evaluar el rendimiento de forma sistem\u00e1tica y controlarlo a largo plazo. Caducidad \u00ablazy\u00bb frente a \u00abactiva\u00bb: comprender y medir la interacci\u00f3n. Dispersi\u00f3n del TTL: compensaciones frente a la caducidad simult\u00e1nea. Ajuste de hz: Equilibrar la frecuencia de los ciclos en segundo plano. Pol\u00edtica de expulsi\u00f3n: \u00aballkeys-lru\u00bb frente a variantes \u00abvolatile\u00bb. Supervisi\u00f3n: observar los valores de caducidad, expulsi\u00f3n y latencia. Apuesto por TTL coherentes, una limpieza adaptativa y l\u00edmites claros. De este modo, distribuyo los momentos de caducidad, evito expulsiones innecesarias y mantengo los tiempos de respuesta fiablemente bajos. Adem\u00e1s, utilizo m\u00e9tricas que se\u00f1alan inmediatamente las fases an\u00f3malas y permiten tomar contramedidas precisas. Caducidad de claves en Redis: funcionamiento e influencia en la latencia. Redis combina la caducidad \u00ablazy\u00bb y la \u00abactiva\u00bb para combinar un alto rendimiento con una carga de CPU limitada. En la caducidad \u00ablazy\u00bb, el servidor solo elimina las claves al acceder a ellas cuando ha caducado el TTL. De este modo, no se generan operaciones en segundo plano adicionales para datos que, de todos modos, se leen peri\u00f3dicamente. La caducidad activa complementa el modelo mediante escaneos breves y frecuentes de las claves que est\u00e1n a punto de caducar, con el fin de eliminar las entradas olvidadas. Esta arquitectura mantiene bajas las latencias y libera memoria sin necesidad de costosos escaneos permanentes. Se produce una latencia apreciable sobre todo cuando un gran n\u00famero de entradas caducan en un intervalo de tiempo reducido. En ese caso, Redis dedica m\u00e1s recursos de CPU a la limpieza activa, lo que reduce temporalmente la capacidad para las operaciones de los clientes. La presi\u00f3n adicional sobre la memoria v"},"I3":{"id":"I3","post_id":21547,"url":"https:\/\/webhosting.de\/redis-expire-strategien-grosse-cache-systeme-cache-architektur\/","title":"Estrategias de caducidad de Redis para grandes sistemas de cach\u00e9: gu\u00eda pr\u00e1ctica para la optimizaci\u00f3n del rendimiento","excerpt":"Los grandes cl\u00fasteres de cach\u00e9, si no se aplican estrategias planificadas de caducidad en Redis, provocan r\u00e1pidamente cuellos de botella en la memoria y latencias variables; te mostrar\u00e9 c\u00f3mo combinar el TTL, la expulsi\u00f3n y la invalidaci\u00f3n para evitar picos de carga. Te proporciono pr\u00e1cticas recomendadas concretas para el dise\u00f1o de claves, los tiempos de caducidad y la monitorizaci\u00f3n, que funcionan de forma fiable en entornos de producci\u00f3n. Puntos clave: comprender y configurar de forma coherente la separaci\u00f3n entre caducidad y expulsi\u00f3n; establecer el TTL en todas partes, adem\u00e1s de combinar el jitter con la invalidaci\u00f3n contra el \u201eThundering Herd\u201c: \u00abDelete-on-write\u00bb, etiquetas, control de versiones. Elegir conscientemente la pol\u00edtica de expulsi\u00f3n y probarla con \u00abmaxmemory\u00bb. Orientar la monitorizaci\u00f3n hacia las claves caducadas o expulsadas, la tasa de aciertos y las latencias. Caducidad frente a expulsi\u00f3n: C\u00f3mo borra Redis En mi planificaci\u00f3n, siempre distingo claramente entre caducidad y expulsi\u00f3n, ya que ambos procesos persiguen objetivos diferentes. La caducidad elimina las claves al vencimiento del TTL, mientras que la expulsi\u00f3n solo se aplica cuando se agota el l\u00edmite de memoria configurado. Con la caducidad diferida (Lazy Expiration), Redis comprueba en cada acceso si una clave ha caducado y, adem\u00e1s, limpia activamente, a intervalos, las entradas seleccionadas al azar. Este m\u00e9todo mixto evita la sobrecarga del temporizador por clave y mantiene baja la carga administrativa. Quien comprenda este mecanismo puede controlar de forma espec\u00edfica cu\u00e1nta memoria \u00abmuerta\u00bb se tolera a corto plazo sin provocar fallos inesperados en la cach\u00e9. Dise\u00f1o del TTL: tiempos, fluctuaciones y jerarquizaci\u00f3n Asigno un TTL a cada clave de cach\u00e9, incluso cuando utilizo la invalidaci\u00f3n expl\u00edcita, ya que un tiempo de caducidad constituye una importante red de seguridad. Para los datos cercanos al usuario, suelo empezar con 5-15 minutos, pero adapto el intervalo a la frecuencia de cambios y a la tolerancia a las lecturas obsoletas. Las sesiones tienen duraciones cortas, los detalles de los productos suelen tenerlas m\u00e1s largas y las configuraciones cuentan con un margen a\u00fan mayor; as\u00ed distribuyo el riesgo y suavizo la carga. Adem\u00e1s, a\u00f1ado un ligero jitter, de unos \u00b110 %, para que no caduquen miles de claves al mismo tiempo. En las cach\u00e9s de varios niveles, hago que la memoria de la aplicaci\u00f3n act\u00fae en segundos, que Redis funcione en minutos u horas y que los niveles previos se mantengan durante m\u00e1s tiempo, para evitar costosas reconstrucciones. Invalidaci\u00f3n expl\u00edcita sin efectos secundarios 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":"C\u00f3mo utilizar correctamente los scripts de Lua de Redis para operaciones at\u00f3micas","slug":"scripts-lua-de-redis-operaciones-atomicas","excerpt":"Los scripts de Lua de Redis combinan la lectura, la comprobaci\u00f3n y la escritura en una \u00fanica operaci\u00f3n aislada del servidor. El art\u00edculo explica KEYS y ARGV, EVAL y las funciones, los l\u00edmites del cl\u00faster, los contratos de error, as\u00ed como patrones seguros para l\u00edmites y reservas.","status":"draft","featured_media":21680},"verify":{"content_md5":"fd52d6dfbe40e10e736d67fc569e8a60","title":"C\u00f3mo utilizar correctamente los scripts de Lua de Redis para operaciones at\u00f3micas","slug":"scripts-lua-de-redis-operaciones-atomicas","excerpt":"Los scripts de Lua de Redis combinan la lectura, la comprobaci\u00f3n y la escritura en una \u00fanica operaci\u00f3n aislada del servidor. El art\u00edculo explica KEYS y ARGV, EVAL y las funciones, los l\u00edmites del cl\u00faster, los contratos de error, as\u00ed como patrones seguros para l\u00edmites y reservas.","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":"C\u00f3mo utilizar correctamente los scripts de Lua de Redis para operaciones at\u00f3micas","slug":"scripts-lua-de-redis-operaciones-atomicas","excerpt":"Los scripts de Lua de Redis combinan la lectura, la comprobaci\u00f3n y la escritura en una \u00fanica operaci\u00f3n aislada del servidor. El art\u00edculo explica KEYS y ARGV, EVAL y las funciones, los l\u00edmites del cl\u00faster, los contratos de error, as\u00ed como patrones seguros para l\u00edmites y reservas.","status":"draft","featured_media":0},"expected":{"content_md5":"fd52d6dfbe40e10e736d67fc569e8a60","title":"C\u00f3mo utilizar correctamente los scripts de Lua de Redis para operaciones at\u00f3micas","slug":"scripts-lua-de-redis-operaciones-atomicas","excerpt":"Los scripts de Lua de Redis combinan la lectura, la comprobaci\u00f3n y la escritura en una \u00fanica operaci\u00f3n aislada del servidor. El art\u00edculo explica KEYS y ARGV, EVAL y las funciones, los l\u00edmites del cl\u00faster, los contratos de error, as\u00ed como patrones seguros para l\u00edmites y reservas.","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":"C\u00f3mo utilizar correctamente los scripts de Lua de Redis para operaciones at\u00f3micas","slug":"scripts-lua-de-redis-operaciones-atomicas","excerpt":"Los scripts de Lua de Redis combinan la lectura, la comprobaci\u00f3n y la escritura en una \u00fanica operaci\u00f3n aislada del servidor. El art\u00edculo explica KEYS y ARGV, EVAL y las funciones, los l\u00edmites del cl\u00faster, los contratos de error, as\u00ed como patrones seguros para l\u00edmites y reservas.","seo":{"title":"Scripts de Lua para Redis destinados a operaciones at\u00f3micas","description":"Uso at\u00f3mico de los scripts Lua de Redis: KEYS, ARGV, EVALSHA, funciones, reglas de cl\u00faster, gesti\u00f3n de errores y l\u00edmites operativos explicados de forma clara.","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":"111","_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\/es\/wp-json\/wp\/v2\/posts\/21670","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/comments?post=21670"}],"version-history":[{"count":8,"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/posts\/21670\/revisions"}],"predecessor-version":[{"id":21683,"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/posts\/21670\/revisions\/21683"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/media\/21680"}],"wp:attachment":[{"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/media?parent=21670"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/categories?post=21670"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webhosting.de\/es\/wp-json\/wp\/v2\/tags?post=21670"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}