CDN والتخزين المؤقت الطرفي
CDN والتخزين المؤقت الطرفي
تخزن شبكات توصيل المحتوى (CDN) المحتوى في مواقع طرفية حول العالم، لخدمة المستخدمين من أقرب خادم. هذا يقلل بشكل كبير من زمن الوصول ويحسن أوقات تحميل الصفحة عالميًا.
ما هي شبكة CDN؟
CDN هي شبكة موزعة من الخوادم التي تخزن وتقدم المحتوى من مواقع أقرب جغرافيًا للمستخدمين. بدلاً من أن يسافر كل طلب إلى خادم المنشأ الخاص بك، تقدم CDN المحتوى المخزن مؤقتًا من خوادم الحافة.
كيف تعمل شبكات CDN
عندما يطلب مستخدم محتوى، يفحص خادم حافة CDN ذاكرته المؤقتة. إذا كان المحتوى موجودًا وحديثًا، يتم تقديمه على الفور. إذا لم يكن كذلك، تجلب CDN من المنشأ وتخزنه مؤقتًا وتقدمه.
تدفق طلب المستخدم:\n1. يطلب المستخدم https://cdn.example.com/logo.png\n2. يحل DNS إلى أقرب خادم حافة CDN\n3. يفحص خادم الحافة الذاكرة المؤقتة\n4. إذا كان مخزنًا مؤقتًا: تقديم فوري (نجاح الذاكرة المؤقتة)\n5. إذا لم يكن مخزنًا مؤقتًا: جلب من المنشأ، التخزين المؤقت، التقديم (فشل الذاكرة المؤقتة)\n6. الطلبات اللاحقة: تقديم من الذاكرة المؤقتة
موفرو CDN الشائعون
يقدم موفرو CDN الرئيسيون شبكات حافة عالمية بميزات ونماذج تسعير مختلفة.
إعداد Cloudflare CDN
يوفر Cloudflare خدمات CDN مجانية مع تخزين مؤقت تلقائي للأصول الثابتة.
// يخزن Cloudflare تلقائيًا:\n// - الصور (.jpg, .png, .gif, .webp)\n// - ملفات CSS و JavaScript\n// - الخطوط (.woff, .woff2, .ttf)\n// - ملفات الفيديو والصوت\n\n// قواعد التخزين المؤقت المخصصة عبر قواعد الصفحة:\n// مستوى الذاكرة المؤقتة: قياسي، قوي، أو تجاوز\n// TTL الذاكرة المؤقتة الطرفية: تجاوز رؤوس الذاكرة المؤقتة للمنشأ\n// TTL ذاكرة المتصفح المؤقتة: التحكم في التخزين المؤقت من جانب العميل\n\n// مثال على قاعدة الصفحة:\n// URL: *.example.com/assets/*\n// الإعدادات:\n// مستوى الذاكرة المؤقتة: تخزين كل شيء مؤقتًا\n// TTL الذاكرة المؤقتة الطرفية: شهر واحد\n// TTL ذاكرة المتصفح المؤقتة: 4 ساعات
إعداد AWS CloudFront
يتكامل CloudFront مع خدمات AWS ويوفر عناصر تحكم تخزين مؤقت متقدمة.
// تكوين توزيع CloudFront\n{\n "Origins": [{\n "DomainName": "origin.example.com",\n "Id": "myOrigin"\n }],\n "DefaultCacheBehavior": {\n "TargetOriginId": "myOrigin",\n "ViewerProtocolPolicy": "redirect-to-https",\n "AllowedMethods": ["GET", "HEAD", "OPTIONS"],\n "CachedMethods": ["GET", "HEAD"],\n "ForwardedValues": {\n "QueryString": false,\n "Cookies": { "Forward": "none" }\n },\n "MinTTL": 0,\n "DefaultTTL": 86400, // يوم واحد\n "MaxTTL": 31536000 // سنة واحدة\n }\n}رؤوس الذاكرة المؤقتة لـ CDN
تتحكم رؤوس الذاكرة المؤقتة HTTP في كيفية تخزين شبكات CDN والمتصفحات للمحتوى مؤقتًا. حدد الرؤوس المناسبة على خادم المنشأ الخاص بك.
// رؤوس الذاكرة المؤقتة في Express.js\napp.use('/assets', (req, res, next) => {\n // تخزين الأصول الثابتة مؤقتًا لمدة سنة\n res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');\n next();\n});\n\napp.use('/api', (req, res, next) => {\n // عدم تخزين استجابات API مؤقتًا\n res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');\n next();\n});\n\n// رأس Vary للتفاوض على المحتوى\nres.setHeader('Vary', 'Accept-Encoding, Accept-Language');\n\n// ETag للتحقق\nres.setHeader('ETag', generateETag(content));توجيهات Cache-Control
فهم توجيهات Cache-Control أمر بالغ الأهمية للتخزين المؤقت الصحيح لـ CDN.
// توجيهات Cache-Control:\n\n// public - يمكن تخزينه مؤقتًا بواسطة CDN والمتصفحات\nCache-Control: public, max-age=3600\n\n// private - ذاكرة المتصفح المؤقتة فقط، وليس CDN\nCache-Control: private, max-age=3600\n\n// no-cache - يجب إعادة التحقق قبل التقديم\nCache-Control: no-cache\n\n// no-store - عدم التخزين المؤقت أبدًا (بيانات حساسة)\nCache-Control: no-store\n\n// immutable - المحتوى لا يتغير أبدًا (أصول ذات إصدارات)\nCache-Control: public, max-age=31536000, immutable\n\n// s-maxage - CDN cache TTL (يتجاوز max-age لـ CDN)\nCache-Control: public, max-age=3600, s-maxage=86400
حماية المنشأ
تضيف حماية المنشأ طبقة تخزين مؤقت إضافية بين خوادم الحافة والمنشأ لتقليل حمل المنشأ.
// بدون حماية المنشأ:\nخادم الحافة 1 (فشل الذاكرة المؤقتة) → المنشأ\nخادم الحافة 2 (فشل الذاكرة المؤقتة) → المنشأ\nخادم الحافة 3 (فشل الذاكرة المؤقتة) → المنشأ\n// 3 طلبات للمنشأ لنفس المحتوى\n\n// مع حماية المنشأ:\nخادم الحافة 1 (فشل الذاكرة المؤقتة) → خادم الحماية (فشل الذاكرة المؤقتة) → المنشأ\nخادم الحافة 2 (فشل الذاكرة المؤقتة) → خادم الحماية (نجاح الذاكرة المؤقتة)\nخادم الحافة 3 (فشل الذاكرة المؤقتة) → خادم الحماية (نجاح الذاكرة المؤقتة)\n// طلب واحد فقط للمنشأ\n\n// تكوين حماية منشأ CloudFront:\n{\n "OriginShield": {\n "Enabled": true,\n "OriginShieldRegion": "us-east-1"\n }\n}مسح ذاكرة CDN المؤقتة
أبطل المحتوى المخزن مؤقتًا عندما تنشر التحديثات أو تحتاج إلى إزالة البيانات القديمة.
// مسح Cloudflare API\nconst cloudflare = require('cloudflare')({\n token: 'your-api-token'\n});\n\n// مسح ملفات محددة\nawait cloudflare.zones.purgeCache(zoneId, {\n files: [\n 'https://example.com/style.css',\n 'https://example.com/app.js'\n ]\n});\n\n// المسح حسب علامة الذاكرة المؤقتة\nawait cloudflare.zones.purgeCache(zoneId, {\n tags: ['product-images']\n});\n\n// مسح كل شيء (استخدم بحذر!)\nawait cloudflare.zones.purgeCache(zoneId, {\n purge_everything: true\n});// إبطال AWS CloudFront\nconst AWS = require('aws-sdk');\nconst cloudfront = new AWS.CloudFront();\n\nconst params = {\n DistributionId: 'E1234567890ABC',\n InvalidationBatch: {\n CallerReference: Date.now().toString(),\n Paths: {\n Quantity: 2,\n Items: [\n '/assets/style.css',\n '/assets/app.js'\n ]\n }\n }\n};\n\nawait cloudfront.createInvalidation(params).promise();التخزين المؤقت الثابت مقابل الديناميكي
تتطلب أنواع المحتوى المختلفة استراتيجيات تخزين مؤقت مختلفة.
// المحتوى الثابت (الصور، CSS، JS):\n// - أوقات تخزين مؤقت طويلة (شهر إلى سنة)\n// - استخدم أسماء ملفات ذات إصدارات (app.v123.js)\n// - Cache-Control: public, max-age=31536000, immutable\napp.use('/static', express.static('public', {\n maxAge: '1y',\n immutable: true\n}));\n\n// المحتوى الديناميكي (صفحات HTML):\n// - أوقات تخزين مؤقت قصيرة (5 دقائق إلى ساعة)\n// - استخدم ETag للتحقق\n// - Cache-Control: public, max-age=300, must-revalidate\napp.get('/blog/:slug', async (req, res) => {\n const post = await getPost(req.params.slug);\n const etag = generateETag(post);\n \n if (req.get('If-None-Match') === etag) {\n return res.status(304).end();\n }\n \n res.set({\n 'Cache-Control': 'public, max-age=300, must-revalidate',\n 'ETag': etag\n });\n res.render('post', { post });\n});الحوسبة الطرفية مع Cloudflare Workers
شغّل التعليمات البرمجية في الحافة لتخصيص سلوك التخزين المؤقت وتوصيل المحتوى.
// مثال على Cloudflare Worker\naddEventListener('fetch', event => {\n event.respondWith(handleRequest(event.request));\n});\n\nasync function handleRequest(request) {\n const url = new URL(request.url);\n \n // منطق تخزين مؤقت مخصص\n if (url.pathname.startsWith('/api/')) {\n // عدم تخزين API مؤقتًا\n return fetch(request);\n }\n \n // فحص الذاكرة المؤقتة\n const cache = caches.default;\n let response = await cache.match(request);\n \n if (!response) {\n // جلب من المنشأ\n response = await fetch(request);\n \n // التخزين المؤقت لمدة ساعة\n const headers = new Headers(response.headers);\n headers.set('Cache-Control', 'public, max-age=3600');\n \n response = new Response(response.body, {\n status: response.status,\n headers\n });\n \n event.waitUntil(cache.put(request, response.clone()));\n }\n \n return response;\n}مراقبة أداء CDN
تتبع معدلات نجاح الذاكرة المؤقتة، واستخدام النطاق الترددي، ومقاييس الأداء.
// مقاييس CDN الرئيسية:\n\n// معدل نجاح الذاكرة المؤقتة: (نجاحات الذاكرة المؤقتة / إجمالي الطلبات) * 100\n// الهدف: >90% للأصول الثابتة، >70% للمحتوى الديناميكي\n\n// معدل نجاح حماية المنشأ: نجاحات ذاكرة الحماية المؤقتة / طلبات الحماية\n// الهدف: >80%\n\n// النطاق الترددي المحفوظ: نطاق المنشأ الترددي مقابل النطاق الترددي الإجمالي\n// CDN جيد يجب أن يوفر 60-90% من النطاق الترددي\n\n// وقت الاستجابة P95: زمن الوصول للطلب في المئوية 95\n// الهدف: <100 مللي ثانية عالميًا\n\n// معدل فشل الذاكرة المؤقتة: عمليات البحث الفاشلة في الذاكرة المؤقتة\n// معدل فشل مرتفع يشير إلى مشاكل في التخزين المؤقت