سرعة الموقع

ما هو التخزين المؤقت وأنواعه

التخزين المؤقت هو حفظ نتيجة عمل ما كي لا يُعاد العمل نفسه في المرة التالية. على هذا الموقع تستغرق الصفحة نفسها، وبعدد البايتات نفسه تقريبا، ٢٣.٥ مللي ثانية من الكاش و١٥٥.٥ مللي ثانية بدونه حتى يصل أول بايت منها.

  • الدرس 6 من 10
  • مبتدئ
  • مجاني، دون تسجيل

يمر الطلب بهذه الطبقات وأول جواب يجده هو الفائز

من الأعلى، الأقرب إلى الزائر. وكلما نزلت صار الجواب أغلى.

  • كاش المتصفحعلى جهاز الزائر نفسه؛ ولا يُرسل أي طلب أصلا سنة
  • حافة شبكة التوزيعخارج خادمك؛ ولا يبلغها مسح الخادم ثلاثون يوما
  • كاش الصفحةHTML جاهز على القرص؛ وحين يوجد لا يعمل PHP ملف واحد
  • كاش الكائناتأجوبة الأسئلة داخل الكود؛ الكاش الوحيد الذي يعمل للمستخدم المسجل في الذاكرة
  • الكود وقاعدة البياناتالقاع؛ هنا تُبنى الصفحة فعلا وتدفع ثمنها بلا كاش

هذا الترتيب لزائر ضيف. أما المستخدم المسجل فيتجاوز الطبقات الثلاث العليا ويصل مباشرة إلى الطبقتين السفليين.

آخر مراجعة: تُراجع الحقائق وأسماء الأدوات في هذا الدرس مقابل مصادرها في هذا التاريخ.

ما الذي يخزنه الكاش فعلا؟

الكاش يحفظ نتيجة عمل منجز كي لا يُعاد العمل في المرة التالية. هذا التعريف أبسط مما يبدو، وله نتيجة واحدة تمر عليها أكثر الدروس: الكاش لا يجعل صفحتك أخف، بل يجعلها تصل أسرع.

أخذنا رقم هذا الادعاء من هذا الموقع نفسه. طلبنا الصفحة الأولى عشر مرات من نسختها المخزنة وعشر مرات بمعامل يكسر الكاش، في كل مرة والضغط مفعّل، وسجلنا لحظة وصول أول بايت. من الكاش كان الوسيط ٢٣.٥ مللي ثانية، وأدنى وأعلى قيمة ٢٢ و٣٧. وبلا كاش كان الوسيط ١٥٥.٥ مللي ثانية ضمن مدى ١٣٤ إلى ١٨٢.

والآن حجم هاتين الاستجابتين نفسيهما: ٤٣.٨ كيلوبايت للنسخة المخزنة و٤٣.١ كيلوبايت للنسخة التي بُنيت في اللحظة. فالنسخة البطيئة بالحجم نفسه تقريبا، بل هي أصغر قليلا. وكل ذلك الفارق المضاعف ست مرات زمن لا بايتات.

فحين يقال إن الكاش يجعل الموقع سريعا، فالعبارة الأصح هي: الكاش يزيل العمل الذي كان الخادم يؤديه لبناء الصفحة. وذلك العمل هو تشغيل الكود وسؤال قاعدة البيانات وتركيب القالب وإنتاج HTML. والناتج ملف يُرسل مباشرة في المرة التالية.

وفي الجملة نفسها يظهر حد الكاش، وهو مهم لاحقا: إن كانت صفحتك بطيئة لأنها تحمل ثلاثة ميغابايت من الصور، فالكاش لا يعين في شيء منها. الكاش يشتري زمن البناء لا زمن التنزيل.

ما التخزين المؤقت؟ الطبقات الأربع التي تمر بها الصفحة

الصفحة نفسها، بكاش وبلا كاش

وسيط عشرة طلبات لكل حالة، من هذا الخادم، ٨ سبتمبر ٢٠٢٦
  1. بُنيت الصفحة في اللحظة ١٥٥.٥ مللي ثانية المدى ١٣٤ إلى ١٨٢
  2. أتت الصفحة من الكاش ٢٣.٥ مللي ثانية المدى ٢٢ إلى ٣٧

طبقة الحافة غائبة عن هذا الرسم عمدا: فقياسها من جهاز يجاور الخادم يعطي رقما مضللا، لأن الحافة للزائر الحقيقي أقرب من الخادم وهي هنا أبعد.

الطبقات الأربع التي يمر بها الطلب

