الفراغ والمفاتيح
ما هو الفراغ
الخصوصية هي خاصية لعملية لا يغير فيها التكرار بنفس المعرف الأثر النهائي. في الأنظمة الموزعة، هذه هي الطريقة الرئيسية لجعل النتيجة مكافئة لـ «معالجة واحدة بالضبط»، على الرغم من إعادة التصوير والرسائل المكررة والمهل الزمنية.
الفكرة الرئيسية: يجب تمييز كل عملية قابلة للتكرار بمفتاح يعترف به النظام «لقد تم ذلك بالفعل» ولا يطبق النتيجة أكثر من مرة.
حيث يهم
المدفوعات والأرصدة: المبالغ المشطوبة/الأرصدة الدائنة حسب 'التشغيل _ id'.
الحجوزات/الحصص/الحدود: نفس الفترة/الموارد.
الخطابات الشبكية/الإخطارات: ينبغي ألا يؤدي التسليم المتكرر إلى تكرار التأثير.
الاستيراد/الهجرة - إعادة تشغيل الملفات/الطرود.
معالجة التيار: نسخ مكررة من الوسيط/مركز السيطرة على الأمراض.
أنواع المفاتيح ونطاقها
1. مفتاح التشغيل - هوية المحاولة المحددة للمعاملة التجارية
أمثلة: 'idempotency _ key' (HTTP), 'operation _ id' (RPC).
النطاق: الخدمة/المجموع ؛ مخزنة في جدول تفريغ.
2. مفتاح الحدث - معرف فريد للحدث/الرسالة
أمثلة: 'event _ id' (UUID), '(producer_id, sequence)'.
المجال: مجموعة المستهلكين/المستهلكين ؛ يحمي الإسقاطات.
3. مفتاح العمل - مفتاح المجال الطبيعي
أمثلة: 'payment _ id', 'valoice _ number', '(user_id, day)'.
المنطقة: المجموع ؛ المستخدمة في عمليات التحقق من التفرد/النسخ.
TTL وسياسة الاحتفاظ
مفاتيح TTL ≥ نافذة إعادة محتملة: الاحتفاظ بالسجل + تأخير الشبكة/العملية.
بالنسبة للمجالات الحرجة (المدفوعات) TTL - أيام/أسابيع ؛ للقياس عن بعد - ساعات.
تنظيف طاولات التخلص مع وظائف خلفية ؛ لمراجعة الحسابات - الأرشيف.
المتاجر الرئيسية (تفريغ)
قاعدة بيانات المعاملات (موصى بها): فهارس متقلبة/فريدة موثوقة، معاملات مشتركة ذات أثر.
KV/Redis: سريع ومناسب لـ TTL قصير، ولكن بدون صفقة مشتركة مع OLTP - حذر.
معالج دفق متجر الدولة: محليا + changelog في الوسيط ؛ جيد في Flink/KStreams.
- idempotency_keys
'consumer _ id' (или 'service'), 'op _ id' (PK на пару), 'applied _ at',' tl _ expires _ at', 'enture _ 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) الأحواض العاطفية (مضطربة/مدمجة)
الاستحقاق مرة واحدة:sql insert into bonuses(user_id, op_id, amount)
values(:u,:op,:amt)
on conflict (user_id, op_id) do nothing;
الخصوصية في البروتوكولات
HTTP/REST
«Idempotency-Key: <uid' hash>» header.
يقوم الخادم بتخزين سجل المفتاح ويعيد نفس الرد مرة أخرى (أو الرمز «409 »/« 422» في حالة التضارب الثابت).
بالنسبة لـ POST «غير الآمن»، مطلوب سياسة «Idempotency-Key» + المهلة المستقرة/إعادة الدفع.
gRPC/RPC
البيانات الوصفية 'idempotency _ key'، 'request _ id' + الموعد النهائي.
تنفيذ الخادم - كما في REST: جدول تفريغ في المعاملة.
الوسطاء/البث (كافكا/ناتس/بولسار)
المنتج: 'event _ id '/idempotent producer (حيثما تم دعمه).
المستهلك: التخلص من '(consumer_id، event_id)' و/أو نسخة تجارية من المجموع.
فصل DLQ للرسائل غير الخاطئة/الفاسدة.
شبكات الويب والشركاء الخارجيين
طلب 'مفتاح الخصوصية '/' حدث _ هوية' في العقد ؛ يجب أن تكون إعادة التسليم آمنة.
تخزين 'إخطار - معرف' وإرسال أوضاع ؛ عند العودة - لا تكرر.
تصميم المفتاح
الحتمية: يجب أن ترسل عمليات إعادة التدوير نفس المفتاح (تولد مسبقًا على العميل/المنسق).
النطاق: الاستمارة 'op _ id' بوصفها 'خدمة: المجموع: معرف: الغرض'.
الاصطدامات: استخدام UUIDv7/ULID أو التجزئة من بارامترات العمل (مع الملح إذا لزم الأمر).
التسلسل الهرمي: تُترجم 'العملية _ id' العامة في الجبهة → إلى جميع العمليات الفرعية (سلسلة الخصوصية).
UX وجوانب المنتج
يجب أن يعيد الطلب الرئيسي المتكرر نفس النتيجة (بما في ذلك الجسم/الحالة) أو «تم تنفيذه بالفعل».
أظهر للمستخدم أن الحالات «تتم معالجة/إكمال العملية» بدلاً من المحاولة مرة أخرى «لحسن الحظ.»
للعمليات الطويلة - الاقتراع حسب المفتاح ('GET/operations/{ op _ id}').
قابلية الملاحظة
Log 'op _ id', 'event _ id', 'trace _ id', contribution: 'APPLED '/' FACE _ APPLED'.
المقاييس: معدل التكرار، حجم جدول التخلص، وقت المعاملة، تضارب النسخ، معدل DLQ.
التتبع: يجب أن يمر المفتاح عبر الأمر → الحدث → الإسقاط → المكالمة الخارجية.
السلامة والامتثال
لا تخزن PII في المفاتيح ؛ مفتاح - معرف وليس حمولة.
قم بتشفير الحقول الحساسة في سجلات التفريغ باستخدام TTL الطويل.
سياسة الاحتفاظ: TTL والمحفوظات ؛ الحق في النسيان - من خلال محو الاستجابات/البيانات الوصفية (إذا كانت تحتوي على PII).
اختبار
1. نسخ مكررة: قم بتشغيل رسالة/طلب واحد 2-5 مرات - تأثير واحد بالضبط.
2. اسقط بين الخطوات: قبل/بعد تسجيل التأثير، قبل/بعد إصلاح الإزاحة.
3. إعادة تشغيل المستهلك/إعادة التوازن: لا يوجد استخدام مزدوج.
4. المنافسة: استفسارات موازية مع «معرف» واحد → تأثير واحد، والثاني - «بالفعل _ APPLIED/409».
5. المفاتيح طويلة العمر: فحوصات لانتهاء صلاحية TTL وإعادة صلاحيتها بعد الاسترداد.
الأنماط المضادة
مفتاح جديد عشوائي لكل إعادة: لا يتعرف النظام على الإعادة.
التزامان منفصلان: أولاً التأثير، ثم التعويض - السقوط بينهما يكرر التأثير.
الثقة فقط في الوسيط: لا تفريغ في الكدمة/المجموع.
النسخة المجمعة المفقودة: تشير التغييرات المتكررة للحدث إلى مرة ثانية.
مفاتيح الدهون: يشمل المفتاح مجالات الأعمال/تسريبات → PII والفهارس المعقدة.
لا توجد ردود قابلة للتكرار: لا يمكن للعميل التراجع بأمان.
أمثلة
بريد الدفع
العميل: "POST/payments' +" Idempotency-Key: k-789 ".
الخادم: المعاملة - تنشئ «الدفع» وإدخال في «الخصوصية _ المفاتيح».
إعادة: يرجع نفس «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)» و «نسخة» من الوحدة ؛ كرر - تجاهل/انزعاج خاطئ.
يتم تسجيل التقدم في القراءة في نفس الصفقة مثل تحديث التوقعات.
قائمة الإنتاج المرجعية
- جميع العمليات غير الآمنة لها مفتاح خفي ونطاقها محدد.
- هناك جداول تفريغ مع TTLs وفهارس فريدة.
- يتم الالتزام ذريًا بتأثير القراءة وتقدمها.
- يتم تضمين المنافسة المتفائلة (النسخة/التسلسل) في نموذج الكتابة.
- تستحوذ عقود API على «Idempotency-Key »/« operation _ id» وسلوك التكرار.
- تحتوي المقاييس والسجلات على 'op _ id '/' event _ id '/' trace _ id'.
- اختبارات التكرارات والسقوط والسباقات - في CI.
- يتم اتباع سياسة TTL/Archive وأمن PII.
الأسئلة الشائعة
كيف يكون «Idempotency-Key» مختلفًا عن «Request-Id» ؟
'معرف الطلب' - أثر ؛ يمكن تغييره في إعادة التصوير. «Idempotency-Key» هو المعرف الدلالي للعملية، والذي يجب أن يكون هو نفسه أثناء التكرار.
هل من الممكن القيام بالحماقة بدون قاعدة بيانات ؟
بالنسبة لنافذة قصيرة - نعم (Redis/cache قيد العملية)، ولكن بدون معاملة مشتركة، يزداد خطر التكرار. في المجالات الحرجة، يكون أفضل في صفقة قاعدة بيانات واحدة.
ماذا تفعل مع الشركاء الخارجيين ؟
التفاوض على المفاتيح والردود القابلة للتكرار. إذا لم يدعم الشريك - قم بلف المكالمة في طبقتك الخفية وتخزينها «المطبق بالفعل».
كيف تختار TTL ؟
مجموع الحد الأقصى للتأخير: الاحتفاظ بالسجل + صافي/إعادة التوازن أسوأ حالة + مخزن مؤقت. أضف المخزون (× 2).
المجموع
الخصوصية هي نظام المفاتيح والمعاملات والإصدارات. تعطي معرفات التشغيل المستقرة + التثبيت الذري للتأثير وتقرير التقدم + الأحواض/الإسقاطات الخفية «تأثيرًا واحدًا بالضبط» بدون سحر على مستوى النقل. اجعل المفاتيح حتمية وواقعية TTL واختبارات ضارة. ثم ستصبح عمليات إعادة التصوير والتكرار روتينية وليست حوادث.