GH GambleHub

Idempotencja i klucze

Czym jest idempotencja

Idempotencja jest właściwością operacji, w której powtarzanie z tym samym identyfikatorem nie zmienia ostatecznego efektu. W systemach rozproszonych jest to główny sposób, aby wynik był równoważny „dokładnie jednej obróbce”, pomimo przekaźników, duplikatów wiadomości i terminów.

Kluczowy pomysł: każda potencjalnie powtarzalna operacja powinna być oznaczona kluczem, za pomocą którego system uznaje „to już zostało wykonane” i stosuje wynik nie więcej niż raz.

Gdzie to ma znaczenie

Płatności i salda: odpisy/kredyty według 'operation _ id'.
Rezerwacje/kwoty/limity: ten sam czas na start lub lądowanie/zasób.
Haki/powiadomienia: wielokrotna dostawa nie powinna powielać efektu.
Import/migracja - ponowne uruchamianie plików/pakietów.
Przetwarzanie strumieniowe: duplikaty z brokera/CDC.

Rodzaje kluczy i ich zakres

1. Klucz operacyjny - identyfikator konkretnej próby transakcji gospodarczej

Przykłady: 'idempotence _ key' (HTTP), 'operation _ id' (RPC).
Zakres: usługa/kruszywo; jest przechowywany w tabeli deduplikacji.

2. Klucz zdarzenia - niepowtarzalny identyfikator zdarzenia/komunikatu

Przykłady: 'event _ id' (UUID),' (producer_id, sekwencja) '.
Obszar: grupa konsumentów/konsumentów; chroni projekcje.

3. Klucz biznesowy - klucz domeny naturalnej

Przykłady: 'payment _ id',' faktura _ number ',' (user_id, day) '.
Obszar: kruszywo; używane w kontrolach unikalności/wersji.

💡 Często używane razem: 'operation _ id' chroni polecenie,' event _ id' - dostawa, 'klucz biznesowy' - niezmienniki agregatu.

Polityka TTL i retencji

Klucze TTL ≥ możliwe okno redo: zatrzymanie dziennika + opóźnienia sieci/procesu.
Dla domen krytycznych (płatności) TTL - dni/tygodnie; dla telemetrii - godziny.
Czyste stoły dedup z tłem pracy; dla audytu - archiwum.

Sklepy kluczy (deduplikacja)

Baza danych transakcji (zalecana): niezawodne indeksy upsert/unique, wspólna transakcja z efektem.
KV/Redis: szybki, wygodny dla krótkiego TTL, ale bez wspólnej transakcji z OLTP - ostrożny.
State store stream processor: locally + changelog in broker; dobry w Flink/KStreams.

Schemat (opcja w DB):
  • idempotency_keys

'consumer _ id' (ила' service '),' op _ id' (PK на сара), 'applied _ at', 'ttl _ expires _ at', 'result _ hash '/' response _ status' (ова.) .

Indeksy: '(consumer_id, op_id)' - niepowtarzalne.

Podstawowe techniki wdrażania

1) Efekt + Transakcja Progress

Zapisz wynik i przechwytuj postęp odczytu/pozycji w jednej transakcji.

pseudo begin tx if not exists(select 1 from idempotency_keys where consumer=:c and op_id=:id) then
-- apply effect atomically (upsert/merge/increment)
apply_effect(...)
insert into idempotency_keys(consumer, op_id, applied_at)
values(:c,:id, now)
end if
-- record reading progress (offset/position)
upsert offsets set pos=:pos where consumer=:c commit

2) Optymistyczne współistnienie (wersja jednostkowa)

Chroni przed podwójnym efektem podczas wyścigów:
sql update account set balance = balance +:delta,
version = version + 1 where id=:account_id and version=:expected_version;
-- if 0 rows are updated → retry/conflict

3) Idempotentne zlewy (upsert/fuzja)

Accrue raz:
sql insert into bonuses(user_id, op_id, amount)
values(:u,:op,:amt)
on conflict (user_id, op_id) do nothing;

