Logo GH

Wiederholungsstrategien und Idempotenz

1) Warum es notwendig ist

In Netzwerken sind Störungen die Norm: Timeouts, transiente Fehler, Netzwerkflapping, Überlastung. Retrays erhöhen die Zuverlässigkeit nur, wenn:

1. Wiederholung ist sicher (idempotent),

2. die Abstände zwischen den Wiederholungen eingehalten werden,

3. Grenzen/Quoten und die „Gesundheit“ von Süchten werden respektiert.

Das Ziel ist effectively-once Verhalten auf der Ebene des Geschäftsbetriebs ohne falsche Takes und Rennen.

2) Taxonomie der Liefersemantik

At-most-once: keine Wiederholungen, Verlustrisiko (logging, fire-and-forget).
At-least-once: Duplikate sind möglich → die Idempotenz des Verbrauchers ist erforderlich (die meisten Warteschlangen, Webhooks).
Effectively-once: Duplikate sind möglich, werden aber korrekt dedupliziert (Schlüssel, Transaktionen, Outbox).

3) Wann retrazieren und wann nicht

Retracement macht Sinn: '408', '429' (unter Beachtung von 'Retry-After'), '425' (Too Early), '499' (Client geschlossen am Perimeter), '5xx', '504', Netzwerk-Timeouts/Pausen, '502' am Gateway, 'connection reset'.
Retraim nicht ohne Änderung der Anfrage: „400/ 401/403/404/422“.
Umstrittene Fälle: „409 Conflict“ (normalerweise nicht retraim; zuerst lesen wir den Status der Operation/bestätigen die Absicht).

4) Timeouts, Backoff und Jitter

4. 1 Regeln

Erst der Timeout, dann die Retrays: Jede Anfrage muss eine „Deadline“ haben.
Exponentieller Backoff: 'delay _ n = base 2 ^ n', limitieren 'max _ delay'.
Jitter ist ein Muss: Fügen Sie den Zufall hinzu, um „stumpfe Synchronwellen“ zu entkoppeln.

4. 2 Jitter-Vorlagen

Full jitter: 'sleep = rand (0, base2 ^ n)' ist die beste Gesamtauswahl.
Decorrelated jitter: 'sleep = min (max_delay, rand (base, sleep_prev3))' - für lange Dialoge.
Equal jitter: 'sleep = base2 ^ n/2 + rand (0, base2 ^ n/2)' ist eine weiche Variante.

4. 3 Retry-budget

Begrenzen Sie den Anteil der Retrays:
  • `retry_budget_per_min = max(α success_rps, floor β)`; Normalerweise' α = 0. 1–0. 2`.
  • Wenn das Budget erschöpft ist, wechseln wir zu fail-fast/circuit breaker „open“.

5) Interaktion mit Rate Limiting und Circuit Breaker

Respektiere' Retry-After', 'RateLimit-Reset' und zähle es im Back-Off.
Bei hohen '5xx '/Timeouts - Reduzieren Sie die Retrae-Frequenz und die allgemeine Parallelität.

Circuit breaker:
  • Half-open: erlaubt eine begrenzte Probe.
  • Offen: lehnt sofort ab (spart Ressourcen).
  • Geschlossen: normale Arbeit.
  • Bei Write-Operationen ist es vorzuziehen, den 409/503 mit einem klaren Hinweis zurückzugeben, als aggressive Retrays zu drehen.

6) Idempotenz der Schreiboperationen

6. 1 Allgemeine Idee

Gleiche Absichten → ein Ergebnis. Grundlage ist der Idempotenzschlüssel und die Speicherung der Ausführungsaufzeichnungen.

6. 2 HTTP-Vertrag

Der Kunde sendet den Titel:

Idempotency-Key: 7a6b7f9e-2a46-4d0b-9c3a-2b30e1c3c9e3
Idempotency-Key-Expiry: 24h # optional
Server:
  • Bei der ersten erfolgreichen Ausführung speichert (der Schlüssel → das Ergebnis, den Status, den Hash des Körpers);
  • gibt bei Wiederholung die vorherige Antwort und den Titel 'Idempotency-Replay: true' zurück;
  • bei einem Körperkonflikt (gleicher Schlüssel, aber anderer Payload) ist „409 Conflict“.

