في كل مرة يطلب فيها المتصفح مورداً من السيرفر، يجب عليه أولاً فتح اتصال. هذه المصافحة تستغرق وقتاً، وإذا كان السيرفر يغلق الاتصال بعد كل طلب فردي، فأنت تدفع هذه التكلفة مراراً وتكراراً. اتصالات Keep-Alive تحل هذه المشكلة، وفهم طريقة عملها يُعد من أبسط الطرق لتقليل وقت استجابة السيرفر في موقعك بالكامل.
ماذا يحدث فعلياً بدون Keep-Alive
بدون الاتصالات الدائمة، يتبع كل طلب هذا النمط:
- مصافحة TCP (SYN, SYN-ACK, ACK)
- مصافحة TLS إذا كنت تستخدم HTTPS (جولات إضافية أخرى)
- الطلب والاستجابة الفعليان عبر HTTP
- إنهاء الاتصال
على اتصال سريع، قد يضيف هذا 50-150 مللي ثانية لكل طلب. أما على شبكات الجوال أو الاتصالات بعيدة المدى، فقد يضيف بسهولة 300 مللي ثانية أو أكثر. الآن اضرب هذا في كل ملف CSS وملف JavaScript وصورة وخط تحمّله صفحتك. صفحة تحتوي على 40 مورداً بدون اتصالات دائمة قد تخسر عدة ثوانٍ فقط في إعداد الاتصال، قبل وصول أي بايت واحد من المحتوى الفعلي.
لماذا يهم هذا بالنسبة لـ TTFB
يحظى الوقت حتى وصول أول بايت (Time to First Byte) باهتمام كبير كمقياس أداء، لكنه في الحقيقة يقيس مدى سرعة استجابة السيرفر بعد إنشاء الاتصال بالفعل. إذا كان السيرفر يقوم باستمرار بإنهاء الاتصالات وإعادة بنائها، فأنت تضيف زمن استجابة خفياً لا تلتقطه قياسات TTFB دائماً بوضوح، خاصة في الصفحات التي تحتوي على موارد فرعية كثيرة. لقد كتبنا عن هذا الموضوع بتفصيل أكبر في لماذا يكلفك وقت الاستجابة الأول تحويلات ضائعة وكيف تصلح ذلك.
كيف تحل Keep-Alive هذه المشكلة
اتصال Keep-Alive يخبر السيرفر والعميل: لا تغلق اتصال TCP هذا بعد الاستجابة، بل أبقه مفتوحاً حتى نستطيع إعادة استخدامه للطلب التالي. بدلاً من مصافحة جديدة لكل ملف، يرسل المتصفح طلبات متعددة عبر نفس القناة.
في HTTP/1.1، تُعتبر Keep-Alive في الواقع السلوك الافتراضي. يبدو الرأس (header) هكذا:
Connection: keep-alive
Keep-Alive: timeout=5, max=100
هذا يعني أن السيرفر سيبقي الاتصال مفتوحاً لمدة 5 ثوانٍ من عدم النشاط، ويسمح بما يصل إلى 100 طلب عبر ذلك الاتصال الواحد قبل إغلاقه. إذا ضبطت هذه الأرقام بشكل خاطئ، فإما أنك تهدر موارد السيرفر بالحفاظ على اتصالات خاملة، أو تغلق الاتصالات مبكراً جداً وتفقد الفائدة كلياً.
إعداد Keep-Alive في Nginx
إليك نقطة بداية معقولة لإعداد Nginx:
keepalive_timeout 15;
keepalive_requests 1000;
- keepalive_timeout يتحكم في المدة التي ينتظرها السيرفر لطلب آخر على نفس الاتصال قبل إغلاقه.
- keepalive_requests يحدد الحد الأقصى لعدد الطلبات المسموح بها لكل اتصال.
مهلة قدرها 15 ثانية تعتبر نقطة وسط شائعة. إذا كانت قصيرة جداً، ستفقد فوائد إعادة الاستخدام للمستخدمين على شبكات أبطأ. وإذا كانت طويلة جداً، فستشغل اتصالات العمل (worker connections) التي يمكن أن تخدم زواراً آخرين، وهذا يصبح مشكلة حقيقية تحت الضغط. إذا أردت التعمق أكثر في ضبط جانب السيرفر من هذه المعادلة، فقد تناولنا إعداد عمليات worker في مقال كيفية إعداد عمليات Nginx worker لأقصى إنتاجية.
اتصالات Keep-Alive الخلفية (Upstream) مهمة أيضاً
يظن معظم الناس أن Keep-Alive تخص فقط الاتصال بين المتصفح وسيرفر الحافة (edge server). لكن إذا كان تطبيقك يقف خلف بروكسي عكسي (reverse proxy)، مثل Nginx الذي يتواصل مع PHP-FPM أو خلفية Node.js، فإن الاتصال بين البروكسي وتطبيقك يستفيد أيضاً من البقاء مفتوحاً.
إليك إعداد نموذجي للـ upstream يفعّل هذا:
upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}
بدون هذا، يفتح Nginx اتصالاً جديداً بالخلفية لكل طلب واحد يقوم بتمريره، حتى لو كان اتصال المتصفح بـ Nginx نفسه دائماً. هذه طريقة سهلة لتقليل وقت استجابة السيرفر يغفل عنها الكثير من الإعدادات تماماً.
استئناف جلسة TLS يضيف طبقة أخرى
إذا كنت تستخدم HTTPS (وينبغي أن تفعل)، فإن استئناف جلسة TLS يعمل جنباً إلى جنب مع Keep-Alive لإزالة تكاليف المصافحة المتكررة. إعداد ssl_session_cache وssl_session_timeout يسمح للعملاء العائدين بتخطي مفاوضة TLS الكاملة عند إعادة الاتصال. إنها إضافة صغيرة، لكنها تتراكم مع إعادة استخدام الاتصال لتقليص عدة مللي ثوانٍ إضافية. إذا لم تراجع إعداد SSL الخاص بك منذ فترة، فإن نظرة عامة على إدارة شهادات SSL لدينا مكان جيد لفحص إعدادك الحالي.
قياس الفرق
لا داعي للتخمين إن كانت Keep-Alive تعمل أم لا. إليك بعض طرق التحقق:
- افتح تبويب Network في متصفحك وانظر إلى عمود "Connection ID"، الطلبات التي تشترك في نفس المعرف تعيد استخدام نفس الاتصال.
- استخدم curl -v وابحث عن رأس "Connection" في الاستجابة.
- شغّل اختبار waterfall في WebPageTest وتحقق من تكرار مراحل DNS/connect/SSL على طلبات لنفس المضيف، وهو ما يشير إلى أن الاتصالات لا يُعاد استخدامها.
للحصول على نظرة أوسع على الأدوات التي تكشف هذا النوع من التفاصيل، راجع كيفية قياس وقت تحميل الصفحة بأدوات تخبرك بشيء مفيد فعلاً.
أين يأتي دور الاستضافة المُدارة
معظم هذا الأمر يعود إلى إعداد السيرفر، وليس كود التطبيق. وهذا بالضبط النوع من الأشياء التي يُساء إعدادها في السيرفرات ذاتية الإدارة وتكلفك الأداء بصمت لأشهر. على VPS مُدار، عادة ما تتم معالجة هذا النوع من الضبط كجزء من إعداد السيرفر الأساسي، لذا لست بحاجة للبحث في إعدادات Nginx بنفسك للحصول على قيم Keep-Alive افتراضية منطقية.
الخلاصة
اتصالات Keep-Alive هي واحدة من تلك التفاصيل الدقيقة التي لا تظهر مباشرة في نتيجة Lighthouse، لكنها تتراكم عبر كل طلب واحد تقوم به صفحتك. إذا كنت تحاول تقليل وقت استجابة السيرفر، تحقق من إعدادات Keep-Alive قبل أن تلجأ إلى أي شيء أكثر تعقيداً. تأكد من أن قيم المهلة والحد الأقصى للطلبات منطقية بالنسبة لنمط حركة المرور لديك، وتحقق من أن اتصالات الـ upstream دائمة أيضاً، واقرن ذلك بتخزين مؤقت مناسب لجلسات TLS. إنه تغيير بسيط في الإعداد لكن بتأثير كبير على أوقات التحميل الفعلية.