حين يفتح أحدهم عنوان موقعك، يمر طلبه بعدة طبقات كاش، وأول طبقة تملك جوابا تنهي الرحلة. والترتيب يبدأ من الأقرب إلى الزائر.

كاش المتصفح على جهاز الزائر نفسه. تبقى فيه الملفات التي لا تتغير، ولا يُرسل في المرة التالية أي طلب أصلا. على هذا الموقع تخرج الخطوط والسكربتات وأوراق الأنماط بترويسة Cache-Control: max-age=31536000، أي سنة كاملة. والخط الأساسي ٢٥٢٧٢ بايت، والزائر الذي جاء الأسبوع الماضي يدفع اليوم صفر بايت مقابله. وهذه أسرع طبقة لأن لا شبكة فيها.

حافة شبكة توزيع المحتوى خارج خادمك وتحفظ نسخة من الصفحة قرب الزائر. لهذه الطبقة درسها الخاص في مسار الانترنت والشبكات؛ وما يلزمك هنا أن الحافة تُوجَّه عادة بترويسة منفصلة، لا بالترويسة التي ترسلها للمتصفح.

كاش الصفحة على خادمك أنت ويحفظ HTML المنجز في ملف. وعلى هذا الموقع هذه الملفات ملفات حقا: صفحة «من نحن» ملف مضغوط حجمه ٣٦٣٣٠ بايت، وكاش الصفحات كله ١٩٨٠ ملفا و١١٢ ميغابايت. وحين يوجد الملف يرسله خادم الويب بنفسه ولا يعمل PHP أصلا، وهذا ما يصنع زمن ٢٣.٥ مللي ثانية.

كاش الكائنات في قاع الطبقات ويختلف عن سائرها: لا يحفظ صفحات بل يحفظ أجوبة الأسئلة التي تُطرح داخل الكود. وعلى هذا الموقع يقوم بذلك Redis ٧.٤.٧. وتظهر قيمته حين تُتجاوز الطبقات الثلاث فوقه، كما لمستخدم مسجل الدخول لا يتلقى صفحة مخزنة أبدا. فهو بالنسبة إليه الكاش الوحيد الذي ما زال يعمل.

وتحت هذه الطبقات الأربع لا كاش البتة: يعمل الكود وتجيب قاعدة البيانات. وكلما لم تملك أي طبقة جوابا كانت الفاتورة ١٥٥.٥ مللي ثانية نفسها.

كاش الصفحة وكاش الكائنات، عملان مختلفان

كاش الصفحة

  • يحفظ كل HTML الجاهز في ملف واحد
  • وحين يجيب لا يعمل PHP أصلا
  • للزائر الضيف؛ ومطفأ عادة للمستخدم المسجل

كاش الكائنات

  • يحفظ أجوبة الأسئلة داخل الكود في الذاكرة
  • يعمل PHP لكنه يسأل قاعدة البيانات أقل
  • الطبقة الوحيدة الباقية للوحة الإدارة والمستخدم المسجل

ولا واحد منهما يغني عن الآخر. فموقع لا يملك إلا الأول لوحته بطيئة، وموقع لا يملك إلا الثاني صفحاته العامة بطيئة.

لماذا لم يصل تغييرك إلى الزائر بعد؟

هذا أكثر أسئلة الكاش يومية، وجوابه واحد في الغالب: طبقة أمام التي مسحتها ما زالت تحمل النسخة القديمة.

وأول ما ينبغي رؤيته أن استجابة واحدة قد تحمل أمرَي كاش مختلفين، أحدهما للمتصفح والآخر للحافة. وصفحات هذا الموقع تصل بهاتين الترويستين:

cache-control: no-cache, must-revalidate
cdn-cache-control: max-age=2592000

أي إننا نقول للمتصفح: اسأل في كل مرة، ونقول للحافة: احتفظ بها ثلاثين يوما. وهذا مقصود وشائع، لكن معناه يجب أن يصل: مسح الكاش على خادمك أنت لا يمس تلك الثلاثين يوما. تعيد بناء الصفحة على الخادم وتحسب أنك انتهيت، والزائر ما زال يرى ما تحمله الحافة. والوصول إلى الحافة يعني أن تطلب المسح من خدمة الحافة نفسها، وذلك فعل منفصل.

والفخ الثاني أصغر ويكلف وقتا أكثر، لأنه يبدو كأن المسح فشل. فكي لا يذهب خادم الويب إلى القرص في كل طلب، يحتفظ بنتيجة بحثه عن الملفات مدة قصيرة؛ وعلى هذا الخادم تلك المدة ستون ثانية بضبط open_file_cache_valid. فتمسح ملف الكاش وتجلب الصفحة فورا، فتأتي الصفحة القديمة. لم يتعطل شيء. انتظر انقضاء الدقيقة ثم أعد الجلب.