6. 3 Lagerung und TTL

Tabelle/Schlüsselwert: 'idempotency _ key', 'request _ hash', 'result',' status', 'expiry _ at'.
TTL = Fenster für mögliche Wiederholungen und verspätete Lieferungen (in der Regel 24-72 Stunden für Zahlungen).
Indizes nach 'idempotency _ key'; für hohe Belastung - Hash-Sharding.

6. 4 Beispielschema (SQL)

sql
CREATE TABLE idempo_store (
key UUID PRIMARY KEY,
req_hash BYTEA NOT NULL,
status INT NOT NULL,
response JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expiry_at TIMESTAMPTZ NOT NULL
);

6. 5 Pseudocode des Handlers

pseudo handle_write(req):
k = req. headers["Idempotency-Key"]
h = hash(req. body)
rec = idempo_store. get(k)

if rec and rec. req_hash == h:
return rec. status, rec. response, {"Idempotency-Replay": "true"}

if rec and rec. req_hash!= h:
return 409, problem("IDEMPOTENT_CONFLICT")

begin tx result = apply_business_mutation (req) # change status upsert once (idempo_store, key = k, req_hash=h, status = 201, response = result, expiry = now () + 2d)
commit

return 201, result

7) „effectively-once“ Muster

Transactional Outbox: Aufzeichnen eines Geschäftsereignisses und Senden einer Nachricht aus derselben DB-Transaktion über einen Hintergrund-Relayer; Der Verbraucher ist idempotent.
Inbox/Processed-table beim Verbraucher: Wir speichern 'event _ id', um die Takes zu ignorieren.
Exactly-once bei Kafka ≠ exactly-once im Business: Auch bei der EOS des Produzenten/Konsumenten muss die angewandte Logik noch idempotent sein.
Kompensationstransaktionen (Saga): Wenn sich die Schritte zurückziehen und Nebenwirkungen verursachen, kehren wir das System zur Invariante zurück.

8) Sonderfälle: Zahlungen und Finanztransaktionen

Starke Identität: Der Schlüssel ist an die Logik der Operation gebunden (z.B. 'external _ payment _ id').
Deduplizierung auf der PSP: Speichern Sie' merchant _ reference' → wenn die PSP wiederholt wird, wird das vorherige Ergebnis zurückgegeben.
Retrays „vom Kunden“: nur bei 'Idempotency-Key' erlauben, sonst Risiko einer doppelten Abbuchung.
Wettbewerb: Sperren „pro Konto/Tool/Vertrag“ für die Dauer der Ausführung; bei Wiederholung 409/423 zurückgeben.
Beobachtbarkeit: Metriken 'idempo _ replay _ total', 'idempo _ conflict _ total'.

9) Webhooks und externe Herausforderungen

HMAC-Signaturen und Zeitfenster; Erst die Prüfung, dann die Bearbeitung.
Absender-Retrays: exponentieller Backoff + Jitter, 'max _ attempts' und DLQ.
Benutzer - idempotent: 'event _ id' → Tabelle/in-memory cache; Eine „saubere“ Ordnung ist nicht garantiert.
Codes: 2xx = erfolgreich, 4xx = nicht wiederholen, 5xx/timeout = wiederholen.

10) Warteschlangen und Hintergrundaufgaben

At-least-once standardmäßig → Duplikate sind unvermeidlich.
Speichern Sie' task _ id '/' event _ id 'und den Ausführungsstatus; wenn doppelt - kurzer Weg „replay“.
DLQ und poison-messages: Versuch-Zähler, Quarantäne, manuelle Analyse.
Wettbewerbslimits (Semaphoren) und idempotente Worker.

11) Versionierung und „natürliche“ Schlüssel