Idempotencja w protokołach

HTTP/REST

'Idempotency-Key: <uuid' hash> 'nagłówek.
Serwer przechowuje rekord klucza i ponownie zwraca tę samą odpowiedź (lub kod '409 '/' 422' w przypadku niezmiennego konfliktu).
W przypadku „niepewnego” programu POST wymagana jest stabilna polityka „Idempotence-Key” + harmonogram/przekaźnik.

gRPC/RPC

Metadane 'idempotence _ key', 'request _ id' + deadline.
Implementacja serwera - tak jak w REST: tabela deduplikacji w transakcji.

Brokerzy/Streaming (Kafka/NATS/Pulsar)

Producent: stabilny "event _ id'/producent idempotent (tam gdzie jest obsługiwany).
Konsument: potrącenie przez „(consumer_id, event_id)” lub przez wersję biznesową agregatu.
Oddzielny DLQ dla wiadomości nieidempotentnych/uszkodzonych.

Haki internetowe i partnerzy zewnętrzni

Żądanie "Idempotency-Key "/" event _ id' w umowie; ponowna dostawa musi być bezpieczna.
Przechowywanie 'notification _ id' i wysyłanie statusów; na retray - nie duplikuj.

Projekt klucza

Determinizm: Przekaźniki muszą wysyłać ten sam klucz (generować z wyprzedzeniem na klienta/orkiestratora).
Zakres: Formularz 'op _ id' jako' service: aggregate: id: purpose '.
Kolizje: użyj UUIDv7/ULID lub hash z parametrów biznesowych (z solą, jeśli to konieczne).
Hierarchia: ogólne 'operation _ id' na → front jest tłumaczone na wszystkie podoperacje (łańcuch idempotentny).

Aspekty UX i produktu

Powtarzające się żądanie klucza musi zwrócić ten sam wynik (w tym ciało/status) lub wyraźny „już wykonany”.
Pokaż użytkownikowi statusy „operacja jest przetwarzana/zakończona” zamiast próbować ponownie „na szczęście”.
Dla długich operacji - sondaż według klucza ('GET/operations/{ op _ id}').

Obserwowalność

Log 'op _ id',' event _ id', 'trace _ id', wynik:' APPLIED '/' ALREADY _ APPLIED '.
Wskaźniki: szybkość powtarzania, rozmiar stołu dedup, czas transakcji, konflikty wersji, szybkość DLQ.
Ślad: klucz musi przejść przez polecenie → zdarzenie → projekcja → wywołanie zewnętrzne.

Bezpieczeństwo i zgodność

Nie przechowywać PII w klawiszach; klucz - identyfikator, nie ładunek.
Szyfruj pola wrażliwe w rekordach deduplikacji z długim TTL.
Polityka zatrzymywania: TTL i archiwum; prawo do bycia zapomnianym - poprzez krypto-usunięcie odpowiedzi/metadanych (jeśli zawierają PII).

Testowanie

1. Duplikaty: uruchom jeden komunikat/żądanie 2-5 razy - efekt dokładnie jeden.
2. Spadek między krokami: przed/po zapisaniu efektu, przed/po ustawianiu przesunięcia.
3. Ponowne uruchomienie/przywrócenie równowagi konsumenckiej: brak podwójnego zastosowania.
4. Konkurencja: równoległe zapytania z jednym 'op _ id' → jeden efekt, drugi -' JUŻ _ APPLIED/409 '.
5. Długotrwałe klucze: Sprawdzenie wygaśnięcia TTL i ponowne próby po odzyskaniu.

Anty-wzory

Losowy nowy klucz dla każdego przekaźnika: system nie rozpoznaje powtórzeń.
Dwa osobne zobowiązania: najpierw efekt, potem offset - upadek między nimi duplikuje efekt.
Zaufanie tylko maklerowi: brak deduplikacji w siniaku/agregacie.
Brakująca wersja zbiorcza: powtarzające się zdarzenie zmienia się po raz drugi.
Klucze tłuszczowe: klucz obejmuje pola biznesowe/PII → wycieki i skomplikowane indeksy.
Brak powtarzalnych odpowiedzi: Klient nie może bezpiecznie wycofać się.