وحالة ثالثة يُفكَّر فيها أقل: الزائر نفسه. إن أرسلت ملفا بعمر سنة ثم غيّرت محتواه، فمتصفح من جاء قبلا لن يعلم أبدا. والصواب ليس تغيير محتوى الملف بل تغيير اسمه أو نسخته في العنوان، فيكون العنوان الجديد ملفا جديدا.

ما الذي يجب ألا يُخزَّن؟

جملة واحدة تمنع كل كوارث الكاش الجدية: خزّن الصفحة لا الشخص. فكل ما يختلف جوابه بين شخصين يجب ألا يُحفظ في ملف يُسلَّم إليهما معا.

والأمثلة هي هي دائما: سلة الشراء، صفحة الحساب، وكل صفحة يُطبع عليها اسم المستخدم، والنماذج قيد التعبئة، وصفحات نتيجة الدفع. وأسوأ صور الفشل هي بالضبط ما يخشاه الجميع: يرى المستخدم الأول سلته، فتُخزَّن، فيرى المستخدم الثاني سلة الأول.

ولهذا لا يعمل كاش الصفحة عادة للمستخدم المسجل أصلا، وهذا قرار تصميم لا عيب. لكن عليك قبول ما يترتب عليه: لوحة إدارتك أبطأ دائما من صفحات الموقع العامة، لأنها تُبنى فعلا في كل مرة. وهنا بالذات يصير كاش الكائنات الأداة الوحيدة الباقية.

وثمة حالة حدية قرارها لك: صفحات واحدة للجميع لكنها تتقادم سريعا، كصفحة تعرض المخزون. يمكن تخزينها بشرط أن يكون العمر قصيرا وأن تعرف ما أسوأ الاحتمالات. فإن كان أسوأها أن يطلب أحدهم شيئا نفد، فعمرك يجب أن يكون قصيرا جدا أو يجب أن يبقى ذلك الجزء خارج الكاش.

ورقة الكاشقبل التشغيل

خزّن هذه

  • الصفحات الواحدة للجميع: المقالات وصفحات الخدمات وصفحات المنتجات
  • الملفات التي لا تتغير: الخطوط والصور وأوراق الأنماط والسكربتات ذات النسخة
  • الصفحات التي تتقادم لكنها واحدة للجميع، بعمر قصير

لا تخزّن هذه أبدا

  • السلة والدفع وصفحة نتيجة الدفع
  • كل صفحة يُطبع عليها اسم مستخدم أو بياناته
  • لوحة الإدارة وكل مسار لا يُرى إلا بعد الدخول
  • استجابات النماذج وكل ما يتغير بطلب واحد

مسح الكاش ليس مجانيا

زر «امسح كل الكاش» أبسط أزرار أي إضافة كاش، وأغلى ما يمكن أن تفعله بالكاش. ونتخذ هنا موقفا لأننا دفعنا ثمنه.

حين تمسح الكاش كله، يجب إعادة بناء كل صفحة أُسقطت. وإن كانت إضافتك تسخّن الصفحات مسبقا بعد المسح، بدأت إعادة البناء فورا لا حين يصل زائر. وعلى موقع فيه ١٩٨٠ صفحة مخزنة يعني ذلك قرابة ألفي تشغيل كامل لمحرك PHP متتاليا. ومع ذلك الوسيط البالغ ١٥٥.٥ مللي ثانية، اضرب الرقم بنفسك، وتذكر أن هذا يجري على خادم يجيب في اللحظة نفسها زوارا حقيقيين.

والقاعدة التي نعمل بها بسيطة: امسح الصفحات التي تغيرت فعلا فقط. فإن حررت نص صفحة واحدة فذلك عنوان واحد. وإن كان الموقع متعدد اللغات فكل لغة عنوان مستقل ويُحسب مستقلا. والمسح الشامل لا يُبرَّر إلا حين يتغير شيء موجود حقا في كل الصفحات، كالترويسة أو ورقة أنماط عامة، وحتى حينها موضعه ساعة هادئة.

وترتيب العمل، وهو يبدو بديهيا ويُعكس غالبا: تحقق من التغيير أولا على النسخة غير المخزنة واطمئن إلى صحته، ثم امسح. وإن عكست، صار كل حفظ مسحا جديدا وأُعيد بناء الصفحة نفسها خمس مرات.

المسار السريع مع الذكاء الاصطناعي

