الجزء 5: قِس، غيّر، قِس ثانية: Load Tests، مساء امتحان حقيقي و المعمارية النهائية
سبع قياسات، مساء امتحان حقيقي واحد و scale-in خطأ واحد: كيف load tests، نموذج الطاقة و خطة soak صادقة شكّلت المعمارية النهائية NovaCommerce، تكلفتها، و قائمة تحقق معماري الحلول. الجزء 5 يغلق السلسلة.
في مساء من 7 أكتوبر، 661 طالب بدأ امتحان على NovaCommerce، في ذروة من 86 يبدأ دقيقة، و 439 أكثر جلس امتحان ثاني بعده. Backend قمم في حول 69 طلب في الثانية ووصل 47% CPU على متوسط دقيقتين. قاعدة البيانات استخدمت أقل من ربع CPU الخاص بها. لا وظيفة خلفية فشلت.
بعدها pool minimum انخفض في وسط امتحان. عقدة تخدم اختفت بدون draining، و حول 360 طلب فشل في دقيقتين.
كلا نصي ذلك المساء كانا اختبار نتائج: النصف الهادي جاء من run قصير من اختبارات الأيام قبل، النصف القبيح من شيء لا امتحان كان قد غطى بعد. هذا الجزء يمشي الرحلة بالترتيب (baseline، load test، bottleneck، optimization، retest، scaling، soak، final result)، بعدها يظهر المعمارية النهائية، تكلفتها، و قائمة تحقق أستخدمها الآن في كل review.
هذا الجزء 5 من سلسلة خماسية «من خادم واحد إلى جاهز لليلة الامتحان». NovaCommerce اسم خيالي؛ المعمارية والأرقام والأخطاء حقيقية.
الحلقة نحن احتفظنا بتكرار
كل تغيير في هذه السلسلة جاء من حلقة واحدة: قِس، جد الاختناق، افهم السبب، غيّر التصميم، اختبر ثانية، قِس ثانية. تغيير قبل السبب مفهوم هو تخمين، و تخمين يحدث ليكون خادم يكلّف أموال كل شهر. فكر من خرطوم حديقة مع knink: إذا ماء ضعيف، صنبور أكبر لا يفعل شيء، لذا تمشي الخرطوم حتى تجد knink. لنا تحرك ثلاث مرات، و كل مرة كانت مشكلة نوع مختلف.
سبع قياسات، كل واحد مع رقم خلفه، و بطاقة واحدة مقطّعة للاختبار ذلك لا يزال مخطط.
Baseline و load test: الاختناق تحرك ثلاث مرات
Baseline: رمز حالة، ليس رسم CPU
الشيء الأول قسناه على الإنتاج لم يكن CPU. في 25 سبتمبر، طلاب كانوا يحصلون على HTTP 429 (طلبات كثير) أثناء امتحانات. API rate limiter مفتاح على عنوان IP، لأن حارس المصادقة الافتراضي كان فارغ لـ token-based طلاب. مدرسة أو carrier جوال يضع مئات الطلاب خلف IP NAT واحد، لذا بناء كامل شارك جرة واحد. 429 التطبيق يقول لا، ليس خادم خارج نفس، لذا لا عقدة إضافية كانت ستساعد. Implemented: المحدد الآن مفاتيح على طالب أو حساب معلم، و على IP فقط لـ ضيوف.
Load test: 2,854 أخطاء، جملة واحدة
في 02:28 في 6 أكتوبر، اختبار تحميل backend أرجع 2,854 تطبيق 500s، كل واحد RedisException: Operation timed out أثناء الاتصال (timeout اتصال 5 ثانية). السبب: Valkey (4 GB، primary و standby) لم تستطيع قبول اتصالات بسرعة كافية، و كل طلب فتح اتصال TLS جديد إليه، حول 5.4 ملسة من CPU لكل طلب ضد حول 3.3 ملسة لـ MySQL. خوادم ويب أكثر فقط كانت ستفتح أكثر اتصالات إلى Valkey نفس.
Implemented: Valkey resized في المكان إلى 8 GB على اثنين عقدة (primary و standby)، البيانات احتفظت، host بدون تغيير. تكلّف أكثر أموال، و أزالت فشل حقيقي.
Retest: ارتقاء تدريجي من 25 إلى 500 طلب في الثانية، ابتداء على اثنين backend عقدة بينما البركة تتسع، أعطى 0 أخطاء تطبيق و 0 backend 5xx. كانت هناك 143 أخطاء في load balancer، لكن فقط بينما الأنوية كانت CPU-saturated. ذلك الإشارة المتوقع «خارج الطاقة»، ليس خطأ، وهو أظهر لنا حيث كل عقدة جري خارج.
كم واحد عقدة يمكن تفعل
اختبارات backend أيضاً أعطتنا الرقم كل قرار لاحق يميل عليه. في CPU كامل، عقدة backend 4 vCPU / 8 GB واحد خدمت حول 65 إلى 70 طلب في الثانية من خليط API حقيقي، حول 59 ملسة من CPU لكل طلب. الأرقام اتفقت: 4 vCPU هو 4,000 ملسة CPU في الثانية، و 4,000 مقسوم على 59 حول 68. Autoscale أضاف عقدة إضافية أولى حول 7 دقائق بعد وصول CPU إلى 99%.
ذلك يجعل ثلاثة اختناقات بالترتيب: قاعدة (محدد المعدل)، طبقة البيانات (اتصالات Valkey)، و فقط بعدها CPU عادي backend. كل واحد احتاج إصلاح مختلف، و فقط الأخير يُحل بـ خوادم أكثر.
اختبارات scaling: هل الخوادم الجديدة تصل، و متى؟
Frontend: عقدتين، 356 طلب في الثانية
مع frontend أُعيد بناء كـ برك (nginx أمام اثنين متطابقين Next.js containers لكل عقدة)، عقدتين خدما حول 356 طلب في الثانية، p95 0.05 س، 0 أخطاء، في 55 إلى 60% CPU، و قارنا 12 صفحة حقيقية مقابل الخادم القديم. Headroom دفعت نفسها: البركة تحرك من dedicated-CPU droplets إلى shared AMD 2 vCPU / 4 GB droplets. Implemented.
اختبار autoscale 16 دقيقة
في 5 أكتوبر، من 21:17 إلى 21:33، k6 أعاد تشغيل خليط طلب ذروة امتحان حقيقي (GET فقط، لا شيء كُتب): 300 إلى 450 طلب في الثانية، بعدها حول 750 لـ ستة دقائق.
Backend تسع من 2 إلى 3 عقدة في 21:29، عندما متوسط بركة وصل 75%. Frontend تسع من 2 إلى 3 في 21:30، في 71%. عقد جديدة انضمت load balancers بنفسهم.
0 أخطاء خادم، 0 timeouts، p95 شاملة من 132 إلى 153 ملسة. API p95 كان 320 إلى 705 ملسة بينما backend جلس بالقرب 90% ينتظر عقدة ثالثة.
حول 4% من طلبات حصل 429، لأن كل الحمل جاء من IP اختبار واحد: حدود per-IP فعل وظيفتهم.
الدرس كان في التوقيت. CPU metric DigitalOcean يتخلف الحمل الحقيقي بـ 5 إلى 8 دقائق، لذا scaling يبدأ متأخر و بعدها overshoots: backend briefly تسع إلى 4 بعد الحمل قد توقف. عقدة backend إضافية أولى جاءت اثنا عشر دقيقة بعد اختبار بدأ، و امتحان لا ينتظر اثنا عشر دقيقة. لذا لـ امتحانات مجدول نحن pre-scale، رفع pool minimum حول 45 دقيقة قبل واحد كبير، و احتفظ autoscaling الفورية كالشبكة الأمان. النسخة الشاملة من هذا الحجة في Autoscaling for Traffic Spikes.
Rollout probe
Tested, then fixed: أول backend template rollout لنا أنتج blip 503 قصير، لأن DigitalOcean حذفت droplets القديمة بينما load balancer لا يزال يوجه إليهم. Guarded rollout غيّر فقط الصورة، ينتظر حتى عقد جديدة أجاب /lb-health، ينتظر حول 40 ثانية لـ balancer لـ تعترف بهم، و يفرّغ عقد القديمة أولاً. Rollout كامل من كلا البركتين في 7 أكتوبر تشغل تحت uptime probe كل 2 ثانية على صفحات حقيقية: 219 probes، 0 أخطاء.
حيث scaling ساعد، و حيث لم يفعل
هذا الجدول أتمنى كنت قد رأيت قبل ابتداء. لـ كل مشكلة الاختبارات أو الإنتاج كشف، ذلك يسأل سؤال واحد: هل خوادم أكثر كانت ستصحح ذلك؟
مشكلة وجدت
خوادم أكثر؟
ما صححه
Status
Backend CPU مشبع في 65 إلى 70 طلب/س لكل عقدة
نعم
Autoscale pool (2 إلى 10 عقدة) زائد pre-scaling
Implemented
مدارس كاملة حصل 429 (25 Sep)
لا
Limiter مفتاح لكل حساب طالب، IP فقط لـ ضيوف
Implemented
Route throttles لا يزالوا يحسبون بـ IP: 74% من استدعاءات إلى endpoint dashboard واحد أرجعت 429 في امتحان (7 Oct)
لا
Throttles احسب لكل طالب لكل route؛ 0 مثل 429s بعده
Implemented
2,854 Valkey اتصال timeouts (6 Oct)
لا
Valkey resized في المكان إلى 8 GB x 2
Implemented
Merit cards (وظيفة 0.34 ثانية) انتظار 10 إلى 115 دقيقة خلف وظائف AI حول 10 ثوان كل (6 Oct)
لا
حارة queue منفصلة لـ وظائف AI؛ merit cards جاهزة في حول 1 دقيقة
Implemented
Backend يرى IP frontend واحد لكل طالب
لا
مرر طالب IP حقيقي في رأس موقع
Planned
من ستة مشاكل، واحد كان مشكلة طاقة. الخمسة الأخرى كانوا قاعدتان، حد اتصال، تخطيط queue و رأس غائب. جانب طبقة البيانات من هذا النموذج مغطى في The Data Tier Under Load.
Soak testing: ما شغلنا و ما لم نفعل
اختبار حمل يسأل كم النظام يمكن يأخذ. اختبار soak يسأل كم طويل يمكن يأخذها: محرك في revs كاملة دقيقة يثبت قليل حول ثلاث ساعات، لأن مشاكل بطيئة تظهر متأخر (ذاكرة التي تزحف، اتصالات التي تسرب، أقراص التي تملأ، طوابير التي تنجرف). «نحن soak اختبرنا ذلك» سهل يقول و صعب defend، لذا سأكون دقيق: نحن لم ننشئ اختبار soak رسمي حتى الآن.
دليل
ما يغطي
Status
Runs قصير sustained: 25 إلى 500 طلب/س climb، 16 دقيقة autoscale اختبار في حول 750 طلب/س، 2 ثانية uptime probe عبر rollout
دقائق من حمل sustained: 0 أخطاء تطبيق في climb، 0 أخطاء خادم في autoscale اختبار
Tested
7 Oct مساء امتحان: حول ساعتان، امتحانان ظهراً ضهراً
CPU ثابت، 0 وظائف فشل، واحد scale-in خطأ
Observed في الإنتاج
Soak متعدد الساعات معاً مع اختبار حمل كبير التالي، في نافذة صيانة موافق عليها
نمو الذاكرة، تسريب اتصال، queue drift
Planned
مساء امتحان أقرب شيء عندنا، لكن أنه مراقبة، ليس اختبار مسيطر عليه. فحص مرتبط واحد يحمل: backend nodes كتبوا 0 ملفات إلى disk في 24 ساعة، لذا أقراص ليست soak خطر هناك. Frontend nodes لا يزالون يبقون حول 440 MB من nginx السجلات يومياً محلياً، وهو لماذا Fluent Bit على frontend على القائمة المخطط.
امتحان حقيقي: 7 أكتوبر كـ إثبات الإنتاج
لا شيء يستبدل طلاب حقيقي. امتحانان تشغلوا ظهراً ضهراً، و digest مرة في دقيقة لنا راقبهم: طلاب بدأوا و أرسلوا، طلبات و 5xx لكل عقدة، pool CPU، حمل عامل و وظائف فشل.
قياس
النتيجة
امتحان A (20 دقيقة)
661 بدأوا، 638 أرسلوا (96.5%)؛ يبدأ قمم في 86 لكل دقيقة
امتحان B (25 دقيقة)
439 بدأوا، 425 أرسلوا (96.8%)
Frontend
حتى 1,741 زائرين فريد في امتحان A، peak 403 في دقيقة واحدة؛ حول 732,000 طلبات من 6 إلى 8 مساء؛ CPU حتى 24%
Backend
Peak حول 69 طلب/س (لكل دقيقة السجلات؛ 63 على متوسط دقيقتين الموفر)؛ CPU حتى 47% على متوسط دقيقتين؛ عقدة واحد 86% دقيقة واحد
MySQL
CPU الأقصى 24.5% (متوسط 13.4%)، في معظم 5 استعلامات جاري، 0 lock waits
Valkey
12.5% ذاكرة
العامل
CPU 46%، 0 وظائف فشل
ثلاثة أشياء برز.
الاختناق backend CPU لكل عقدة، وقاعدة البيانات كانت حول 6 مرات headroom. النموذج أسفل يضع حد MySQL بالقرب 450 طلب/س، ضد 69 على الليلة.
أرقام الاختبار تنبأت المساء. 63 طلب في الثانية في 59 ملسة من CPU كل حول 3.7 ملسة CPU في الثانية. اثنين 4 vCPU عقدة لديها 8 vCPU، لذا المتوسط يجب أن يكون حول 46%. لوحة تحكم قال 47%.
المتوسط يخفي عقدة التي تؤلم. حركة انقسمت 65/35 بين اثنين backend عقدة، لأن اتصالات long-lived keep-alive من frontend proxies أداة حركة. لوحة تحكم قالت 47% بينما عقدة واحد لمس 86% دقيقة واحد.
خطأ scale-in
في وسط امتحان، شخص خفض backend pool minimum. DigitalOcean أزالت عقدة تخدم بدون draining، و حول 360 طلب فشل في دقيقتين. الاختبارات السابقة كانت قد علمتنا أن scale-out بطيء و متأخر. امتحان علم النصف الآخر: scale-in سريع و لا تقول وداع. Implemented كقاعدة runbook: رفع minimum قبل امتحان، خفض فقط بعد، و أبداً لا ثقة autoscale scale-in إلى drain عقدة.
نموذج الطاقة: ما يقول، و حيث يتوقف
بعد امتحان حولت البيانات الحقيقية إلى نموذج صغير، لذا امتحان التالي يمكن مخطط مع حساب بدلاً من خوف. لديه أربع مدخلات مقاس: حول 15 طلبات لكل طالب عندما امتحان يفتح، بعدها حول 1.5 دقيقة (0.025 الثانية)؛ حول 30 طلب/س من حركة baseline؛ 50 طلب/س كـ safe حمل لـ عقدة backend واحد (75% CPU)؛ و هامش 30% لـ uneven splitting.
بكلمات عادية: خذ عقد التي ستملك، اضرب بـ 50، اقسم بـ 1.3 لـ الهامش، و اطرح 30 من حركة baseline. ما يبقى هو ما الطلاب قد استخدم في لحظة الأخير واحد ينضم. كل طالب يكلّفة 15 طلب افتتاح انتشر عبر نافذة الانضمام، زائد 0.025 لـ وجود.
خذ 4 عقدة. 4 × 50 / 1.3 حول 154، و minus 30 يترك حول 124. إذا الطلاب تنضم عبر 10 دقائق، كل كلفة 15 / 600 + 0.025 = 0.05 طلب/س، لذا 124 / 0.05 يعطي تقريباً 2,500 طالب؛ جدول يجمع أسفل إلى 2,400. إذا كلهم تنضم في دقيقتين، كل كلفة 15 / 120 + 0.025 = 0.15، وهو يعطي تقريباً 800.
Backend nodes
الانضمام عبر ~10 دقائق
كل الانضمام ضمن ~2 دقيقة
Safe backend حمل (derived)
2
حول 900
حول 300
حول 77 طلب/س
4
حول 2,400
حول 800
حول 154 طلب/س
6
حول 4,000
حول 1,300
حول 231 طلب/س
8 إلى 10
5,500 أو أكثر
1,800 إلى 2,300
حول 308 إلى 385 طلب/س
Backend عقدة الحد طول الطريق إلى 10 عقدة؛ MySQL سطر يجلس فوق حتى 10-node ceiling.
المساء الحقيقي يناسب الصف الأول: ذروة من 86 يبدأ دقيقة ضد تقريباً 90 دقيقة ذلك الصف يسمح. حيث النموذج يتوقف:
ذلك جاء من امتحان اختيار متعدد واحد. امتحانات مكتوبة مع تحميل PDF أثقل العامل بكثير و يجب أن تُقاس منفصل.
صفوف فوق 3 عقدة extrapolated؛ الأكثر رأينا في اختبار 3 عقدة، briefly 4. Planned: اختبار حمل كامل في نافذة صيانة.
عقد فقط تحسب مرة تلك الموجود. مع metric تتخلف 5 إلى 8 دقائق و عقدة إضافية أولى حول 7 دقائق بعد وصول CPU إلى 99%، الجدول guide pre-scaling، ليس وعد autoscaling الفورية.
هو يغطي backend طلب path فقط. العامل، Valkey و حد معدل الموفر AI لديهم سقوفهم الخاصة.
المعمارية النهائية، طبقة بـ طبقة
صناديق صلبة تشغل اليوم؛ شريط مقطّع مخطط.
كل صندوق موجود لأن اختبار أو امتحان حقيقي طلب ذلك؛ شريط مقطّع ما لم نفعل بعد.
حافة. اثنين load balancers، واحد لكل tier. Rejected: واحد balancer لـ كلاهما، لأن DigitalOcean balancer لا يمكن يوجه بـ host أو path.
Frontend pool. 2 إلى 10 عقدة، nginx أمام اثنين Next.js containers (واحد لكل vCPU)، scaling في 70% CPU.
Backend pool. 2 إلى 10 عقدة من snapshot ذهبي واحد، فقط nginx و php-fpm، CPU target 55% (بدأ في 70%). لا وظائف على عقد ويب، لذا عقد إضافية أبداً لا تشغل واحد مرتين.
البيانات. MySQL Standard 8.4 (4 vCPU / 16 GB، primary و standby، القراءات على standby، sticky = true)؛ Valkey 8 GB على اثنين عقدة؛ PostgreSQL مع pgvector (2 vCPU / 4 GB) بقيت أجزاء، لذا vector استعلامات أبداً تتنافس مع كتابات امتحان.
العامل. Droplet ثابت واحد 4 vCPU / 8 GB لـ حارات queue (يشمل حارة AI منفصل)، المجدول، WebSockets و كل SMS، لأن بوابة SMS whitelist عنوان واحد. نقطة فشل معروف مفردة.
ملفات، السجلات، مراقبة. Spaces خلف CDN؛ backend سجلات عبر Fluent Bit إلى OpenSearch؛ ops console لنا العينات كل tier read-only و يشغل guarded deploys.
قبل و بعد
مجال
قبل (حتى 5 Oct)
الآن
Frontend
Droplet واحد 8 vCPU / 16 GB، حاوية Next.js واحد، لا load balancer
Load-balanced بركة من 2 إلى 10 عقدة، اثنين containers لكل عقدة
Backend
Droplets اثنين ثابتين، مستهدفين برقم معرف، لذا خوادم جديدة أبداً لا تنضم
Balancer يستهدف وسم؛ بركة من 2 إلى 10 من snapshot واحد، pre-scaled قبل امتحانات
MySQL
عقدة Advanced واحد، 8 vCPU / 32 GB، لا standby
Standard 4 vCPU / 16 GB، primary و standby
خوادم «Standby»
Droplets اثنين مطفأين، $112 شهرياً، دقائق للتشغيل
أزيل؛ standby حقيقي داخل MySQL و Valkey (الآن 8 GB، من 4)
ما الأموال يشتري
البند (شهري، أسعار DigitalOcean القائمة)
التكلفة
قبل: web tier كامل (16 GB frontend، 2 backend، worker، 1 load balancer، 2 powered-off standbys)
حول $416
الآن، web tier: 2 backend ($56 كل)، 2 frontend ($28 كل)، worker، اثنين load balancers
$112 + $56 + $56 + $48
الآن، البيانات و السجلات: MySQL زوج، Valkey 8 GB x 2، PostgreSQL، OpenSearch
حول $389 + $240 + $60 + $20
الآن: snapshots، Spaces
حول $5 + $5 و استخدام
الآن: الإنتاج الكامل، backend بركة في 2 عقد
حول $990
الإجماليات ليست مثل لـ مثل: $416 كان web tier فقط، و $990 الإنتاج كل. على نفس أسعار القائمة web tier وحده الآن حول $272. الآخر $709 Managed MySQL، Valkey، PostgreSQL و OpenSearch، و ذلك ما المال إضافي يشتري: قاعدة بيانات التي تنجو من فشل عقدة، Valkey مع مجال و standby، vector search ذلك يبقى خارج الطريق من كتابات امتحان، و السجلات التي تنجو عقدة حذف. Pre-scaling الجزء الرخيص: عقدة backend إضافية تكلّف حول $0.08 في الساعة. القرارات خلف الأرقام في قائمة التحقق أسفل.
مخطط، و not done
Planned: اختبار حمل كامل و soak متعدد الساعات رسمي في نافذة صيانة، قبل امتحان كبير التالي.
Planned: Next.js أصول ثابتة من CDN، Fluent Bit على عقد frontend، و رأس real-IP موقع من frontend إلى backend لذا كل قاعدة per-IP و كل سطر log دقيق.
Planned: عامل high availability: محجوز IP whitelist مع بوابة SMS، عامل standby صغير، و عامل burst exam-only بدأ قبل امتحانات كبيرة.
Considered: Kubernetes (DOKS) لـ seconds-level scaling، الذي أكثر بكثير للتشغيل. Warm standby جاهز في 3 إلى 4 ثوان أيضاً considered، لكن DigitalOcean برك لا دافئ، لذا نحن pre-scale و احتفظ طاقة احتياطية تخدم داخل balancer.
قائمة تحقق لمهندس الحلول (Solutions Architect)
هذه هي القائمة التي أستخدمها الآن في مراجعات المعمارية. كل بند فيها شيء فعله هذا المشروع أو دفع ثمنه.
قابلية التوسع
عُقد الويب بلا حالة (stateless): الجلسات والـ cache والـ queues في Valkey، والملفات المرفوعة في Spaces، ولم يُكتب أي ملف على القرص خلال 24 ساعة.
كل طبقة تتوسع بوحدتها الخاصة: حاويتا Next.js في كل عقدة frontend، وعمّال php-fpm في كل عقدة backend.
الحمل المعروف مسبقًا يُجهَّز له مسبقًا (pre-scale)، والتوسع التفاعلي ليس إلا شبكة أمان.
التوافر
لا توجد عقدة واحدة يمكن أن تُسقط الموقع: موازِنا حمل، وحد أدنى من عقدتين في كل pool، وstandby لكل من MySQL وValkey.
يجيب nginx وحده على فحص الصحة، وتُفرَّغ العقدة (503 على /lb-health) قبل إزالتها.
يبقى النظام القديم حتى تغادره الحركة فعلًا: بعد ساعة من تبديل DNS كان لا يزال يستقبل نحو 36% من الطلبات.
الأداء
اعرف زمن CPU لكل طلب (59 ms)، وليس فقط عدد الطلبات في الثانية.
راقب كلفة الإعداد لكل طلب: اتصال TLS جديد كلّف نحو 5.4 ms من CPU مع Valkey و3.3 ms مع MySQL.
القراءات تتوزع بين الـ standby والـ primary، والكتابات تذهب إلى الـ primary، ومع ذلك يرى الطالب إجابته فورًا.
الموثوقية
المهام البطيئة لها مسار queue خاص بها، فلا تنتظر مهمة مدتها 0.34 ثانية خلف مهمة مدتها 10 ثوانٍ.
الاستدعاءات إلى المزودين الخارجيين منظَّمة الإيقاع ويُعاد تنفيذها (8 في الدقيقة مشتركة، وتراجع من 1 إلى 15 دقيقة، ولمدة تصل إلى 12 ساعة)، فلا يرى الطلاب أي خطأ.
حدود المعدل تُحسب لكل طالب لا لكل IP، أينما تشارك طلاب كثيرون عنوانًا واحدًا.
قابلية المراقبة
ملخص كل دقيقة أثناء الامتحانات: من بدأ ومن سلّم، والطلبات و5xx لكل عقدة، وCPU الـ pool، وحمل الـ worker، والمهام الفاشلة.
انظر إلى كل عقدة على حدة، لا إلى متوسط الـ pool فقط (47% مقابل 86%).
السجلات تعيش أطول من العقدة: Fluent Bit إلى OpenSearch في الـ backend، أما الـ frontend فما زال Planned.
التعافي من الأعطال
نسخ احتياطية وfailover مُدارة لقاعدة البيانات، وsnapshots ذهبية، والاحتفاظ بآخر 3 صور جيدة للتراجع (rollback).
كل انتقال يترك طريقًا للعودة: قاعدة البيانات القديمة مجمّدة 48 ساعة، والـ frontend القديم باقٍ حتى انتهاء تأثير DNS.
نقاط الفشل المفردة مكتوبة صراحة. الـ worker واحدة منها: إن توقف، تتوقف الرسائل النصية والمجدول ومعالجة الامتحانات، بينما تنتظر التسليمات بأمان في Valkey.
التكلفة
قِس الهامش قبل اختيار الحجم: انتقل الـ frontend إلى CPU مشترك بعد الاختبار، وحلّ MySQL من فئة Standard مع standby محل عقدة Advanced واحدة كبيرة (أرخص ومتاح بدرجة عالية).
أزل الإنفاق الذي لا يشتري شيئًا: كلّف خادمان احتياطيان مُطفآن 112 دولارًا شهريًا ولم يقدّما أي توافر.
جهّز مسبقًا بدل الإفراط في الحجز، وأنفق حيث يزيل الإنفاق عطلًا حقيقيًا، مثل Valkey الأكبر.
قابلية الصيانة
لا تعدّل عُقد الـ pool يدويًا أبدًا: غيّر عقدة واحدة، واختبرها، وخذ لها snapshot، ثم وجّه قالب الـ pool إليها.
مرّر كل الإعدادات في أي تحديث للـ pool حتى لا يُعاد ضبط شيء بصمت.
الحمايات الجديدة تُشحن مع اختبارات تفشل من دون الإصلاح، كما حدث مع حدود المعدل لكل طالب.
النمو المستقبلي
اكتب حساب الاتصالات: 10 عُقد × 80 عامل php-fpm = 800، أقل من حد MySQL البالغ 1,601.
اعرف السقف التالي: MySQL عند نحو 450 طلبًا في الثانية، أي قرابة 6 أضعاف ذروة تلك الليلة.
قِس الامتحانات الكتابية وحدها، وراجع حدود الحساب مبكرًا: كان لا بد من رفع حد الـ droplets البالغ 25 قبل أن يصل الـ poolان معًا إلى حدهما الأقصى أثناء rollout.
ما تعلمناه، وأين يتركنا هذا
أول اختناق نادرًا ما يكون ما كنت تخشاه. قلقنا من الخوادم، لكن المشكلات الثلاث الأولى كانت قاعدة لحدود المعدل، وحدًا للاتصالات، وتصميمًا للـ queues.
عالج السبب لا العَرَض. مشكلة واحدة فقط من كل ست كانت مشكلة سعة.
قارن الإنتاج بالنموذج. 63 طلبًا في الثانية بـ 59 ms توقّعت نحو 46% من CPU، ورأينا 47%.
المتوسطات تخفي العقدة المتألمة، والتقليص (scale-in) مفاجئ. 47% في المتوسط و86% على عقدة واحدة؛ ارفع الحد الأدنى قبل الامتحان ولا تخفضه إلا بعده.
قل ما لم تختبره. لدينا اختبارات حمل وأمسية حقيقية واحدة، أما اختبار soak الرسمي فهو Planned.
عندما بدأت هذه السلسلة، كانت المنصة droplet واحدة للـ frontend، واثنتين للـ backend مثبتتين بالمعرّف، وعقدة قاعدة بيانات كبيرة واحدة. أمسية امتحان 7 أكتوبر عملت على نظام مختلف، ولم يأتِ أي من هذا الفرق من إضافة خوادم لمجرد الإضافة. جاء من الحلقة نفسها مرة بعد مرة، بما في ذلك المرات التي أخبرنا فيها القياس أننا مخطئون.
هذه الحلقة هي المعمارية؛ أما الـ pools والـ standbys والرسوم فهي ما تتركه خلفها. إن احتفظت بشيء واحد من هذه الأجزاء الخمسة، فاحتفظ بالحلقة، واستخدمها قبل ليلة امتحانك القادمة أو تخفيضاتك أو إطلاقك القادم.