تحسين الاستجابة الخلفية: قوائم الانتظار، async، الضغط الخلفي
1) السبب: الأهداف و SLOs
الهدف هو استجابة سريعة مستقرة حتى تحت رشقات نارية. تعبر الأعمال عن هذا SLO:- API (CRUD/directories): p95 ≤ 250-400 ms، معدل الخطأ أقل من 1٪.
- الدفع/التسوية (غير متزامنة): اتفاق SLA الداخلي للتأكيد ≤ 2-5 دقائق، والعميل - استطلاع فوري 202/Accepted + حالة/خطاف ويب.
- WS/في الوقت الفعلي: RTT p95 ≤ 120 мс، قطع الاتصال ≤ 0. 5%.
المفتاح: لفك قيود الخطوات «البطيئة» (مقدمو الخدمات وقواعد البيانات وواجهات برمجة التطبيقات الخارجية) من استجابة المستخدم إلى قوائم الانتظار والحد من التحميل الكفء.
2) الصورة الأساسية: حيث يتم التقاط زمن الكمون
الاختناقات: قاعدة البيانات (المجمعات/الفهارس)، مقدمو الخدمات الخارجيون (PSP/game)، منع I/O، GC/stop world، تسلسل JSON، التجميعات «الثقيلة».
الأعراض: نمو p99، طابور اتصال DB، رشقات نارية، إعادة تجربة العاصفة.
الترياق: خطوط الأنابيب غير المتزامنة + الضغط الخلفي + المهلات/التراجعات + الخصوصية.
3) الأنماط غير المتزامنة: SEDA و CQRS
SEDA (بنية قائمة على الأحداث): تقسيم المعالجة إلى مراحل (الدخول → التحقق → الكتابة → التكامل → الإشعار). لكل منها دوره الخاص وحدود التزامن.
CQRS: يقرأ ويكتب منفصل. الكتابة - إلى السجل/قاعدة البيانات، القراءة - من الإسقاطات/المخابئ.
Outbox: يتم نشر الحدث ذريًا جنبًا إلى جنب مع السجل (تجنب الرسائل «المفقودة»).
ملحمة: عمليات تجارية طويلة مع معاملات تعويضية بدلاً من معاملات عالمية.
4) قوائم الانتظار والتدفقات: الاختيار والضبط
RabbitMQ/NATS JetStream - أوامر المهام (قوائم انتظار العمل)، كافكا - الأحداث/التدفقات مع إعادة التشغيل.
الإعدادات التي تؤثر على الاستجابة:- Prepetch/max in-flight: حد من عدد الرسائل المعالجة في وقت واحد لكل عامل (على سبيل المثال، 16-64) حتى لا «يسد» قاعدة البيانات/واجهة برمجة التطبيقات الخارجية.
- أكير/يكرر: «ack» بعد التسجيل الخفي ؛ التأخير الأسي والنفخ يتكرر.
- DLQ/ساحة انتظار السيارات: لا توجد ملاذات لا نهاية لها - بعد محاولات N، تذهب إلى Dead Letter Queue.
- التقسيم (كافكا): المفتاح حسب الجوهر (المستخدم/txnId) للطلب ؛ التوازي من خلال عدد الأحزاب.
5) الضغط على الظهر - كيف لا تغرق
الفكرة: خذ فقط ما يمكنك معالجته ضمن زمن انتقال SLO.
الفنيون:- التحكم في القبول: الحد من المنافسة (semaphore/worker-pool) لكل تبعية خارجية: قاعدة بيانات، PSP، مزود الألعاب.
- تشكيل حركة المرور: دلو رمزي/دلو متسرب عند مدخل الخدمة وعلى الطرق الحرجة.
- قوائم الانتظار ذات الحدود العليا: عند الامتلاء، اقطع الذيل (429/503 + Retry-After) أو انتقل إلى الدفعة في أسرع وقت ممكن.
- التزامن التكيفي (AIMD): زيادة التوازي في النجاح، وتقليل المهلات.
- قاطع الدائرة: «مغلق → مفتوح → نصف مفتوح» بسبب أخطاء/مهلات واجهة برمجة التطبيقات الخارجية ؛ عند الانهيار المفتوح (المخبأ/الكعب).
اذهب sem: = make (chan struct {}، 64 )//حد المنافسة إلى DB/PSP
مقبض func (req) {
اختر {
case sem <- struct {} {}:
تأجيل func () {<-sem} ()
ctx، إلغاء: = السياق. WithTimeout (req. ctx، 300 مرة. مللي ثانية)
إرجاء الإلغاء ()
القرار، الخطأ: = db. افعل (ctx، req)
إذا كان الخطأ = السياق. الموعد النهائي تجاوز {المقاييس. مهلة. Inc () ؛ TooSlow ()}
عودة طيب (قرار)
الافتراضي:
المقاييس. ضغط خلفي. Inc ()
Return TooBusy (429، "Retry-After: 0. 2")
}
}
6) المهلات والتراجع والرحيل: «ثلاثة حيتان على قيد الحياة»
مهلة أقصر من SLO: إذا SLO 400 mm، مهلة DB/مزود 250-300 mm ؛ إجمالي مهلة الطلب <400-600 مللي ثانية.
Retrai محدود وذكي: 1-2 محاولات كحد أقصى، فقط للعمليات الآمنة (الحمقاء)، مع الأس والذبابة.
الفحم: إعادة تجميع لمفتاح واحد.
Cseudocode (asonent + jitter):ثعبان لمحاولة في المدى (0، 2):
حاول:
نداء العودة (dep, timeout = 0. 3)
باستثناء المهلة:
التراجع = (0. 05 (2attempt)) + عشوائي. الزي الرسمي (0، 0. 05)
النوم (التراجع)
رفع المنبع غير متوفر
7) الهوية والتفريغ
Idempotency-Key on HTTP (الودائع، المدفوعات)، 'التشغيل _ id' في قاعدة البيانات (الفهرس الفريد).
Inbox/Outbox: خطوط الويب الواردة - دائمًا من خلال جدول بريد غير قابل للتغيير مع شطب بواسطة 'event _ id' ؛ الخارج - من صندوق الخروج عن طريق المعاملة.
مرة واحدة بالضبط «بالمعنى»: نسمح بالتسليم/التنفيذ المتكرر، ولكن هناك تأثير واحد فقط.
8) واجهة برمجة التطبيقات السريعة للعمليات البطيئة
الرد المتزامن: 201/202 + الحالة URL ('/status/{ id} ')، ETA والتلميحات الرجعية.
Hooks/Server-Sended Events/WS - ادفع الحالة عند الاستعداد.
انضباط العميل: «إعادة المحاولة بعد»، الغباء، حد الاقتراع.
مثال على الرد:جسون
HTTP/1. 1 202 مقبولة
الموقع :/ v1/withdrawals/req_9f2/status
إعادة المحاولة بعد: 2
{
«request_id": «req_9f2,» «دولة»: «معالجة»، «next_check_sec": 2
}
9) تقليل العمل الساخن
ضع الأشياء الثقيلة في الخلفية: التحولات والتجمعات والإشعارات والكتابة إلى DWH.
المخبأ والإسقاطات: عادة ما تقرأ - بغض النظر عن المخبأ مع TTL قصير وإعاقة الحدث.
أنماط الدفعات: المكالمات الخارجية الجماعية (على سبيل المثال طلب حدود مقدمي الطلب مرة واحدة في N ms).
التسلسل: الترميز السريع (protobuf/msgpack) للاتصالات بين الخدمات ؛ جسون على حافة الهاوية فقط.
10) DB تحت السيطرة
برك الاتصال: الحدود العليا (بناءً على النوى/IO)، تم تمكين قوائم الانتظار للتجمع.
الفهارس والخطة: p95 شرح + الانحدار التلقائي للخطط.
طلب مهلة: قصيرة، «بيان _ مهلة» (Postgres).
الصفوف/الأقفال الساخنة: شحنات المفاتيح، الأقفال المتفائلة (إصدار التوازن)، الملحمة بدلاً من المعاملة «المتجانسة».
11) WebSocket/في الوقت الفعلي
محدد النشرة الإخبارية: بث مدفوع، أقصى msgs/ثانية لكل اتصال.
الضغط الخلفي الداخلي: طابور الرسائل الصادرة مع غطاء ؛ على الفائض - إسقاط الأولوية المنخفضة.
التوجيه اللاصق و PDB أثناء الإصدارات - حتى لا تنتج عاصفة إعادة الاتصال.
12) إمكانية الملاحظة حتى لا تخمن
المقاييس (RED/USE + الضغط الخلفي):- «request _ rate», «error _ rato», «latency _ p95/p99» on routes.
- «queue _ depth», «lag _ seconds',» consumer _ floight', «retries _ total», «dlq _ rate».
- "backpressure _ drops'،" قبول _ رفض "،" دائرة _ مفتوحة ".
- Для БД: «الاتصالات _ في _ الاستخدام/الحد الأقصى»، «الأقفال»، «الاستفسارات البطيئة».
- الآثار: قائمة انتظار → العامل → db/psp «بعلامات» عملية _ id' و «تقسيم» و «إعادة».
- جذوع الأشجار: هيكلية، مع 'تعقب - معرف'، بدون مؤشر هوامش الاستثمار ؛ أحداث فردية «دائرة مفتوحة/مغلقة».
13) اختبار التحميل
نموذج مفتوح (وصول/ثانية) للرشقات النارية ؛ النموذج المغلق للدورات.
الملفات الشخصية: انفجار قصير 60-120 ثانية ونقع 1-4 ساعة.
فشل الحقن: إبطاء واجهة برمجة التطبيقات الخارجية بمقدار + 200-500 مللي ثانية، انظر إلى p99/retrai/قوائم الانتظار.
معايير المنطقة الخضراء: لا توجد قائمة انتظار للنمو، مستقرة p95، 'dlq_rate≈0'.
14) السلامة والموثوقية
طوابير TLS/mTLS، توقيع الرسائل، مراقبة المخطط (Avro/Protobuf + Schema Registry).
المنتج اللطيف (كافكا)، مرة واحدة بالضبط حيث يكون مبررًا.
وضع الفوضى: «إسقاط» الإدمان بشكل دوري وانظر إلى التدهور (الدائرة، الاحتياطي).
15) أمثلة على «قطع» من التكوينات
تشكيل مدخلات Nginx/المبعوث:nginx limit_req_zone $ binary _ remote _ addr zone = api: 10 مليون معدل = 20r/s ؛
خادم {
الموقع/api/{
منطقة limit_req = انفجار آبي = 40 عقدة ؛
proxy_read_timeout 0. 6s ؛ # أقصر من SLO proxy_connect_timeout 0. 2 ق ؛
}
}
RabbitMQ (بريفتش):
الأساسية. qos (prefetch_count = 32) # رصيد وحدة المعالجة المركزية/IO
مستهلك كافكا (جزء جاوة):
دعائم جافا. (ConsumerConfig. MAX_POLL_RECORDS_CONFIG، 200) ؛
الدعائم. (ConsumerConfig. FETCH_MAX_BYTES_CONFIG، 5_000_000) ؛
الدعائم. (ConsumerConfig. MAX_POLL_INTERVAL_MS_CONFIG، 60_000) ؛
16) قائمة مرجعية للتنفيذ (جاهزة)
- تنقسم المسارات الحرجة إلى استجابة متزامنة ومعالجة غير متزامنة (SEDA).
- مراقبة القبول وحدود المنافسة بالنسبة للتبعيات الخارجية.
- المهلات أقصر من SLO ؛ retrai ≤ 2، مع الأس والنفث ؛ الدمج.
- قاطع الدائرة + التحلل (المخبأ/الكعب)، سياسة نصف مفتوحة.
- قوائم الانتظار/التدفقات: مسبقة/على متن الطائرة، DLQ، دفعات رئيسية.
- الخصوصية (operation_id/Idempotency-Key)، Outbox/Inbox، التفريغ.
- ذاكرة التخزين المؤقت: بغض النظر عن المخبأ، إعاقة قصيرة في حدث TTL +.
- DB: حدود المجموعة، statement_timeout، والفهارس، واستراتيجيات منع القفل.
- WS: حدود الرسالة، الجزر، التوجيه اللزج، PDB.
- إمكانية الملاحظة: مقاييس الضغط الخلفي/قوائم الانتظار/الإعادات، المسارات من طرف إلى طرف، لوحات القيادة.
- اختبارات الحمل والفشل (مفتوحة + مغلقة، انفجار + نقع)، معايير المنطقة الخضراء.
ملخص السيرة الذاتية
الواجهة الخلفية السريعة ليست «صنع مخبأ آخر»، ولكنها تيار متحكم فيه: الدخول محدود وثقيل - في الخلفية، كل مرحلة بها قائمة انتظار وحدود، إعادة التدوير نادرة وذكية، والسلاسل محمية بواسطة قاطع الدائرة والغباء. أضف انضباط المهلة وقابلية الملاحظة واختبارات الإجهاد المنتظمة - وستظل p95/p99 خضراء حتى تحت رشقات ونزوات مقدمي الخدمات الخارجيين.