Przykłady

Płatność POST

Klient: 'POST/płatności' + 'Idempotency-Key: k-789'.
Serwer: transakcja - tworzy 'płatność' i wpis w 'idempotence _ keys'.
Redo: zwraca to samo '201 '/ciało; w przypadku niezmiennego konfliktu - „409”.

Bonus memoriałowy (sink)

sql insert into credits(user_id, op_id, amount, created_at)
values(:u,:op,:amt, now)
on conflict (user_id, op_id) do nothing;

Projekcja z wydarzeń

konsument przechowuje „widziane (event_id)” i „wersję” jednostki; powtarzać - ignorować/idempotent upsert.
Postęp odczytu jest przechwytywany w tej samej transakcji co aktualizacja projekcji.

Lista kontrolna produkcji

  • Wszystkie niebezpieczne operacje mają klucz idempotentny i ich zakres określony.
  • Istnieją tabele deduplikacji z TTL i unikalne indeksy.
  • Efekt i postęp czytania są popełniane atomowo.
  • Optymistyczna konkurencja (wersja/sekwencja) jest zawarta w modelu pisma.
  • Umowy API przechwytują "Idempotency-Key "/" operation _ id' oraz zachowanie powtórzeń.
  • Mierniki i dzienniki zawierają 'op _ id'/' event _ id'/' trace _ id'.
  • Testy na duplikaty, upadki i wyścigi - w CI.
  • Przestrzegane są zasady TTL/Archiwum oraz bezpieczeństwo PII.

NAJCZĘŚCIEJ ZADAWANE PYTANIA

W jaki sposób 'Idempotence-Key' pochodzi z 'Request-Id'?
„Id żądania” - ślad; można to zmienić na przekładkach. „Idempotency-Key” jest semantycznym identyfikatorem operacji, który musi być taki sam podczas powtórzeń.

Czy można zrobić idempotencję bez bazy danych?
W przypadku krótkiego okna - tak (Redis/in-process cache), ale bez wspólnej transakcji, ryzyko powielania wzrasta. W domenach krytycznych jest lepiej w jednej transakcji bazodanowej.

Co zrobić z partnerami zewnętrznymi?
Negocjuj klucze i powtarzalne odpowiedzi. Jeśli partner nie obsługuje - zawinąć połączenie do warstwy idempotent i przechowywać „już zastosowane”.

Jak wybrać TTL?
Suma maksymalnych opóźnień: zatrzymanie dziennika + najgorszy przypadek netto/rebalance + bufor. Dodać zapasy (× 2).

Razem

Idempotencja jest dyscypliną kluczy, transakcji i wersji. Stabilne identyfikatory pracy + atomowe utrwalenie efektu i postęp odczytu + idempotentne zlewy/projekcje dają „dokładnie jeden efekt” bez magii na poziomie transportu. Sprawiają, że klawisze deterministyczne, TTL realistyczne i testy złośliwe. Wtedy przekłady i duplikaty staną się rutynowe, a nie incydenty.

Contact

Skontaktuj się z nami

Napisz do nas w każdej sprawie — pytania, wsparcie, konsultacje.Zawsze jesteśmy gotowi pomóc!

Rozpocznij integrację

Email jest wymagany. Telegram lub WhatsApp są opcjonalne.

Twoje imię opcjonalne
Email opcjonalne
Temat opcjonalne
Wiadomość opcjonalne
Telegram opcjonalne
@
Jeśli podasz Telegram — odpowiemy także tam, oprócz emaila.
WhatsApp opcjonalne
Format: kod kraju i numer (np. +48XXXXXXXXX).

Klikając przycisk, wyrażasz zgodę na przetwarzanie swoich danych.