Natürliche Schlüssel (Kontonummer + Datum + Dokumentennummer) erhöhen die Wiederholungsresistenz.
Wenn Sie das Schema/die Version ändern, fügen Sie den Versionsschlüssel in den 'Idempotency-Key' oder in den Abfrage-Hash ein.

12) HTTP-Header und Client-Hinweise

„Idempotency-Key“, „Idempotency-Replay“, „Retry-After“, „Prefer: wait = <sec>“ (bei langen Operationen), „If-Match “/„ ETag“ (optimistische Blockaden).
409 bei einem Schlüsselkonflikt, 425/429/503 mit dem gültigen 'Retry-After'.
Bei „langen“ Vorgängen den asynchronen Status akzeptieren ('202 Accepted' + 'Location' auf die Statusressource).

13) Test- und Chaos-Szenarien

Negative Tests: Doppelsendung, Wiederholung mit einem anderen Körper, ein Rassynhron der Uhr.
Ordnungswidrigkeit: 't2' kommt vor 't1'.
Timeout-Injektion/„ RST “/„ EOF “, halbherzige Abfragen (slow-POST).
Gefallener idempotency Speicher → fail-closed Verhalten (bessere Ablehnung als doppeltes Abschreiben).

14) Metriken und Alerts

`retries_total{reason}`, `retry_budget_used{route}`, `backoff_seconds_bucket`.
`idempo_replay_total`, `idempo_conflict_total`, `duplicate_detected_total`.
Anteil 409/425/429/5xx nach Strecken; p95/p99 „Zeit bis zum Erfolg“ mit Retrays.
Alertas: Burn-Rate-Budget für Retrays, Anstieg der Idempotenzkonflikte, DLQ-Wachstum.

15) Antipatterns

Retrace alle Fehler in einer Reihe.
Das Fehlen von Jitter → synchrone Wellen von Retrays.
Langlebige Schlüssel ohne TTL und Reinigung.
Speichern des Ergebnisses nach einem Nebeneffekt-Commit (Outbox-Verletzung).
Logs ohne' trace _ id '/' idempotency _ key '→ keine Forensik möglich.
Aggressive parallele Retrays auf Write-Operationen.

16) Checkliste Prod-Ready

  • Einheitliche Politik: Was retraim, was nicht; Codes und Hinweise an den Kunden.
  • Exponentieller Backoff + Volljitter; wird 'retry _ budget' gesetzt.
  • Vertrag 'Idempotency-Key' + Speicherung der Ergebnisse mit TTL.
  • Outbox/Inbox für Ereignisse; DLQ; Grenzen der Wettbewerbsfähigkeit.
  • Integration mit Circuit Breaker, respect 'Retry-After'.
  • Metriken/Warnungen nach Retrays/Duplikaten/Konflikten.
  • Eine Reihe von Chaos-Tests und Emulation von Netzwerkfehlern.
  • Kundendokumentation: Beispiele für Backoffs und Status.

17) TL; DR

Retrays sind nur zusammen mit Idempotenz nützlich. Geben Sie' Idempotency-Key 'und Ergebnisspeicher ein, wenden Sie exponentiellen Backoff mit Jitter und Retry-Budget an, respektieren Sie' Retry-After', integrieren Sie sich in den Circuit Breaker. Für Ereignisse - outbox/inbox; für Zahlungen - strenge Deduplizierung und Blockierung. Messen Sie Retrays und Konflikte, testen Sie Duplikate und Timeouts.

Contact

Kontakt aufnehmen

Kontaktieren Sie uns bei Fragen oder Support.Wir helfen Ihnen jederzeit gerne!

Integration starten

Email ist erforderlich. Telegram oder WhatsApp – optional.

Ihr Name optional
Email optional
Betreff optional
Nachricht optional
Telegram optional
@
Wenn Sie Telegram angeben – antworten wir zusätzlich dort.
WhatsApp optional
Format: +Ländercode und Nummer (z. B. +49XXXXXXXXX).

Mit dem Klicken des Buttons stimmen Sie der Datenverarbeitung zu.