الطريقة المعتادة حين لا يصل تغيير إلى الموقع أن تمسح كل شيء واحدا واحدا حتى يستقيم أخيرا. وهي تنفع وهي مكلفة في كل مرة. أما المسار السريع فأن تسأل أولا أي طبقة أجابت، وترويسات الاستجابة تقول ذلك. والنموذج اللغوي يجيد هذا، لأن العمل قراءة نص منظم وربط بضعة أسطر ببعضها. والذي يفصل هذا عن سؤال عادي: خذ الترويسات من عنوانين، العنوان نفسه والعنوان نفسه مع معامل بلا معنى، وسلّمهما معا. فالفرق بينهما هو التشخيص ذاته.

  1. خذ ترويسات الحالتين: مرة العنوان نفسه، ومرة العنوان نفسه مع معامل عشوائي مثل ?cb=12345 لم يره أي كاش قط.
  2. سلّم الاثنتين معا إلى النموذج واسأله أي طبقة أجابت وأي ترويسة تدل على ذلك. وإغفال الحالة الثانية هو الخطأ الذي يجعل الجواب بلا فائدة.
  3. اطلب منه أن يسمي الطبقة المسؤولة وحدها ويقترح أصغر عمل لازم، وقل صراحة ألا يقترح مسحا شاملا.
  4. نفّذ العمل المقترح وانتظر دقيقة ثم خذ الترويسات ثانية. والانتظار ليس اختياريا: فنافذة الستين ثانية في خادم الويب هي ما يجعل العمل الصحيح يبدو فاشلا.

وصفة جاهزة للنسخ

هذه ترويسات استجابة صفحة من موقعي، في حالتين.

الحالة A، العنوان العادي:
{الصق الترويسات كاملة هنا}

الحالة B، العنوان نفسه مع معامل عشوائي لم يره أي كاش:
{الصق الترويسات كاملة هنا}

أريد أن أعرف لماذا لا يظهر بعد تغيير أجريته على الخادم.

القواعد:
١. استنتج من هذه الترويسات وحدها. وإن غابت ترويسة تحتاجها فقل أيها المطلوبة، ولا تخمّن.
٢. قل أي طبقة أجابت في الحالة A: المتصفح أم الحافة أم كاش الصفحة أم الكود. وقل أي سطر يدل على ذلك.
٣. إن اختلف محتوى الحالتين A وB فقل ماذا يعني ذلك.
٤. سمِّ طبقة مسؤولة واحدة لا عدة طبقات.
٥. اقترح أصغر عمل لازم. ولا تقترح مسحا شاملا ولا مسح كل الكاش.
٦. لا تذكر اسم أي ضبط غائب عن هذه الترويسات.

أجب في أربعة أسطر: الطبقة التي أجابت، والسبب، والعمل المقترح، وما ينبغي أن يكون قد تغير بعده.

قبل أن تثق بالناتج: يقرأ النموذج الترويسات جيدا ويخمّن الإعدادات سيئا. اسأله بلا ترويسات لماذا لا يتحدث موقعي، فيكتب بثقة تامة أسماء خيارات لا وجود لها في لوحتك، فتقضي نصف ساعة تبحث عنها. ولهذا وُضعت القاعدة السادسة أعلاه. وعمل واحد لا يُوكل إلى النموذج أبدا: قرار المسح الشامل. فذاك قرار تشغيلي يتوقف على عدد صفحاتك وعلى ساعة اليوم، والنموذج لا يعرف أيا منهما.

الذكاء الاصطناعي في هذا العمل

الكاش موضع يجيد فيه الذكاء الاصطناعي عملا ويخطر في آخر. يجيد قراءة الترويسات وشرح توجيه وترجمة رسالة خطأ إلى لغة البشر. ويخطر في اقتراح الإعدادات، لأن إعدادات كل إضافة كاش تختلف ولا سبيل للنموذج إلى رؤية لوحتك. وموقفنا: استعمل النموذج للتشخيص لا للضبط.

أدوات تساعد فعلا

  • Claude مناسب للعمل التشخيصي أعلاه: يقرأ نصا منظما ويجد الروابط بين بضعة أسطر، ويلتزم بالقواعد إن وضعتها. وإيران ليست في قائمة الدول المدعومة لدى Anthropic، فلا تسجيل رسمي ولا قبول لبطاقة إيرانية.
  • Gemini جيد حين تريد فهم مصطلح أو توجيه بسرعة، كالفرق بين no-cache وno-store. وتقول صفحة غوغل نفسها إن تطبيق Gemini على الويب يعمل في أكثر من ٢٣٠ دولة وإقليما، وإيران ليست في تلك القائمة.
  • ChatGPT يكفي لقراءة الترويسات نفسها وشرحها. ولا ندّعي شيئا عن الوصول من إيران، لأن صفحة الدول المدعومة لدى OpenAI، كسائر ذلك النطاق، تعيد ٤٠٣ لهذا الخادم.

