Idempotence و کلید
ایده آل بودن چیست
Idempotency یک ویژگی از یک عملیات است که در آن تکرار با همان شناسه اثر نهایی را تغییر نمی دهد. در سیستم های توزیع شده، این راه اصلی برای ایجاد نتیجه معادل «دقیقا یک پردازش» است، با وجود بازپرداخت، پیام های تکراری و وقفه.
ایده کلیدی: هر عملیات بالقوه قابل تکرار باید با یک کلید مشخص شود که توسط آن سیستم تشخیص می دهد «این قبلا انجام شده است» و نتیجه بیش از یک بار اعمال نمی شود.
جایی که اهمیت دارد
پرداخت و تعادل: نوشتن آف/اعتبار توسط 'operation _ id'.
رزرو/سهمیه/محدودیت: همان اسلات/منابع.
Webhooks/notifications: تحویل مکرر نباید اثر را تکرار کند.
Import/Migration - فایل ها/بسته ها را دوباره اجرا کنید.
پردازش جریان: تکراری از کارگزار/CDC.
انواع کلیدها و دامنه آنها
1. کلید عملیاتی - شناسه تلاش خاص معامله تجاری
مثال: 'idempotency _ key' (HTTP)، 'operation _ id' (RPC).
محدوده: خدمات/جمع آوری ؛ در یک جدول deduplication ذخیره می شود.
2. کلید رویداد - شناسه منحصر به فرد رویداد/پیام
مثال: 'event _ id' (UUID), '(producer_id, sequence)'.
منطقه: گروه مصرف کننده/مصرف کننده ؛ محافظت از پیش بینی ها
3. کلید کسب و کار - کلید دامنه طبیعی
به عنوان مثال: 'payment _ id', 'invoice _ number', '(user_id, day)'.
منطقه: مجموع ؛ در چک های منحصر به فرد/نسخه استفاده می شود.
TTL و سیاست نگهداری
کلید TTL ≥ یک پنجره مجدد ممکن است: حفظ ورود به سیستم + تاخیر شبکه/فرآیند.
برای دامنه های بحرانی (پرداخت) TTL - روزها/هفته ها ؛ برای تله متری - ساعت.
پاک کردن جداول dedup با مشاغل پس زمینه ؛ برای حسابرسی - آرشیو.
فروشگاه های کلیدی (deduplication)
پایگاه داده معاملات (توصیه می شود): شاخص های قابل اعتماد upsert/منحصر به فرد، معامله مشترک با اثر.
KV/Redis: سریع، مناسب برای TTL کوتاه، اما بدون معامله مشترک با OLTP - مراقب باشید.
پردازنده جریان فروشگاه دولتی: محلی + changelog در کارگزار ؛ خوب در Flink/KStreams.
- idempotency_keys
'consumer _ id' (или 'service'), 'op _ id' (PK на пару), 'applied _ at', 'ttl _ expires _ at', 'result _ hash '/' response _ status' (опц.) .
شاخص ها: '(consumer_id، op_id)' - منحصر به فرد.
تکنیک های پیاده سازی پایه
1) اثر + معامله پیشرفت
ضبط نتیجه و ضبط پیشرفت خواندن/موقعیت در یک معامله.
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) همزمانی خوش بینانه (نسخه واحد)
محافظت در برابر اثر دوگانه در هنگام مسابقه: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) غرق idempotent (upsert/ادغام)
یک بار افزایش یابد:sql insert into bonuses(user_id, op_id, amount)
values(:u,:op,:amt)
on conflict (user_id, op_id) do nothing;
عدم توانایی در پروتکل ها
HTTP/استراحت
'Idempotency-Key: <uid' hash> 'هدر.
سرور رکورد کلید را ذخیره می کند و دوباره همان پاسخ را باز می گرداند (یا کد «409 »/« 422» در صورت درگیری ثابت).
برای POST «ناامن»، سیاست «Idempotency-Key» + timeout/retray پایدار مورد نیاز است.
gRPC/RPC
فراداده «idemotency _ key»، «request _ id» + مهلت.
پیاده سازی سرور - مانند REST: یک جدول deduplication در یک معامله.
کارگزاران/جریان (کافکا/NATS/پولسار)
تولیدکننده: تولیدکننده پایدار 'event _ id '/idempotent (در صورت پشتیبانی).
مصرف کننده: توسط «(consumer_id، event_id)» و/یا نسخه تجاری جمع آوری شده است.
DLQ جداگانه برای پیام های غیر idempotent/فاسد.
وبوکها و شرکای خارجی
تقاضا «Idempotency-Key »/« event _ id» در قرارداد ؛ تحویل مجدد باید امن باشد.
ذخیره «notification _ id» و ارسال وضعیت ؛ در retray - تکرار نکنید.
طراحی کلیدی
جبرگرایی: Retrays باید همان کلید را ارسال کند (تولید در پیشبرد مشتری/ارکستر).
محدوده: فرم «op _ id» را به عنوان «سرویس: aggregate: id: هدف».
برخورد: استفاده از UUIDv7/ULID یا هش از پارامترهای کسب و کار (با نمک در صورت لزوم).
سلسله مراتب: عمومی 'operation _ id' در → front به تمام عملیات های فرعی (زنجیره idempotent) ترجمه می شود.
جنبه های UX و محصول
یک درخواست کلید تکراری باید همان نتیجه (از جمله بدن/وضعیت) یا صریح «قبلا اجرا شده» را بازگرداند.
نمایش کاربر وضعیت «عملیات در حال پردازش/تکمیل» به جای تلاش دوباره «برای موفقیت».
برای عملیات طولانی - نظرسنجی با کلید ('GET/operations/{ op _ id}').
قابلیت مشاهده
Log 'op _ id', 'event _ id', 'trace _ id', نتیجه: 'APPLIED '/' ALREADY _ APPLIED'.
معیارها: میزان تکرار، اندازه جدول dedup، زمان معامله، درگیری های نسخه، نرخ DLQ.
Trace: کلید باید از مسیر command → event → projection → external call عبور کند.
ایمنی و انطباق
PII را در کلید ذخیره نکنید کلید - شناسه، نه بارگیری.
زمینه های حساس را در سوابق deduplication با TTL طولانی رمزگذاری کنید.
سیاست نگهداری: TTL و آرشیو ؛ حق فراموش شدن - از طریق رمزنگاری پاک کردن پاسخ ها/ابرداده (اگر آنها حاوی PII).
تست کردن
1. تکراری: اجرای یک پیام/درخواست 2-5 بار - اثر دقیقا یک.
2. قطره بین مراحل: قبل/بعد از ضبط اثر، قبل/بعد از رفع افست.
3. راه اندازی مجدد/تعادل مصرف کننده: بدون استفاده دوگانه.
4. رقابت: پرس و جوهای موازی با یک «op _ id» → یک اثر، دوم - «ALREADY _ APPLIED/409».
5. کلیدهای با عمر طولانی: چک کردن انقضای TTL و تلاش مجدد پس از بازیابی.
ضد الگوهای
کلید جدید تصادفی برای هر تکرار: سیستم تکرار را تشخیص نمی دهد.
دو تعهد جداگانه: اول اثر، سپس افست - سقوط بین آنها اثر را تکرار می کند.
اعتماد تنها کارگزار: بدون deduplication در کبودی/دانه.
نسخهی مجموع گمشده: رویداد تکراری برای بار دوم وضعیت را تغییر میدهد.
کلید های چربی: کلید شامل زمینه های کسب و کار/PII → نشت و شاخص های پیچیده است.
بدون پاسخ قابل تکرار: مشتری نمی تواند با خیال راحت پس بگیرد.
مثال ها
پست پرداخت
مشتری: 'POST/payments' + 'Idempotency-Key: k-789'.
Server: transaction - یک «پرداخت» و یک ورودی در «idempointency _ keys» ایجاد می کند.
Redo: همان «201 »/بدن را باز می گرداند ؛ در صورت تعارض ثابت - «409».
پاداش تعهدی (سینک)
sql insert into credits(user_id, op_id, amount, created_at)
values(:u,:op,:amt, now)
on conflict (user_id, op_id) do nothing;
طرح ریزی از حوادث
فروشگاه های مصرف کننده «دیده (event_id)» و «نسخه» واحد ؛ تکرار - نادیده گرفتن/idempotent upsert.
پیشرفت خواندن در همان معامله به عنوان به روز رسانی طرح ریزی دستگیر شده است.
چک لیست تولید
- تمام عملیات ناامن دارای یک کلید idempotent و دامنه آن تعریف شده است.
- جداول deduplication با TTL ها و شاخص های منحصر به فرد وجود دارد.
- اثر و پیشرفت خواندن متعهد به اتمی است.
- رقابت خوش بینانه (نسخه/دنباله) در مدل نوشتن گنجانده شده است.
- قراردادهای API ضبط «Idempotency-کلید »/« operation _ id» و رفتار تکرار.
- معیارها و سیاهههای مربوط حاوی 'op _ id '/' event _ id '/' trace _ id' است.
- تست برای تکراری، سقوط و نژادها - در CI.
- سیاست TTL/بایگانی و امنیت PII دنبال می شود.
سوالات متداول
تفاوت «Idempotency-Key» از «Request-Id» چیست ؟
'Request-Id' - ردیابی ؛ می توان آن را در retrays تغییر داد. «Idempotency-Key» شناسه معنایی عملیات است که لازم است در طول تکرارها یکسان باشد.
آیا می توان idempointence را بدون پایگاه داده انجام داد ؟
برای یک پنجره کوتاه - بله (Redis/in-process cache)، اما بدون یک معامله مشترک، خطر تکراری افزایش می یابد. در حوزه های بحرانی، در یک معامله پایگاه داده بهتر است.
با شرکای خارجی چه کنیم ؟
مذاکره کلید و پاسخ های تکراری. اگر شریک پشتیبانی نمی کند - تماس را در لایه idempoint خود قرار دهید و «قبلاً اعمال شده» را ذخیره کنید.
چگونه TTL را انتخاب کنیم ؟
حداکثر تاخیر را جمع کنید: نگهداری ورود به سیستم + خالص/تعادل مجدد بدترین حالت + بافر. اضافه کردن سهام (× 2).
مجموع
Idempotency یک رشته از کلید ها، معاملات و نسخه ها است. شناسه عملیات پایدار + تثبیت اتمی اثر و پیشرفت خواندن + غرق idempotent/پیش بینی را «دقیقا یک اثر» بدون سحر و جادو در سطح حمل و نقل. را کلید قطعی، TTL واقع بینانه و تست های مخرب. سپس تکرارها و تکرارها عادی می شوند، نه حوادث.