التخزين المؤقت والضغط
التخزين المؤقت والضغط
يمتلك مهندس DevOps أداتين بالغتي الأثر داخل Nginx: التخزين المؤقت للوكيل وضغط الاستجابات. تعمل الأداتان معًا على التخلص من الطلبات المتكررة إلى الخادم الأصلي وتقليص البيانات المنقولة عبر الشبكة. على نطاق شركات التقنية الكبرى — حيث قد تستقبل عقدة Nginx واحدة خمسين ألف طلب في الثانية — لا تُعدّ هذه الأدوات رفاهية، بل هي الفارق بين خادم يتحمل الأحمال بيسر وآخر ينهار عند أول موجة حركة مرور.
التخزين المؤقت للوكيل: كيف يخزن Nginx استجابات الخادم الأصلي
حين يقف Nginx أمام خادم أصلي (تطبيق Node.js، أو مجموعة PHP-FPM، أو تطبيق Rails، أو خدمة مصغرة)، يستطيع تخزين استجابة الخادم الأصلي على القرص أو في الذاكرة، ثم يعيد تقديم تلك النسخة المخزنة للعملاء التاليين دون أن يُلامس الخادم الأصلي البتة. هذا ما يُعرف بـالتخزين المؤقت للوكيل، ويُعدَّل عبر التوجيهَين proxy_cache_path وproxy_cache.
يُوضع إعلان التخزين داخل كتلة http {} لأنه مورد مشترك بين جميع كتل الخوادم. تُنشئ معامل levels هيكلًا ثنائي المستوى من الأدلة حتى لا يعاني نظام الملفات من ملايين الملفات في دليل واحد. يُخصص keys_zone قطاعًا من الذاكرة المشتركة يحمل الاسم المحدد لفهرس البيانات الوصفية للتخزين — لا لأجسام الاستجابات ذاتها. يحدّ max_size من استهلاك القرص وينشّط آلية الإخلاء الأقل استخدامًا عند الوصول إليه. أما inactive فتُنهي صلاحية الإدخالات التي لم يُطلب عليها أحد مؤخرًا.
HIT إصابة، MISS إخفاق، BYPASS تجاوز، EXPIRED منتهية الصلاحية، STALE قديمة، UPDATING قيد التحديث، REVALIDATED مُعاد التحقق منها، UNCACHEABLE غير قابلة للتخزين. راقب هذا الرأس في الإنتاج للتحقق من أن التخزين يعمل فعلًا قبل الاحتفال.مفاتيح التخزين: ما الذي يُشكّل إدخالًا فريدًا في التخزين
يبني Nginx مفتاح التخزين افتراضيًا من كامل URI مع سلسلة الاستعلام: $scheme$proxy_host$request_uri. وهذا صحيح لمعظم واجهات REST. أما نقاط النهاية المصادق عليها، فتنويع المفتاح ليشمل هوية المستخدم ضرورة — أو الأفضل تعطيل التخزين كليًا عليها. وإن كان المحتوى يتباين بين الهاتف والحاسوب، أدرج تصنيف User-Agent ضمن المفتاح.
إبطال التخزين
إبطال التخزين مسألة معروفة بصعوبتها. عمليًا، ثمة ثلاثة مناهج على مستوى Nginx: الأول، ترك الإدخالات تنتهي صلاحيتها وفق TTL المحدد في proxy_cache_valid — مناسب للمحتوى الذي يتغير وفق جدول معروف. الثاني، استخدام وحدة ngx_cache_purge (متضمنة في Nginx Plus التجاري، أو تُرفق بنسخة المصدر المفتوح) لإرسال طلب PURGE. الثالث، وسم الإدخالات بمعرّفات عبر رأس Surrogate-Key أو Cache-Tag وإبطالها دفعةً واحدة — نمط شائع في Cloudflare وFastly وبيئات Varnish.
للحالة الشائعة لنشر CI/CD: نفّذ طلب تنظيف من خط الأنابيب مباشرةً بعد بدء تشغيل الإصدار الجديد. لا تعتمد على انتهاء TTL حين تنشر تغييرًا جوهريًا.
ضغط Gzip
يُقلل الضغط حجم جسم الاستجابة قبل مغادرتها Nginx، مستبدلًا قدرًا بسيطًا من المعالج بعرض نطاق ترددي أقل وزمن تحميل مُتصوَّر أسرع. للحمولات النصية (HTML، JSON، CSS، JS) يمكن توقع انخفاض بنسبة 60–80% في الحجم. وحدة gzip المدمجة في Nginx مفعّلة افتراضيًا في معظم التوزيعات.
gzip_types.ضغط Brotli
حقق Brotli (جوجل، 2015) نسب ضغط أفضل بـ15–25% مقارنةً بـgzip بتكلفة معالجة مماثلة للمحتوى النصي. وتدعمه جميع المتصفحات الرئيسية منذ عام 2017. على جانب Nginx، تحتاج وحدة ngx_brotli التي لا تُجمَّع ضمن الحزمة الافتراضية في معظم التوزيعات. على Ubuntu/Debian يمكنك تثبيت libnginx-mod-brotli أو البناء من المصدر. أما في بيئات Cloudflare، فيُطبَّق ضغط Brotli تلقائيًا على حافة CDN.
brotli --best (أو CompressionPlugin في Webpack) أثناء CI ينتج ملفات .br و.gz بجانب الملفات الأصلية. مع تفعيل gzip_static on وbrotli_static on، يقدم Nginx هذه الملفات المضغوطة مسبقًا دون أي عمل للمعالج — مما يُخفف استهلاك المعالج على الحافة بشكل جذري عند أحمال المرور العالية. هذا ممارسة معيارية في شركات كـShopify وGitHub لخطوط أنابيب أصولهم الثابتة.الجمع بين التخزين المؤقت والضغط
حين يكون كلاهما مفعَّلَين، يضغط Nginx الاستجابة بعد استردادها من الخادم الأصلي وقبل كتابتها في التخزين، لكن فقط إن كان العميل يقبل الترميز. يعني هذا أن النسخة المخزنة مضغوطة بالفعل — واستجابات الإصابة التالية تُقدَّم دون أي عمل للمعالج. تحقق من ذلك بـcurl -H "Accept-Encoding: gzip" -I https://api.example.com/endpoint وراقب رأسَي Content-Encoding وX-Cache-Status معًا.
X-Cache-Status: HIT في رؤوس الاستجابة. (2) تأكد من Content-Encoding: br أو gzip. (3) تأكد من نجاح nginx -t قبل إعادة التحميل. (4) راقب /var/log/nginx/error.log بحثًا عن أخطاء أذونات التخزين — يجب أن يمتلك مستخدم العامل دليل التخزين. (5) اضبط proxy_cache_bypass $cookie_session لأي نقاط نهاية جلسة مصادَق عليها لمنع تلوث بيانات المستخدمين.