اين ينقلب ضدك

الخطر الأساسي هنا الأسماء المخترعة، وله شكل يستحق أن يُعرف. فقد رأى النموذج نمط ترويسات الكاش وتوجيهاته، فيستطيع كتابة ترويسة لا وجود لها، أو اسم خيار في لوحة إضافة لم يكن فيها خيار كهذا قط. ولأن جوابه يشبه الجواب الصحيح يصعب كشفه. والاختبار البسيط هو: كل اسم كتبه النموذج ولا تراه في ترويساتك الحقيقية ولا في شاشة إعداداتك فهو غير موجود حتى يثبت العكس. والخطر الثاني تشغيلي: اسأل أي نموذج تقريبا لماذا لا يظهر تغييري، فسيقترح في مكان ما من جوابه مسح الكاش كله. وهذا غير ضار على موقع صغير ومكلف على موقع فيه آلاف الصفحات، والنموذج لا يعلم أي الموقعين موقعك.

المصادر: MDN: Cache-Control Anthropic: supported countries Google: where Gemini Apps are available

حدود هذه النصيحة

هذا الدرس عن تخزين صفحات موقع عادي، وله ثلاثة حدود جديرة بالمعرفة. الأول أن الكاش داخل الكود نفسه، حيث يحفظ المبرمج نتيجة حساب ثقيل في الذاكرة، موضوع آخر لم نتناوله هنا. والثاني أن أرقام هذه الصفحة من خادم في أوروبا بقرص دافئ؛ فالنسب تُعمَّم على موقعك، أما الأرقام فلا، والرقم الوحيد الجدير بالثقة ما قسته أنت على موقعك أنت. والثالث وهو أهم منهما: إن كان موقعك يبني فعلا صفحة مختلفة لكل زائر، كلوحة معلومات أو شبكة اجتماعية، فكاش الصفحة ليس أداتك الصحيحة وجوابك أخفض في الطبقات.

من عملنا نحن

أغلى ساعة أنفقناها على الكاش ذهبت في مطاردة خلل لم يكن خللا. مسحنا ملف الكاش لصفحة واحدة وجلبنا الصفحة فورا، فأتت النسخة القديمة. مسحنا ثانية، والنتيجة نفسها. فرحنا نبحث عمّا يعيد الملف. وكان الجواب أن خادم الويب، كي لا يذهب إلى القرص في كل طلب، يحتفظ بنتيجة بحثه عن الملفات ستين ثانية، وكنا نعيد الاختبار داخل نافذة الستين ثانية نفسها في كل مرة. لم يكن شيء معطلا؛ نحن لم ننتظر. وصارت تلك قاعدة ثابتة عندنا: بعد مسح صفحة واحدة ننتظر دقيقة ثم نتحقق، وإن بدا شيء خاطئا فور المسح نظرنا إلى الساعة قبل أن ننظر إلى الكود.

اسئلة متابعة حقيقية

كم إضافة كاش أحتاج؟

واحدة. فإضافتا كاش صفحة على موقع واحد تتنازعان، والنتيجة صفحات تتحدث أحيانا ولا تتحدث أحيانا، ويكاد يستحيل تحديد المسؤول. أما كاش الكائنات فإضافة منفصلة ولا تتعارض مع كاش الصفحة؛ وتلك يمكن تشغيلها معا.

إن كانت لدي شبكة توزيع، أأحتاج كاش صفحة أيضا؟

نعم، لأن كلا منهما يسد ثغرة مختلفة. فالحافة لا تحمل إلا صفحات طلبها أحد من قبل ولم ينته عمرها؛ وأي عنوان جديد أو سقط من الحافة يصل طلبه إلى خادمك، وهناك يقرر كاش الصفحة أيعمل PHP أم لا. والموقع الذي لا يملك إلا حافة يذوق البطء كاملا كلما خلت الحافة.

أي عمر أضبط للكاش؟

قرّر بسؤال لا برقم افتراضي: لو كانت هذه الصفحة عمرها ساعة، فما الذي يسوء؟ للمقال الجواب لا شيء، فاجعل العمر طويلا. ولصفحة تعرض سعرا أو مخزونا الجواب شكوى عميل، فإما أن تقصّر العمر جدا وإما أن تبقي ذلك الجزء خارج الكاش. والملفات التي في أسمائها نسخة استثناء ويمكنها البقاء سنة، لأن تغييرها يعني اسما جديدا.