التخزين الكائني وشبكات CDN
💡 دليل التعلم: ستأخذك هذه المقالة في رحلة كاملة — من رفع الملفات إلى تنزيل المستخدم لها. سترى كيف يعمل التخزين الكائني مثل "مستودع ذكي" لإدارة كميات هائلة من الملفات، وكيف تعمل CDN مثل "نقاط توزيع البريد السريع" لإيصال المحتوى إلى باب المستخدم، وما هي "العقبات" التي تنتظرك. يُنصح بفهم أساسيات طلبات HTTP ومبادئ تحليل DNS مسبقًا.
قبل البدء، يُنصح ببناء بعض "الأساسيات":
- عملية طلب HTTP: يمكنك قراءة ماذا يحدث بعد إدخال عنوان URL في المتصفح لفهم المسار الكامل للطلب.
- مبادئ تحليل DNS: إذا لم تكن معتادًا على تحليل أسماء النطاقات، يمكنك الاطلاع على الجزء التوضيحي في عملية استعلام DNS.
0. المقدمة: لماذا يكون رفع وتنزيل الملفات "بطيئًا" جدًا؟
تخيل هذا السيناريو: قمت برفع صورة عالية الدقة بحجم 10 ميجابايت في مجتمع للصور، وانتظرت نصف دقيقة حتى اكتمل الرفع؛ بينما صديقك في بكين ينقر للتنزيل ويستغرق ثانيتين فقط. لماذا تختلف تجربة الرفع والتنزيل لنفس الملف بهذا القدر الكبير؟
أو فكر مرة أخرى: موقع التجارة الإلكترونية الخاص بك يجري عرضًا ترويجيًا في يوم العزاب (11.11)، وفجأة تتدفق ملايين الزيارات إلى صفحة تفاصيل المنتج، فيتعطل الخادم مباشرة. هل المشكلة في عرض النطاق الترددي؟ أم أن هناك خطأ في تصميم البنية؟
إجابات هذه الأسئلة مخبأة في الثنائي الذهبي: التخزين الكائني و CDN.
1. التخزين الكائني: "مستودعك السحابي الذكي"
1.1 ما هو التخزين الكائني؟
نظام الملفات التقليدي يشبه خزانة ملابسك: الملابس مرتبة حسب "قمصان/بناطيل/تنانير" في طبقات، للعثور على قميص، يجب أن تفتح الخزانة → منطقة القمصان → رف القمصان. هذا النموذج "الهرمي المتداخل" يصبح بطيئًا للغاية عندما ينفجر عدد الملفات.
أما التخزين الكائني فهو مثل اللوجستيات الحديثة: كل طرد له "رقم تتبع" فريد (مفتاح الكائن)، يكفي إعطاء الرقم، ويقوم روبوت المستودع باستخراجه بدقة من بين آلاف الطرود.
مقارنة الفروقات الأساسية:
| البُعد | نظام الملفات التقليدي | التخزين الكائني |
|---|---|---|
| طريقة التنظيم | شجرة أدلة هرمية | أزواج مفتاح-قيمة مسطحة |
| بروتوكول الوصول | POSIX (عمليات الملفات المحلية) | HTTP/REST API |
| قابلية التوسع | سعة محدودة للجهاز الواحد | توسع أفقي غير محدود تقريبًا |
| البيانات الوصفية | خصائص أساسية (الحجم، الوقت) | بيانات وصفية مخصصة غنية |
| السيناريوهات النموذجية | مستندات المكتب المحلية | الصور/الفيديو/النسخ الاحتياطي/الموارد الثابتة |
1.2 المفاهيم الأساسية للتخزين الكائني
الحاوية (Bucket): "قسم المستودع" الخاص بك
الحاوية هي الحاوية العليا في التخزين الكائني، وتعادل مساحة اسم مستقلة. يجب تخزين جميع الكائنات داخل حاوية معينة.
قواعد التسمية (باستخدام Alibaba Cloud OSS كمثال):
- فريدة عالميًا: لا يمكن تكرارها بين جميع مستخدمي مزود السحابة بأكمله
- يمكن أن تحتوي فقط على أحرف صغيرة وأرقام وشرطات
- يجب أن تبدأ وتنتهي بحرف صغير أو رقم
- الطول بين 3-63 حرفًا
درس عملي: أنشأ أحد الفرق عشرات الحاويات بناءً على خطوط الأعمال، وعندما جاءت الفاتورة في نهاية الشهر اندهشوا — كل حاوية لها حد أدنى من رسوم التخزين والطلبات. نصيحة: خطط الحاويات بناءً على "البيئة + الغرض"، مثل prod-static-assets و dev-backup-archive.
الكائن (Object): "طرد البيانات" الخاص بك
الكائن هو الوحدة الأساسية للتخزين، ويتكون من ثلاثة أجزاء:
المفتاح (Key): المعرّف الفريد للكائن، يعادل "رقم التتبع"
- مثال:
images/avatar/2024/user123.jpg - على الرغم من أنه يبدو كمسار، إلا أنه في جوهره مجرد سلسلة نصية
- مثال:
البيانات (Data): محتوى الكائن نفسه
- يمكن أن تكون أي بيانات ثنائية
- حد الحجم يعتمد على مزود السحابة (عادةً في حدود 5 تيرابايت للكائن الواحد)
البيانات الوصفية (Metadata): معلومات إضافية تصف الكائن
- بيانات وصفية للنظام: Content-Type و ETag و Last-Modified إلخ
- بيانات وصفية مخصصة: مثل
x-oss-meta-ownerوx-oss-meta-project
التحكم في الوصول: من يستطيع الوصول إلى "مستودعي"؟
يوفر التخزين الكائني تحكمًا متعدد المستويات في الصلاحيات:
| المستوى | طريقة التحكم | السيناريو النموذجي |
|---|---|---|
| مستوى الحاوية | Bucket Policy (سياسة الموارد) | منع كل الوصول الخارجي، السماح بعناوين IP محددة فقط |
| مستوى الكائن | ACL (قائمة التحكم في الوصول) | صور عامة، مستندات خاصة |
| تفويض مؤقت | STS (خدمة الرمز الآمن) | الرفع المباشر من الواجهة الأمامية، الرفع من الجوال |
الخط الأحمر الأمني: لا تضع أبدًا AccessKey ID و AccessKey Secret في كود الواجهة الأمامية! الطريقة الصحيحة: تطلب الواجهة الأمامية بيانات اعتماد STS المؤقتة من الخادم الخلفي، ويتحقق الخادم الخلفي من الهوية ثم يعيد بيانات اعتماد مؤقتة مع وقت انتهاء صلاحية.
2. CDN: "شبكة التوصيل السريع العالمية" الخاصة بك
2.1 لماذا نحتاج إلى CDN؟
تخيل أنك فتحت متجرًا إلكترونيًا، والخادم موجود في شنتشن. الآن مستخدم في بكين يصل إلى صورك:
بدون CDN: ينتقل الطلب من بكين → خبي → خنان → خوبي → خونان → غوانغدونغ → شنتشن، عبر أكثر من 2000 كيلومتر، ذهابًا وإيابًا أكثر من 4000 كيلومتر. يستغرق النقل الشبكي وحده عشرات المللي ثانية، ويكون أسوأ في أوقات ازدحام الشبكة.
مع CDN: ينتقل الطلب من بكين مباشرة إلى عقدة CDN في بكين (قد تكون في غرفة خوادم China Unicom في بكين)، وتتقلص المسافة من 2000 كيلومتر إلى 20 كيلومترًا، والتأخير من 50 مللي ثانية إلى 5 مللي ثانية.
هذه هي القيمة الأساسية لـ CDN: جعل المحتوى أقرب إلى المستخدم.
2.2 البنية الأساسية لـ CDN
العقد الطرفية: "محطة التوصيل" الأقرب للمستخدم
العقد الطرفية هي الطبقة الأقرب للمستخدم في شبكة CDN، وتُنشر عادةً في:
- غرف خوادم مزودي الخدمة (China Unicom / China Telecom / China Mobile)
- مراكز تبادل الإنترنت في المدن الكبرى
- محاور النقل المهمة
توزيع عقد CDN الرئيسية في الصين:
- مدن الدرجة الأولى: بكين، شنغهاي، غوانغتشو، شنتشن
- مدن الدرجة الثانية: هانغتشو، نانجينغ، تشنغدو، ووهان، شيآن
- خارج الصين: هونغ كونغ، سنغافورة، طوكيو، وادي السيليكون، فرانكفورت
Edge Node Distribution Demo
Shows global CDN edge-node distribution and scheduling strategy.
Edge node distribution demo placeholder - interaction to be implemented
الخادم المصدر: "المستودع الرئيسي" للمحتوى
الخادم المصدر هو المكان الذي تعود إليه CDN للحصول على المحتوى، ويمكن أن يكون:
- التخزين الكائني (OSS/COS/S3)
- خادم ذاتي البناء (ECS/خادم مادي)
- موازن تحميل (SLB/CLB)
الإعدادات الرئيسية:
- مضيف العودة للمصدر (Origin HOST): اسم النطاق/IP المستخدم عند وصول عقدة CDN إلى الخادم المصدر
- بروتوكول العودة للمصدر: HTTP أم HTTPS
- منفذ العودة للمصدر: 80 أو 443 أو منفذ مخصص
العقد الوسيطة: "مركز الفرز الإقليمي"
بين العقد الطرفية والخادم المصدر، تمتلك CDN عادةً طبقة أو أكثر من العقد الوسيطة:
- عقد التجميع: تجميع طلبات العودة للمصدر من عدة عقد طرفية، لتقليل الضغط على الخادم المصدر
- المراكز الإقليمية: مسؤولة عن توزيع وجدولة المحتوى لمنطقة كبيرة
فوائد هذه البنية الطبقية:
- تقليل ضغط الخادم المصدر: 1000 طلب من العقد الطرفية، قد يحتاج فقط إلى 10 طلبات إلى الخادم المصدر
- تحسين معدل الإصاب��: يتم اعتراض المحتوى الشائع في الطبقة الوسيطة، دون الحاجة للعودة إلى المصدر
- عزل الأعطال: عند حدوث مشكلة في مسار معين، يمكن التبديل تلقائيًا إلى مسارات أخرى
2.3 العملية الكاملة لتسريع CDN
لنتتبع طلب مستخدم حقيقي:
Cache policy demo placeholder - interaction to be implemented
الخطوة 1: تحليل DNS (الجدولة الذكية)
إدخال المستخدم: cdn.example.com/image.jpg
↓
خادم DNS يعيد: عنوان IP لعقدة CDN في بكين China Unicom (1.2.3.4)المفتاح هنا هو DNS الذكي: يعيد عنوان IP الأمثل لعقدة CDN بناءً على مزود خدمة المستخدم وموقعه الجغرافي وحمل العقدة.
الخطوة 2: بحث العقدة الطرفية (إصابة في الذاكرة المؤقتة؟)
يصل الطلب إلى عقدة CDN في بكين China Unicom (1.2.3.4)
↓
تتحقق العقدة من الذاكرة المؤقتة المحلية:
├─ إصابة؟ تعيد المحتوى مباشرة ✓
└─ غير مصابة؟ تتابع إلى الخطوة التاليةالخطوة 3: العودة إلى المصدر (تصاعديًا طبقة تلو الأخرى)
العقدة الطرفية غير مصابة
↓
تطلب من العقدة الأم (مثل: المركز الإقليمي لشمال الصين)
├─ العقدة الأم مصابة؟ تعيد المحتوى
└─ العقدة الأم غير مصابة؟ تستمر للأعلى
↓
تطلب من الخادم المصدر
↓
الخادم المصدر يعيد المحتوىالخطوة 4: التخزين المؤقت والإرجاع (أسرع في المرة القادمة)
يعود المحتوى عبر المسار
↓
كل طبقة من العقد تخزن نسخة مؤقتة
↓
يصل أخيرًا إلى المستخدمبهذه الطريقة، عندما يطلب مستخدم آخر نفس الملف، يمكن إعادته مباشرة من العقدة الطرفية، محققًا "فتحًا فوريًا".
3. من الرفع إلى الوصول: تحليل المسار الكامل
3.1 ثلاث طرق لرفع الملفات
الطريقة الأولى: العميل → الخادم → التخزين الكائني (النمط التقليدي)
المتصفح → خادمك الخلفي → التخزين الكائنيالعملية:
- يختار المستخدم الملف، وينقر على رفع
- يُرفع الملف أولاً إلى خادمك الخلفي
- بعد أن يستلم الخادم الخلفي الملف بالكامل، يعيد رفعه إلى التخزين الكائني
- تُعاد نتيجة الرفع إلى المستخدم
المزايا:
- تنفيذ بسيط، سهل التحكم فيه من الطرفين الأمامي والخلفي
- يمكن إجراء التحقق من الملفات وتحويل التنسيق في الخادم الخلفي
- يمكن تسجيل العمليات الحساسة وإجراء التحقق من الصلاحيات
العيوب:
- استهلاك مضاعف لعرض النطاق: رفع المستخدم يستهلك عرض النطاق مرة، وإعادة رفع الخادم تستهلكه مرة أخرى
- ضغط عالٍ على الخادم: الملفات الكبيرة تستهلك الكثير من الذاكرة ووحدة المعالجة المركزية
- رفع بطيء: يعادل وجود محطة عبور إضافية، مما يجعل وقت الرفع المدرك من المستخدم أطول
السيناريوهات المناسبة: الملفات الصغيرة (< 10 ميجابايت)، الحاجة إلى معالجة خلفية (مثل ضغط الصور، إضافة العلامات المائية)، أنظمة الإدارة الداخلية.
الطريقة الثانية: الرفع المباشر من العميل إلى التخزين الكائني (موصى به حديثًا)
المتصفح ──────→ التخزين الكائني
↑
الخادم الخلفي يصدر فقط بيانات الاعتماد المؤقتةالعملية:
- يختار المستخدم الملف، وتطلب الواجهة الأمامية أولاً "بيانات اعتماد الرفع" من الخادم الخلفي
- يتحقق الخادم الخلفي من هوية المستخدم، ويطلب بيانات اعتماد STS المؤقتة (مع وقت انتهاء) من خدمة التخزين الكائني
- يعيد الخادم الخلفي بيانات الاعتماد المؤقتة إلى الواجهة الأمامية
- تستخدم الواجهة الأمامية بيانات الاعتماد لرفع الملف مباشرة إلى التخزين الكائني
- يعيد التخزين الكائني نتيجة الرفع، وتُعلم الواجهة الأمامية الخادم الخلفي "باكت���ال الرفع"
المزايا:
- رفع سريع: إزالة خطوة العبور الوسيطة، أسرع سرعة يدركها المستخدم
- ضغط منخفض على الخادم: يتعامل فقط مع إصدار بيانات الاعتماد، وليس مع تدفق الملفات
- توفير عرض النطاق: تمر حركة الرفع مرة واحدة فقط
- أمان عالٍ: بيانات الاعتماد المؤقتة لها وقت انتهاء، والضرر محدود حتى في حالة التسريب
العيوب:
- تنفيذ أكثر تعقيدًا قليلاً، يتطلب فهم STS وآلية التوقيع
- تحتاج الواجهة الأمامية إلى معالجة منطق الرفع المجزأ واستئناف التحميل بعد الانقطاع
- يحتاج CORS (المشاركة عبر الأصول) إلى التكوين
السيناريوهات المناسبة: رفع الملفات الكبيرة، المحتوى الذي ينشئه المستخدم (UGC)، الأعمال التي تتطلب رفعًا عالي التزامن.
الطريقة الثالثة: الرفع المجزأ + استئناف التحميل بعد الانقطاع (ضروري للملفات الكبيرة)
ملف فيديو بحجم 10 جيجابايت
↓
تقسيمه إلى 1000 جزء بحجم 10 ميجابايت لكل جزء
↓
رفع متوازٍ (5 أجزاء في نفس الوقت)
↓
انقطع الاتصال! تم رفع 600 جزء
↓
استعادة الاتصال، الاستمرار من الجزء 601
↓
بعد رفع كل الأجزاء، إرسال طلب "دمج"لماذا نحتاج إلى التجزئة؟
| السيناريو | بدون تجزئة | مع تجزئة |
|---|---|---|
| تقلب الشبكة | بعد رفع 99%، انقطاع الشبكة، إعادة رفع كاملة | إعادة رفع الأجزاء الفاشلة فقط |
| سرعة الرفع | خيط واحد، بطيء | خيوط متعددة متوازية، سريعة |
| استهلاك الذاكرة | تحتاج إلى تخزين الملف بالكامل | تحتاج فقط إلى تخزين الجزء الحالي |
| عرض التقدم | فقط 0% و 100% | تقدم دقيق لكل جزء |
مواصفات التجزئة لمزودي السحابة الرئيسيين:
| المزود | حد حجم الجزء | الحد الأقصى للأجزاء | الحد الأدنى لحجم الجزء |
|---|---|---|---|
| Alibaba Cloud OSS | 100 ميجابايت | 10000 | 100 كيلوبايت |
| Tencent Cloud COS | 5 جيجابايت | 10000 | 1 ميجابايت |
| AWS S3 | 5 جيجابايت | 10000 | 5 ميجابايت (موصى به) |
| Qiniu Cloud | 100 ميجابايت | 10000 | 4 ميجابايت |
3.2 شرح تفصيلي لاستراتيجيات العودة إلى المصدر في CDN
Cache policy demo placeholder - interaction to be implemented
ما هي "العودة إلى المصدر"؟
عقدة CDN الطرفية تخزن محتوى الخادم المصدر مؤقتًا، لكن عندما:
- يُطلب المحتوى لأول مرة
- المحتوى المخزن مؤقتًا انتهت صلاحيته (انتهاء TTL)
- تم مسح/تسخين الذاكرة المؤقتة يدويًا
تحتاج عقدة CDN إلى طلب أحدث محتوى من الخادم المصدر، وتسمى هذه العملية "العودة إلى المصدر".
أنماط العودة إلى المصدر الثلاثة
| النمط | المبدأ | السيناريو المناسب | المزايا والعيوب |
|---|---|---|---|
| العودة المباشرة | عقدة CDN → الخادم المصدر | الخادم المصدر له IP عام، وحركة المرور ليست كبيرة | بسيط ومباشر، لكن ضغط الخادم المصدر عالٍ |
| العودة عبر مصدر وسيط | عقدة CDN → الطبقة الوسيطة → الخادم المصدر | المواقع الكبيرة، بنية تخزين مؤقت متعددة الطبقات | توزيع ضغط الخادم المصدر، البنية معقدة |
| OSS/COS كمصدر | عقدة CDN → التخزين الكائني | الموارد الثابتة، الصور، الفيديو | أفضل ممارسة، تكلفة منخفضة، أداء جيد |
تكوين العودة إلى المصدر عمليًا
السيناريو 1: التخزين الكائني كمصدر (موصى به)
وصول المستخدم: cdn.example.com/images/photo.jpg
↓
عقدة CDN الطرفية (بكين)
↓
غير مصابة، العودة إلى المصدر
↓
المصدر: bucket-name.oss-cn-beijing.aliyuncs.com
↓
إعادة الصورة، CDN تخزن مؤقتًا وتستجيب للمستخدمعناصر التكوين الرئيسية:
- نوع المصدر: نطاق OSS/COS أو مصدر مخصص
- بروتوكول العودة: HTTP أم HTTPS (يُنصح بـ HTTPS)
- مضيف العودة (Origin HOST): رأس Host المستخدم عند الوصول إلى المصدر
- SNI العودة: مؤشر اسم الخادم عند العودة عبر HTTPS
السيناريو 2: موازنة تحميل بمصادر متعددة
عندما لا يتحمل مصدر واحد ضغط العودة، يمكن تكوين مصادر متعددة:
عقدة CDN الطرفية
├─ المصدر A (وزن 50%)
├─ المصدر B (وزن 30%)
└─ المصدر C (وزن 20%)نمط الرئيسي/الاحتياطي:
عقدة CDN الطرفية
├─ المصدر الرئيسي A (كل حركة المرور عندما يكون سليمًا)
└─ المصدر الاحتياطي B (التبديل عند تعطل المصدر الرئيسي)عرض النطاق للعودة مقابل عرض نطاق CDN
هناك مفهوم سهل الخلط بينه:
| المؤشر | التعريف | علاقة الفوترة |
|---|---|---|
| عرض النطاق الصادر لـ CDN | حركة المرور من عقدة CDN إلى المستخدم | عادةً رسوم CDN حسب حركة المرور |
| عرض النطاق للعودة | حركة المرور من المصدر إلى عقدة CDN | عادةً رسوم حركة المرور الصادرة من التخزين الكائني أو المصدر |
نصائح لتوفير التكاليف:
- تحسين معدل إصابة CDN (جعل المزيد من الطلبات تصيب الذاكرة المؤقتة، لتقليل العودة)
- تعيين وقت تخزين مؤقت معقول (TTL)
- استخدام ميزة التسخين، لتخزين المحتوى الشائع مؤقتًا قبل وصول المستخدم
- تفعيل "متابعة 301/302"، لتجنب قفزات العودة غير الضرورية
3.3 تكوين استراتيجية التخزين المؤقت
Cache policy demo placeholder - interaction to be implemented
مفتاح التخزين المؤقت (Cache Key): تحديد ما يعتبر "نفس الملف"
كيف تحدد CDN ما إذا كان يجب إعادة نفس النسخة المخزنة مؤقتًا لطلبين؟ يعتمد ذلك على مفتاح التخزين المؤقت.
مفتاح التخزين المؤقت الافتراضي يشمل عادةً:
- مسار URL (بدون معاملات الاستعلام)
- مثال:
/images/photo.jpg
سيناريو المشكلة:
طلب المستخدم A: /images/photo.jpg?w=100&h=100 (صورة مصغرة 100×100)
طلب المستخدم B: /images/photo.jpg?w=800&h=600 (صورة كبيرة 800×600)إذا كان مفتاح التخزين المؤقت يشمل المسار فقط، فسيتم اعتبار الصورتين ذات الأحجام المختلفة نفس الملف، مما يسبب فوضى.
الحل: قواعد مفتاح تخزين مؤقت مخصصة
| القاعدة | مثال | التأثير |
|---|---|---|
| الاحتفاظ بمعاملات استعلام محددة | الاحتفاظ بـ w، h | تخزين مؤقت منفصل لكل حجم |
| الاحتفاظ بجميع معاملات الاستعلام | الاحتفاظ بالكل | مطابقة دقيقة تمامًا |
| تجاهل معاملات استعلام محددة | تجاهل token، timestamp | عناوين URL ذات الطوابع الزمنية يمكنها إصابة الذاكرة المؤقتة |
| تضمين رؤوس الطلب | تضمين Accept-Language | إرجاع محتوى مختلف للغات المختلفة |
مثال تكوين عملي (Alibaba Cloud CDN):
قواعد مفتاح التخزين المؤقت:
- مسار URL: /images/*
- معاملات الاستعلام المحتفظ بها: w, h, format
- معاملات الاستعلام المتجاهلة: token, timestamp, utm_sourceوقت التخزين المؤقت (TTL): توازن "حداثة" المحتوى
TTL (Time To Live) يحدد مدة بقاء المحتوى مخزنًا مؤقتًا على عقدة CDN. إذا كان قصيرًا جدًا، تكثر العودة إلى المصدر وتزيد التكلفة؛ وإذا كان طويلاً جدًا، يرى المستخدم محتوى قديمًا بعد التحديث.
اقتراحات TTL حسب نوع الملف:
| نوع الملف | TTL المقترح | السبب |
|---|---|---|
| صفحات HTML | 0-5 دقائق | تحديث متكرر للمحتوى، يحتاج إلى وقت حقيقي |
| ملفات JS/CSS | سنة واحدة (مع hash في اسم الملف) | المحتوى لا يتغير، يتغير اسم الملف عند تغير المحتوى |
| الصور/الفيديو | 7-30 يومًا | تردد تحديث منخفض، يمكن تخزينه طويل المدى |
| ملفات الخطوط | سنة واحدة | لا تتغير تقريبًا |
| استجابات API | 0-5 دقائق (حسب العمل) | متطلبات عالية لآنية البيانات |
أفضل ممارسات هندسة الواجهة الأمامية بالتزامن مع CDN:
// إعدادات webpack/vite
output: {
filename: 'js/[name]-[contenthash:8].js',
chunkFilename: 'js/[name]-[contenthash:8].chunk.js',
}اسم الملف المُنشأ: app-a3f2b1c9.js
- تغير محتوى الملف → تغير hash → عنوان URL جديد → انتهاء صلاحية التخزين المؤقت طبيعيًا
- عدم تغير محتوى الملف → عدم تغير hash → عدم تغير URL → إصابة تخزين مؤقت طويل المدى
مسح وتسخين الذاكرة المؤقتة
المسح اليدوي (سيناريوهات الطوارئ):
عندما تقوم بتحديث محتوى المصدر، لكن ذاكرة CDN المؤقتة لم تنته صلاحيتها بعد، يرى المستخدم المحتوى القديم:
| نوع المسح | التأثير | الوقت المستغرق | السيناريو المناسب |
|---|---|---|---|
| مسح URL | إبطال ذاكرة مؤقتة لـ URL محدد | 5-10 دقائق | تحديث ملف واحد |
| مسح الدليل | إبطال كل المحتوى تحت دليل محدد | 10-30 دقيقة | تحديث دفعة |
| مسح كامل | إبطال كل الذاكرة المؤقتة للنطاق بالكامل | 30 دقيقة فأكثر | تراجع طارئ |
تنبيه مهم: المسح فقط يجعل الذاكرة المؤقتة غير صالحة، وسيؤدي الطلب التالي إلى العودة إلى المصدر لجلب محتوى جديد. لا تقم بمسح كميات كبيرة في أوقات الذروة، وإلا فقد يتعطل الخادم المصدر.
التسخين (تحسين استباقي):
المسح سلبي (تم تحديث المحتوى)، بينما التسخين استباقي (تخزين مؤقت مسبق).
السيناريو: غدًا الساعة 10 صباحًا سيتم نشر مقال رائج
قدم طلب تسخين الليلة:
- URL: https://cdn.example.com/articles/رائج.html
- نطاق التسخين: جميع العقد الطرفية على مستوى الدولة
التأثير:
عند وصول المستخدمين غدًا الساعة 10، المحتوى موجود مسبقًا في العقد الطرفية
→ تأخير عودة إلى المصدر صفري، تجربة فتح فورية4. جدولة حركة المرور: جعل المستخدم يصل إلى "أقرب" عقدة
Traffic scheduling demo placeholder - interaction to be implemented
4.1 جدولة DNS الذكية
تحليل DNS التقليدي:
يسأل المستخدم: ما هو عنوان IP لـ cdn.example.com؟
يجيب DNS: 1.2.3.4 (ثابت)تحليل DNS الذكي:
يسأل المستخدم (بكين، China Unicom): ما هو عنوان IP لـ cdn.example.com؟
DNS الذكي: دعني أتحقق... عقدة CDN لـ Beijing Unicom هي 1.2.3.4
يسأل المستخدم (شنغهاي، China Telecom): ما هو عنوان IP لـ cdn.example.com؟
DNS الذكي: عقدة CDN لـ Shanghai Telecom هي 5.6.7.8أبعاد الجدولة:
| البعد | الوصف | التأثير |
|---|---|---|
| الموقع الجغرافي | التوزيع حسب المقاطعة/المدينة/الدولة | وصول قريب، تقليل التأخير |
| مزود الخدمة | Unicom/Telecom/Mobile/BGP | نقل داخل نفس المزود، تجنب عبور الشبكات |
| حمل العقدة | CPU/عرض النطاق/QPS في الوقت الحقيقي | تجنب العقد المثقلة |
| صحة العقدة | فحص التوفر | استبعاد العقد المعطلة تلقائيًا |
| عوامل التكلفة | فروق أسعار عرض النطاق | موازنة الأداء والتكلفة |
4.2 HTTP DNS والاتصال المباشر بـ IP
مشكلة DNS التقليدي: اختطاف DNS وتأخير التحليل.
حل HTTP DNS:
العميل → تجاوز DNS النظام → يسأل خدمة HTTP DNS مباشرة (مثل 223.5.5.5:80)
↓
يعيد قائمة عناوين IP المثلى (مع أوزان)
↓
يختار العميل عنوان IP الأمثل بناءً على فحص جودة الشبكةالمزايا:
- منع الاختطاف: لا يمر عبر DNS مزود الخدمة
- أكثر دقة: يمكن اختيار IP بناءً على جودة شبكة العميل
- آنية: تبديل أسرع عند الأعطال
نصائح عملية:
- تطبيقات الجوال يُنصح بشدة باستخدام HTTP DNS
- جانب الويب يمكنه استخدام جدولة CNAME المقدمة من CDN
- الأعمال الحرجة يمكنها عمل تكرار بعناوين IP متعددة (نطاق واحد يعيد عدة عناوين IP)
5. تحسين HTTPS: توازن الأمان والأداء
HTTPS optimization demo placeholder - interaction to be implemented
5.1 لماذا HTTPS مهم على CDN؟
مقارنة السيناريوهات:
بدون HTTPS:
وصول المستخدم إلى http://cdn.example.com/image.jpg
↓
شريط عنوان المتصفح يعرض "غير آمن"
↓
بعض المتصفحات/التطبيقات تمنع الوصول مباشرة
↓
انخفاض ترتيب SEOمع HTTPS:
وصول المستخدم إلى https://cdn.example.com/image.jpg
↓
المتصفح يعرض أيقونة القفل الأخضر
↓
تفعيل HTTP/2 تعدد الإرسال
↓
تحسين مزدوج في الأداء + الأمان5.2 نقاط تكوين HTTPS على CDN
إدارة الشهادات
| الحل | الوصف | التكلفة | السيناريو المناسب |
|---|---|---|---|
| شهادة مجانية من مزود السحابة | مقدمة من Alibaba Cloud/Tencent Cloud إلخ | مجانية | نطاق واحد، بدء سريع |
| Let's Encrypt | شهادة مجتمعية مجانية | مجانية | نشر آلي |
| شهادة تجارية DV/OV/EV | Symantec، GeoTrust إلخ | مئات إلى آلاف اليوانات/سنة | مستوى المؤسسات، تحتاج إلى شريط أخضر |
| شهادة نطاق شامل | *.example.com | آلاف اليوانات/سنة | نطاقات فرعية متعددة |
نصائح عملية:
- بيئة الاختبار: Let's Encrypt أو شهادة مجانية من مزود السحابة
- بيئة الإنتاج: شهادة نطاق شامل (لتوفير الجهد) أو شهادة OV لنطاق واحد (لتوفير المال)
- انتبه لوقت انتهاء الشهادة، وعيّن تذكيرات تجديد تلقائي
تكوين تحسين HTTPS
اختيار إصدار TLS:
التكوين الموصى به: TLS 1.2 و TLS 1.3 فقط
تكوين التوافق: TLS 1.1 + TLS 1.2 + TLS 1.3 (لتوافق المتصفحات القديمة)مجموعات التشفير (Cipher Suites):
موصى به: تبادل مفاتيح ECDHE + تشفير AES-GCM
معطل: DES، RC4، MD5، SHA1OCSP Stapling:
الوظيفة: عقدة CDN تجلب حالة إبطال الشهادة مسبقًا
التأثير: تقليل وقت تحقق العميل بمقدار 200-500 مللي ثانية
نصيحة: يجب تفعيلهإعادة استخدام جلسة TLS:
إعادة استخدام Session ID: العميل يحمل Session ID السابق، الخادم يستعيد الجلسة
إعادة استخدام Session Ticket: الخادم يرسل حالة الجلسة مشفرة للعميل، يعيدها في المرة القادمة
التأثير: تجنب مصافحة TLS الكاملة، تقليل 1-RTT5.3 تطبيق HTTP/2 و HTTP/3 على CDN
تعدد إرسال HTTP/2:
HTTP/1.1:
طلب 1 (index.html) ────────────────→
استجابة 1 ←──────────────────────────────
طلب 2 (style.css) ─────────────────→
استجابة 2 ←──────────────────────────────
طلب 3 (script.js) ─────────────────→
استجابة 3 ←──────────────────────────────
(تسلسلي، واحد تلو الآخر)
HTTP/2:
طلب 1 ──→
طلب 2 ──→ مدمجة في اتصال TCP واحد، إطارات متداخلة
طلب 3 ──→
استجابة 1 ←── إرجاع متدفق حسب الأولوية
استجابة 2 ←──
استجابة 3 ←──
(متوازٍ، اتصال واحد متعدد الإرسال)دفع الخادم في HTTP/2 (Server Push):
السيناريو: يطلب المستخدم index.html، الذي يشير إلى style.css و script.js
الطريقة التقليدية:
1. ينزل المستخدم index.html
2. يكتشف التحليل الحاجة إلى style.css و script.js
3. يرسل طلبين آخرين للحصول عليهما
دفع HTTP/2:
1. يطلب المستخدم index.html
2. عقدة CDN تعيد index.html وتدفع بنشاط style.css و script.js
3. عندما يحلل المستخدم html، الموارد موجودة مسبقًا في الذاكرة المؤقتة
تنبيه: يجب توخي الحذر في الدفع، الدفع الزائد يهدر عرض النطاق، والقليل لا يحقق التأثيرHTTP/3 (QUIC):
مشكلة HTTP/2: مبني على TCP، حظر رأس الصف (Head-of-Line Blocking)
→ فقدان حزمة TCP واحدة، الاتصال بالكامل ينتظر إعادة الإرسال
حل HTTP/3: مبني على QUIC (نقل موثوق فوق UDP)
→ كل تدفق مستقل، حظر تدفق واحد لا يؤثر على التدفقات الأخرى
→ ترحيل الاتصال: التبديل من WiFi إلى 4G، الاتصال لا ينقطع
→ مصافحة 0-RTT: حتى أول زيارة يمكنها إنشاء اتصال بسرعة
الوضع الحالي: في 2024، CDN الرئيسية تدعم HTTP/3، يُنصح بتفعيله6. تحليل الوصول: فهم تقارير CDN الخاصة بك
Access analytics demo placeholder - interaction to be implemented
6.1 شرح المؤشرات الأساسية
عرض النطاق (Bandwidth)
التعريف: كمية البيانات المنقولة في وحدة الزمن
الوحدة: bps (بت في الثانية)، Mbps، Gbps
عرض نطاق CDN = مجموع حركة المرور الصادرة من جميع العقد الطرفية
انتبه للتمييز بين:
- عرض النطاق المحتسب: عادةً يُحسب على ذروة 95% أو الذروة اليومية
- عرض النطاق الفعلي: معدل النقل في الوقت الحقيقيالعلاقة بين عرض النطاق وحجم المرور:
1 Mbps عرض نطاق يعمل باستمرار لمدة ساعة واحدة = 450 MB حركة مرور
(الحساب: 1,000,000 bps × 3600s ÷ 8 ÷ 1024 ÷ 1024 ≈ 429 MB)QPS (Queries Per Second)
التعريف: عدد الاستعلامات/الطلبات في الثانية
CDN QPS = إجمالي طلبات HTTP التي تعالجها جميع العقد الطرفية في الثانية
انتبه: QPS مرتفع لا يعني عرض نطاق مرتفع
- سيناريو الملفات الصغيرة: QPS مرتفع جدًا، عرض النطاق ليس مرتفعًا
- سيناريو الملفات الكبيرة: QPS ليس مرتفعًا، عرض النطاق مرتفع جدًامعدل الإصاب�� (Hit Ratio)
التعريف: نسبة الطلبات التي تصيب العقد الطرفية لـ CDN من إجمالي الطلبات
صيغة الحساب:
معدل الإصابة = (عدد الإصابات / إجمالي الطلبات) × 100%
أو
معدل الإصابة = (1 - حركة العودة / إجمالي حركة المرور الصادرة) × 100%
المعيار الصناعي:
- الصور/الفيديو/JS/CSS: > 95%
- صفحات HTML: 50-80% (حسب تردد التحديث)
- واجهات API: عادةً لا تُخزن مؤقتًا أو منخفضة جدًاالأسباب الشائعة لانخفاض معدل الإصابة:
| السبب | الظاهرة | الحل |
|---|---|---|
| وقت تخزين قصير جدًا | TTL بضع دقائق فقط | ضبط TTL حسب نوع الملف |
| تغير معاملات الاستعلام | URL يحمل رقمًا عشوائيًا | تكوين تجاهل معاملات محددة |
| إعداد مفتاح تخزين غير مناسب | تم تمييز ما لا يجب تمييزه | تحسين قواعد مفتاح التخزين |
| تحديث متكرر للمحتوى | الملفات تُستبدل كثيرًا | استخدام أرقام الإصدارات أو hash في أسماء الملفات |
| زيارات أولى كثيرة | محتوى جديد أو عقد جديدة | تسخين مسبق |
6.2 تحليل السجلات واستكشاف المشكلات
تحليل حقول سجل CDN
يحتوي سجل وصول CDN النموذجي على الحقول التالية:
الوقت | IP العميل | طريقة الطلب | URL | رمز حالة HTTP | حجم الاستجابة | حالة التخزين المؤقت | وقت الاستجابة | Referer | User-Agent
مثال:
2024-01-15 14:32:01 | 114.114.114.114 | GET | https://cdn.example.com/images/photo.jpg | 200 | 153600 | HIT | 23 | https://example.com/ | Mozilla/5.0...شرح الحقول الرئيسية:
| الحقل | الوصف | قيمة التحليل |
|---|---|---|
cache_status | حالة التخزين المؤقت | HIT (إصابة)، MISS (غير مصاب)، EXPIRED (منتهي الصلاحية) |
response_time | وقت الاستجابة (ms) | الحكم على تجربة المستخدم، > 500ms يحتاج تحسين |
http_status | رمز حالة HTTP | استكشاف أخطاء 404/500 |
bytes_sent | البايتات المرسلة | إحصاء عرض النطاق |
استكشاف المشكلات الشائعة
المشكلة 1: المستخدم يبلغ عن بطء الوصول
خطوات الاستكشاف:
1. انظر إلى response_time في السجل
- إذا كان كبيرًا (> 500ms): تحقق مما إذا كانت الذاكرة المؤقتة MISS أو المصدر بطيئًا
2. تحقق من cache_status
- HIT: إصابة في الذاكرة المؤقتة، البطء قد يكون بسبب حجم الملف الكبير أو مشكلة في العقدة
- MISS: غير مصاب، تحتاج إلى تحسين استراتيجية التخزين المؤقت أو معدل الإصابة
3. تحقق من توزيع IP العملاء
- مناطق معينة بطيئة: قد تكون العقدة مثقلة أو التغطية غير كافيةالمشكلة 2: التخزين المؤقت لا يعمل، العودة إلى المصدر في كل مرة
قائمة التحقق:
□ هل رأس استجابة المصدر يحتوي على Cache-Control: no-cache / private؟
□ هل URL يحمل معاملات عشوائية (مثل ?_=123456)؟
□ هل تكوين مفتاح التخزين المؤقت صحيح؟
□ هل إعداد TTL قصير جدًا؟
□ هل تمت الإصابة في الذاكرة المؤقتة المحلية للمتصفح بدلاً من CDN؟المشكلة 3: ارتفاع مفاجئ في التكاليف
اتجاه الاستكشاف:
1. انظر إلى تفاصيل الفاتورة
- رسوم حركة CDN مرتفعة: تحقق مما إذا كانت هناك ملفات كبيرة يتم الوصول إليها بشكل متكرر، أو سرقة روابط
- رسوم حركة العودة مرتفعة: تحقق مما إذا انخفض معدل الإصابة فجأة
- رسوم عدد الطلبات مرتفعة: تحقق من وجود هجوم CC أو برامج زحف
2. انظر إلى سجل الوصول
- هل هناك عدد كبير من طلبات 404 (قد يكون فحصًا أو خطأ في التكوين)
- هل Referer غير طبيعي (لتحديد سرقة الروابط)
3. إعدادات الأمان
- تفعيل منع سرقة الروابط (القائمة البيضاء لـ Referer)
- تفعيل القائمة السوداء/البيضاء لـ IP
- تكوين حماية CC7. حالة عملية: بناء حل تسريع الصور من الصفر
7.1 سيناريو العمل
افترض أنك المسؤول التقني لمجتمع صور، وتواجه التحديات التالية:
- رفع المستخدم: يرفع المستخدمون مليون صورة يوميًا (متوسط 2 ميجابايت/صورة)
- وصول المستخدم: 50 مليون طلب مشاهدة صور يوميًا
- توزيع الوصول: المستخدمون منتشرون في جميع أنحاء البلاد، مع وصول محدود من الخارج
- متطلبات الأداء: وقت تحميل الصورة < 500 مللي ثانية
- ميزانية التكلفة: محاولة البقاء ضمن 50,000 يوان شهريًا
7.2 تصميم البنية
┌──────────────────────────────────────┐
│ عملية رفع المستخدم │
└──────────────────────────────────────┘
متصفح المستخدم الخدمة الخلفية التخزين الكائني
│ │ │
│ 1. طلب بيانات اعتماد الرفع │ │
│───────────────────────────────────────────>│ │
│ │ │
│ │ 2. طلب بيانات اعتماد STS المؤقتة │
│ │───────────────────────────>│
│ │ │
│ │ 3. إعادة بيانات اعتماد STS │
│ │<───────────────────────────│
│ │ │
│ 4. إعادة بيانات اعتماد الرفع (متضمنة STS) │
│<───────────────────────────────────────────│ │
│ │ │
│ 5. رفع الملف مباشرة (باستخدام توقيع STS) │
│──────────────────────────────────────────────────────────────────────>│
│ │ │
│ 6. إعادة نتيجة الرفع (URL، ETag إلخ) │
│<──────────────────────────────────────────────────────────────────────│
│ │ │
│ 7. إعلام الخادم الخلفي باكتمال الرفع (حفظ في قاعدة البيانات) │
│───────────────────────────────────────────>│ │
┌──────────────────────────────────────┐
│ عملية وصول المستخدم │
└──────────────────────────────────────┘
متصفح المستخدم تحليل DNS عقدة CDN التخزين الكائني (المصدر)
│ │ │ │
│ 1. طلب URL الصورة │ │ │
│────────────────────────────────────────>│ │
│ │ │ │
│ │ 2. استعلام DNS │ │
│ │────────────────────>│ │
│ │ │ │
│ │ 3. إعادة IP العقدة المثلى │ │
│ │<────────────────────│ │
│ │ │ │
│ 4. الاتصال بعقدة CDN │ │ │
│────────────────────────────────────────>│ │
│ │ │ │
│ │ 5. فحص الذاكرة المؤقتة │ │
│ │ ├─ إصابة؟ إعادة مباشرة │
│ │ └─ غير مصابة؟ متابعة │
│ │ │ │
│ │ │ 6. العودة للمصدر │
│ │ │──────────────────>│
│ │ │ │
│ │ │ 7. إعادة الملف │
│ │ │<──────────────────│
│ │ │ │
│ │ 8. تخزين مؤقت واستجابة │ │
│<────────────────────────────────────────│ │7.3 شرح التكوينات الرئيسية
تكوين التخزين الكائني
تخطيط حاوية التخزين:
Bucket: myapp-images-prod
├─ هيكل الدليل:
│ ├─ uploads/ # الصور الأصلية التي يرفعها المستخدم
│ │ ├─ 2024/01/15/user123-abc.jpg
│ │ └─ 2024/01/15/user456-def.png
│ ├─ thumbnails/ # الصور المصغرة
│ │ ├─ small/ # 100x100
│ │ ├─ medium/ # 400x300
│ │ └─ large/ # 800x600
│ └─ processed/ # الصور المعالجة (مع علامة مائية إلخ)
│
├─ صلاحيات الوصول:
│ ├─ دليل الصور الأصلية: خاص (يحتاج وصولًا موقعًا)
│ ├─ دليل الصور المصغرة: قراءة عامة
│ └─ CORS عبر النطاقات: السماح لـ *.myapp.com بالوصول
│
└─ سياسة دورة الحياة:
├─ بعد 7 أيام من الرفع: تخزين منخفض التردد (توفير 40% من التكلفة)
├─ بعد 90 يومًا من الرفع: تخزين أرشيفي (توفير 70% من التكلفة)
└─ بعد 3 سنوات من الرفع: حذف تلقائي (أو نقل إلى تخزين بارد أرخص)تكوين CORS عبر النطاقات:
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>https://myapp.com</AllowedOrigin>
<AllowedOrigin>https://www.myapp.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<ExposeHeader>ETag</ExposeHeader>
<ExposeHeader>x-oss-request-id</ExposeHeader>
<MaxAgeSeconds>3600</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>تكوين تسريع CDN
تكوين استراتيجية التخزين المؤقت:
القاعدة الافتراضية العامة:
├─ مفتاح التخزين المؤقت: مسار URL + الاحتفاظ بمعاملات w، h، format
├─ TTL الافتراضي: 7 أيام
└─ مضيف العودة: متابعة تلقائية
تقسيم حسب نوع الملف:
├─ *.html:
│ ├─ TTL: 5 دقائق
│ └─ أولوية القراءة من ذاكرة التخزين المؤقت
│
├─ *.js, *.css:
│ ├─ TTL: سنة واحدة
│ └─ تجاهل معاملات الاستعلام (لأن اسم الملف يحتوي على hash)
│
├─ *.jpg, *.png, *.gif, *.webp:
│ ├─ TTL: 30 يومًا
│ ├─ الاحتفاظ بمعاملات الاستعلام (w، h، format للقص الديناميكي)
│ └─ تفعيل تحسين ضغط الصور التلقائي
│
└─ /api/*:
├─ TTL: 0 (بدون تخزين مؤقت)
└─ عودة مباشرة للمصدرتكوين تحسين HTTPS:
تكوين الشهادة:
├─ نوع الشهادة: شهادة نطاق شامل *.myapp.com
├─ طريقة النشر: رفع في لوحة تحكم CDN، تجديد تلقائي
└─ شهادة احتياطية: شهادة EV للنطاق الرئيسي (عرض شريط العنوان الأخضر)
تكوين TLS:
├─ أدنى إصدار TLS: 1.2 (توازن التوافق والأمان)
├─ أعلى إصدار TLS: 1.3
├─ مجموعات التشفير: تفعيل مجموعات التشفير القوية فقط
├─ OCSP Stapling: مفعّل
├─ إعادة استخدام جلسة TLS: تفعيل Session Ticket
└─ HSTS: مفعّل (max-age=31536000)
HTTP/2 و HTTP/3:
├─ HTTP/2: مفعّل (تعدد الإرسال، ضغط الرؤوس)
├─ HTTP/2 Server Push: تفعيل حسب الحاجة (يُنصح باستخدام Preload كبديل)
└─ HTTP/3 (QUIC): مفعّل (ميزة تجريبية، زيادة تدريجية)7.4 استراتيجية التحكم في التكاليف
تحليل مكونات التكلفة
مكونات التكلفة الشهرية لـ CDN + التخزين الكائني:
جزء CDN:
├─ رسوم حركة المرور الصادرة (الجزء الأكبر، حوالي 60%)
│ ├─ الصين الرئيسية: 0.15-0.30 يوان/جيجابايت
│ ├─ منطقة آسيا والمحيط الهادئ: 0.40-0.80 يوان/جيجابايت
│ └─ أوروبا وأمريكا: 0.30-0.60 يوان/جيجابايت
│
├─ رسوم عدد الطلبات (جزء صغير، حوالي 5%)
│ ├─ HTTP: 0.01-0.05 يوان/10,000 مرة
│ └─ HTTPS: 0.05-0.15 يوان/10,000 مرة (لأن مصافحة TLS تستهلك موارد)
│
├─ رسوم ذروة عرض النطاق (طريقة فوترة اختيارية)
│ └─ فوترة ذروة 95%: مناسبة للسيناريوهات ذات التقلب الكبير في حركة المرور
│
└─ رسوم الميزات الإضافية (حوالي 5%)
├─ إدارة شهادات HTTPS
├─ حماية WAF
├─ دفع السجلات في الوقت الحقيقي
└─ النصوص/الدوال الطرفية
جزء التخزين الكائني:
├─ رسوم سعة التخزين (حوالي 15%)
│ ├─ تخزين قياسي: 0.12-0.15 يوان/جيجابايت/شهر
│ ├─ تخزين منخفض التردد: 0.08-0.10 يوان/جيجابايت/شهر
│ └─ تخزين أرشيفي: 0.03-0.05 يوان/جيجابايت/شهر
│
├─ رسوم الطلبات (حوالي 5%)
│ ├─ PUT: 0.01-0.05 يوان/10,000 مرة
│ └─ GET: 0.005-0.01 يوان/10,000 مرة
│
├─ رسوم استرجاع البيانات (منخفض التردد/الأرشيفي)
│ └─ رسوم إضافية على الحذف المبكر أو الاسترجاع
│
└─ رسوم حركة العودة للمصدر (حوالي 10%)
└─ رسوم حركة مرور عودة CDN إلى التخزين الكائنينصائح عملية لتوفير التكاليف
نصيحة 1: تقسيم التخزين، إدارة دورة الحياة التلقائية
# مثال قواعد دورة الحياة
rules:
- id: image-lifecycle
prefix: uploads/
transitions:
# بعد 7 أيام، نقل إلى تخزين منخفض التردد، توفير 30% من التكلفة
- days: 7
storageClass: IA
# بعد 90 يومًا، نقل إلى تخزين أرشيفي، توفير 70% من التكلفة
- days: 90
storageClass: Archive
# حذف تلقائي بعد 3 سنوات
expiration:
days: 1095نصيحة 2: تحسين معدل إصابة CDN، تقليل العودة إلى المصدر
ماذا يعني رفع معدل الإصابة من 90% إلى 95%؟
بافتراض:
- حركة المرور اليومية: 10 TB
- معدل الإصابة 90%: العودة 1 TB
- معدل الإصابة 95%: العودة 0.5 TB
توفير حركة العودة: 0.5 TB/يوم × 0.15 يوان/GB × 30 يومًا = 2,250 يوان/شهرنصيحة 3: الضغط وتحسين التنسيق
خطة تحسين الصور:
├─ تخزين الصور الأصلية في التخزين الكائني (غير متاحة مباشرة للخارج)
├─ تفعيل ميزة معالجة الصور في CDN:
│ ├─ تحويل تلقائي للتنسيق: JPEG → WebP/AVIF (توفير 30-50%)
│ ├─ ضغط تلقائي للجودة: ضغط بلا فقدان بصري (توفير 20-40%)
│ ├─ تكيف الأبعاد: إرجاع الحجم المناسب حسب الجهاز
│ └─ تحميل تدريجي: ضبابي ثم واضح
└─ التأثير: خفض تكلفة عرض النطاق بنسبة 50-70%نصيحة 4: تحديد سقف عرض النطاق والتنبيهات
# تكوين سقف عرض النطاق
bandwidth_cap:
daily_limit: 500 # Mbps، إذا تجاوزت الذروة اليومية، إيقاف CDN تلقائيًا
monthly_limit: 10000 # GB، إذا تجاوزت حركة المرور الشهرية، إيقاف
# عتبات التنبيه
alerts:
- threshold: 70% # عند الوصول إلى 70%، إرسال تنبيه
channels: [sms, email]
- threshold: 90% # عند الوصول إلى 90%، اتصال هاتفي
channels: [phone]8. الخلاصة: القواعد الذهبية للتخزين الكائني + CDN
8.1 مبادئ تصميم البنية
المبدأ 1: فصل المحتوى الديناميكي عن الثابت
المحتوى الديناميكي (API، HTML) → عبر الخادم المصدر أو الدوال الطرفية
المحتوى الثابت (الصور، JS، CSS، الفيديو) → عبر CDN + التخزين الكائنيالمبدأ 2: الخدمة من أقرب نقطة
أينما كان المستخدم، يُخزن المحتوى مؤقتًا هناك
→ اختر مزود CDN بتغطية واسعة
→ فعّل جدولة DNS الذكية
→ سخّن المحتوى المهم مسبقًاالمبدأ 3: التخزين المؤقت متعدد الطبقات
ذاكرة المتصفح المحلية المؤقتة (الأقوى)
↓
ذاكرة عقدة CDN الطرفية المؤقتة (ثاني أقوى)
↓
طبقة CDN الوسيطة/العقد الإقليمية (شبكة أمان)
↓
التخزين الكائني/الخادم المصدر (خط الدفاع الأخير)المبدأ 4: توازن التكلفة والتجربة
تقسيم التخزين: البيانات الساخنة تخزين قياسي، البيانات الباردة تخزين أرشيفي
استراتيجية التخزين المؤقت: محتوى عالي التردد TTL طويل، محتوى منخفض التردد TTL قصير
تحسين الضغط: تنسيق WebP/AVIF، ضغط ذكي للجودة
المراقبة والتنبيه: تعيين سقف عرض النطاق، منع حركة المرور غير الطبيعية8.2 قائمة تجنب العقبات
تسمية الحاويات والصلاحيات
- [ ] اسم الحاوية فريد عالميًا، تجنب أن يكون محجوزًا
- [ ] عدم تعيين الملفات الخاصة للقراءة العامة
- [ ] عدم كتابة AccessKey في كود الواجهة الأمامية، استخدم بيانات اعتماد STS المؤقتة
- [ ] تفعيل التشفير من جانب الخادم (SSE) لحماية البيانات الحساسة
تكوين ذاكرة CDN المؤقتة
- [ ] TTL ملفات HTML لا يجب أن يكون طويلاً جدًا (يُنصح < 5 دقائق)
- [ ] JS/CSS يُنصح باستخدام أسماء ملفات مع hash، وتعيين TTL لسنة واحدة
- [ ] مفتاح التخزين المؤقت يجب أن يكون معقولاً، لا تضع معلومات المستخدم كمتغيرات فيه
- [ ] بعد التحديثات المهمة، تذكر مسح الذاكرة المؤقتة أو التسخين
أمان HTTPS
- [ ] عدم انتهاء صلاحية الشهادة، تعيين تجديد تلقائي
- [ ] أدنى إصدار TLS موصى به هو 1.2
- [ ] تفعيل HSTS لمنع هجمات التخفيض
- [ ] تعيين Secure و HttpOnly لملفات تعريف الارتباط الحساسة
التحكم في التكاليف
- [ ] تفعيل تنبيه سقف عرض النطاق، منع حركة المرور غير الطبيعية
- [ ] التخزين منخفض التردد/الأرشيفي له حد أدنى لوقت التخزين ورسوم حذف مبكر، انتبه للقواعد
- [ ] رسوم حركة العودة مرتفعة أيضًا، اجتهد في تحسين معدل إصابة CDN
- [ ] تحليل سجلات الوصول بانتظام، تنظيف الموارد غير المستخدمة
9. قوالب كود عملية
9.1 الرفع المباشر من الواجهة الأمامية إلى التخزين الكائني (JavaScript)
/**
* فئة أداة الرفع المباشر للتخزين الكائني
* الدعم: Alibaba Cloud OSS، Tencent Cloud COS، AWS S3
*/
class DirectUploader {
constructor(config) {
this.provider = config.provider // 'oss' | 'cos' | 's3'
this.region = config.region
this.bucket = config.bucket
this.getCredentials = config.getCredentials // دالة للحصول على بيانات الاعتماد المؤقتة
}
/**
* الحصول على بيانات اعتماد STS المؤقتة
*/
async fetchCredentials() {
// طلب بيانات اعتماد مؤقتة من الخادم الخلفي
const credentials = await this.getCredentials()
return {
accessKeyId: credentials.accessKeyId,
accessKeySecret: credentials.accessKeySecret,
sessionToken: credentials.securityToken || credentials.sessionToken,
expiration: credentials.expiration
}
}
/**
* إنشاء توقيع الرفع (للحساب من جانب الواجهة الأمامية)
*/
generateSignature(credentials, fileKey, fileType, options = {}) {
const timestamp = new Date().toISOString()
const date = timestamp.slice(0, 10).replace(/-/g, '')
// خوارزميات التوقيع تختلف قليلاً بين المزودين
switch (this.provider) {
case 'oss':
return this._ossSignature(credentials, fileKey, date, options)
case 'cos':
return this._cosSignature(credentials, fileKey, date, options)
case 's3':
return this._s3Signature(credentials, fileKey, date, options)
default:
throw new Error('Unknown provider')
}
}
/**
* رفع ملف واحد (ملفات صغيرة < 100 ميجابايت)
*/
async upload(file, options = {}) {
const credentials = await this.fetchCredentials()
const fileKey = this._generateFileKey(file, options.directory)
const formData = new FormData()
// بناء حقول النموذج (تختلف أسماء الحقول بين المزودين)
const formFields = this._buildFormFields(
credentials,
fileKey,
file.type,
options
)
Object.entries(formFields).forEach(([key, value]) => {
formData.append(key, value)
})
formData.append('file', file)
// إرسال طلب الرفع
const uploadUrl = this._getUploadUrl()
const response = await fetch(uploadUrl, {
method: 'POST',
body: formData,
// إذا كان الملف كبيرًا، قد تحتاج إلى تعيين مهلة أطول
signal: options.signal // دعم AbortController لإلغاء الرفع
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Upload failed: ${response.status} ${errorText}`)
}
return {
url: this._getFileUrl(fileKey),
key: fileKey,
etag: response.headers.get('ETag'),
size: file.size
}
}
/**
* رفع مجزأ (ملفات كبيرة > 100 ميجابايت)
*/
async multipartUpload(file, options = {}) {
const partSize = options.partSize || 10 * 1024 * 1024 // افتراضي 10 ميجابايت/جزء
const parallel = options.parallel || 3 // افتراضي 3 تزامن
const credentials = await this.fetchCredentials()
const fileKey = this._generateFileKey(file, options.directory)
// 1. تهيئة الرفع المجزأ
const uploadId = await this._initMultipartUpload(
credentials,
fileKey,
file.type
)
// 2. حساب الأجزاء
const parts = []
const totalParts = Math.ceil(file.size / partSize)
for (let i = 0; i < totalParts; i++) {
const start = i * partSize
const end = Math.min(start + partSize, file.size)
parts.push({
number: i + 1,
start,
end,
blob: file.slice(start, end)
})
}
// 3. رفع الأجزاء (مع تحكم في التزامن واستئناف بعد الانقطاع)
const uploadedParts = []
const failedParts = []
// دعم استئناف الرفع: التحقق من الأجزاء التي تم رفعها
if (options.resume) {
const existingParts = await this._listParts(
credentials,
fileKey,
uploadId
)
for (const part of existingParts) {
uploadedParts.push(part)
}
}
// تصفية الأجزاء غير المرفوعة
const pendingParts = parts.filter(
(p) => !uploadedParts.some((up) => up.partNumber === p.number)
)
// رفع متزامن
const uploadPart = async (part) => {
try {
const etag = await this._uploadPart(
credentials,
fileKey,
uploadId,
part
)
return { partNumber: part.number, etag }
} catch (error) {
failedParts.push({ part, error })
throw error
}
}
// استخدام Promise.all للتحكم في التزامن
const chunks = []
for (let i = 0; i < pendingParts.length; i += parallel) {
chunks.push(pendingParts.slice(i, i + parallel))
}
for (const chunk of chunks) {
const results = await Promise.allSettled(chunk.map(uploadPart))
for (const result of results) {
if (result.status === 'fulfilled') {
uploadedParts.push(result.value)
}
}
}
// التحقق من نجاح رفع جميع الأجزاء
if (uploadedParts.length !== totalParts) {
throw new Error(
`Upload incomplete: ${uploadedParts.length}/${totalParts} parts uploaded`
)
}
// 4. إكمال الرفع المجزأ (دمج الأجزاء)
await this._completeMultipartUpload(
credentials,
fileKey,
uploadId,
uploadedParts
)
return {
url: this._getFileUrl(fileKey),
key: fileKey,
size: file.size,
parts: totalParts
}
}
/**
* إنشاء مسار تخزين الملف
*/
_generateFileKey(file, directory = '') {
const date = new Date()
const datePath = `${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, '0')}/${String(date.getDate()).padStart(2, '0')}`
const random = Math.random().toString(36).substring(2, 10)
const ext = file.name.split('.').pop() || 'bin'
const key = directory
? `${directory}/${datePath}/${random}.${ext}`
: `${datePath}/${random}.${ext}`
return key
}
// ============ طرق خاصة بكل مزود ============
_getUploadUrl() {
switch (this.provider) {
case 'oss':
return `https://${this.bucket}.oss-${this.region}.aliyuncs.com`
case 'cos':
return `https://${this.bucket}.cos.${this.region}.myqcloud.com`
case 's3':
return `https://${this.bucket}.s3.${this.region}.amazonaws.com`
default:
throw new Error('Unknown provider')
}
}
_getFileUrl(key) {
return `https://${this.bucket}.${this.provider === 'oss' ? 'oss' : 'cos'}-${this.region}.${
this.provider === 'oss'
? 'aliyuncs.com'
: this.provider === 'cos'
? 'myqcloud.com'
: 'amazonaws.com'
}/${key}`
}
// طرق التوقيع والرفع المجزأ لكل مزود... (نفذ حسب الاحتياج الفعلي)
_buildFormFields(credentials, fileKey, fileType, options) {
// منطق بناء حقول النموذج لكل مزود
// يحتاج إلى التنفيذ حسب توثيق المزود المحدد
return {}
}
async _initMultipartUpload(credentials, fileKey, fileType) {
// منطق تهيئة الرفع المجزأ لكل مزود
return 'upload-id'
}
async _uploadPart(credentials, fileKey, uploadId, part) {
// منطق رفع الأجزاء لكل مزود
return 'etag'
}
async _completeMultipartUpload(credentials, fileKey, uploadId, parts) {
// منطق إكمال الرفع المجزأ لكل مزود
}
async _listParts(credentials, fileKey, uploadId) {
// منطق سرد الأجزاء المرفوعة لكل مزود
return []
}
}
// مثال استخدام
const uploader = new DirectUploader({
provider: 'oss',
region: 'cn-beijing',
bucket: 'myapp-images-prod',
getCredentials: async () => {
// طلب بيانات اعتماد مؤقتة من الخادم الخلفي
const res = await fetch('/api/upload/credentials')
return res.json()
}
})
// رفع ملف صغير
async function uploadAvatar(file) {
try {
const result = await uploader.upload(file, {
directory: 'avatars',
onProgress: (progress) => {
console.log(`تقدم الرفع: ${progress.percent}%`)
}
})
console.log('نجاح الرفع:', result.url)
return result
} catch (error) {
console.error('فشل الرفع:', error)
throw error
}
}
// رفع ملف كبير مجزأ
async function uploadVideo(file) {
try {
const result = await uploader.multipartUpload(file, {
directory: 'videos',
partSize: 10 * 1024 * 1024, // 10 ميجابايت لكل جزء
parallel: 3, // 3 تزامن
resume: true, // دعم استئناف الرفع بعد الانقطاع
onProgress: (progress) => {
console.log(
`تقدم الرفع: ${progress.percent}%, تم رفع ${progress.loaded}/${progress.total}`
)
},
onPartComplete: (part) => {
console.log(`اكتمل رفع الجزء ${part.number}`)
}
})
console.log('نجاح الرفع:', result.url)
return result
} catch (error) {
console.error('فشل الرفع:', error)
// يمكن تنفيذ منطق إعادة المحاولة أو حفظ معلومات نقطة الانقطاع هنا
throw error
}
}9.2 خدمة بيانات الاعتماد المؤقتة في الخادم الخلفي (Node.js/Express)
/**
* خدمة بيانات اعتماد STS المؤقتة للتخزين الكائني
* الدعم: Alibaba Cloud OSS، Tencent Cloud COS، AWS S3
*/
const express = require('express')
const STS = require('ali-oss').STS // Alibaba Cloud
// const COS = require('cos-nodejs-sdk-v5') // Tencent Cloud
const router = express.Router()
// التكوين
const config = {
// تكوين Alibaba Cloud OSS
oss: {
accessKeyId: process.env.OSS_ACCESS_KEY_ID,
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
region: 'oss-cn-beijing',
bucket: 'myapp-images-prod',
// دور STS ARN (يحتاج إلى إنشاء في لوحة تحكم RAM)
roleArn: process.env.OSS_STS_ROLE_ARN
}
}
/**
* الحصول على بيانات اعتماد STS المؤقتة (Alibaba Cloud OSS)
* POST /api/upload/credentials
*/
router.post('/credentials', async (req, res) => {
try {
// 1. التحقق من هوية المستخدم (نفذ حسب الحالة الفعلية)
const userId = req.user?.id
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' })
}
// 2. إنشاء بادئة فريدة لمسار الملف (لعزل الصلاحيات)
const date = new Date()
const prefix = `uploads/${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, '0')}/${userId}/`
// 3. إنشاء عميل STS
const sts = new STS({
accessKeyId: config.oss.accessKeyId,
accessKeySecret: config.oss.accessKeySecret
})
// 4. طلب بيانات اعتماد مؤقتة
const result = await sts.assumeRole(
config.oss.roleArn,
{
// تقييد نطاق الصلاحيات بالسياسة (مبدأ الحد الأدنى من الصلاحيات)
Statement: [
{
Effect: 'Allow',
Action: [
'oss:PutObject',
'oss:InitiateMultipartUpload',
'oss:UploadPart',
'oss:CompleteMultipartUpload',
'oss:AbortMultipartUpload',
'oss:ListParts'
],
Resource: [`acs:oss:*:*:${config.oss.bucket}/${prefix}*`]
}
],
Version: '1'
},
3600, // صلاحية بيانات الاعتماد ساعة واحدة
'web-upload-session-' + Date.now()
)
// 5. إعادة بيانات الاعتماد والتكوين
res.json({
success: true,
data: {
// بيانات اعتماد STS المؤقتة
credentials: {
accessKeyId: result.credentials.AccessKeyId,
accessKeySecret: result.credentials.AccessKeySecret,
sessionToken: result.credentials.SecurityToken,
expiration: result.credentials.Expiration
},
// تكوين الرفع
config: {
provider: 'oss',
region: config.oss.region,
bucket: config.oss.bucket,
endpoint: `https://${config.oss.bucket}.${config.oss.region}.aliyuncs.com`,
prefix: prefix, // بادئة مسار الملف
// قيود الأمان
maxSize: 100 * 1024 * 1024, // الحد الأقصى 100 ميجابايت
allowedTypes: [
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'video/mp4'
]
}
}
})
} catch (error) {
console.error('Get credentials failed:', error)
res.status(500).json({
success: false,
error: 'Failed to get upload credentials',
message: error.message
})
}
})
/**
* إشعار معاودة الاتصال: بعد اكتمال رفع الواجهة الأمامية، إعلام الخادم الخلفي
* POST /api/upload/callback
*/
router.post('/callback', async (req, res) => {
try {
const { key, etag, size, mimeType, originalName } = req.body
const userId = req.user?.id
// 1. التحقق من وجود الملف
// 2. حفظ معلومات الملف في قاعدة البيانات
const fileRecord = await db.files.create({
userId,
key,
etag,
size,
mimeType,
originalName,
url: `https://cdn.example.com/${key}`,
createdAt: new Date()
})
// 3. معالجة غير متزامنة: إنشاء صور مصغرة، استخراج البيانات الوصفية، مراجعة المحتوى إلخ
await processFileAsync(fileRecord)
res.json({
success: true,
data: {
fileId: fileRecord.id,
url: fileRecord.url,
size: fileRecord.size
}
})
} catch (error) {
console.error('Upload callback failed:', error)
res.status(500).json({
success: false,
error: 'Failed to process uploaded file'
})
}
})
module.exports = router9.3 منع سرقة الروابط وتكوين الأمان
/**
* مثال تكوين منع سرقة الروابط والأمان لـ CDN
*/
// 1. منع سرقة الروابط بـ Referer (منع المواقع الأخرى من الإشارة مباشرة إلى مواردك)
const refererConfig = {
// نمط القائمة البيضاء: السماح فقط لـ Referer التالية بالوصول
allowList: [
'*.myapp.com', // الموقع الرئيسي
'*.myapp.cn', // الموقع المحلي
'localhost:*', // التطوير المحلي
'127.0.0.1:*'
],
// نمط القائمة السوداء (اختياري): حظر Referer التالية
blockList: [
'*.competitor.com', // المنافسون
'spam-site.com'
],
// معالجة Referer الفارغ: هل يُسمح بالوصول المباشر (كتابة URL في شريط عنوان المتصفح)
allowEmptyReferer: false // بيئة الإنتاج يُنصح false، بيئة الاختبار يمكن true
}
// 2. توثيق URL (منع سرقة روابط أكثر أمانًا، مع طابع زمني وتوقيع)
class URLAuth {
constructor(config) {
this.key = config.key // مفتاح التوثيق، يُحفظ فقط في جانب الخادم
this.expireTime = config.expireTime || 3600 // افتراضي ساعة واحدة صلاحية
}
/**
* إنشاء URL مع توثيق
* @param {string} url - URL الأصلي، مثل https://cdn.example.com/images/photo.jpg
* @param {number} expireIn - مدة الصلاحية (بالثواني)
* @returns {string} URL مع معاملات التوثيق
*/
sign(url, expireIn = this.expireTime) {
const urlObj = new URL(url)
const pathname = urlObj.pathname
const timestamp = Math.floor(Date.now() / 1000) + expireIn
// بناء سلسلة التوقيع (تختلف الصيغة بين المزودين، هذا مثال عام)
const signStr = `${pathname}-${timestamp}-${this.key}`
const signature = this._md5(signStr)
// إضافة معاملات التوثيق
urlObj.searchParams.set('sign', signature)
urlObj.searchParams.set('t', timestamp.toString())
return urlObj.toString()
}
/**
* التحقق من توقيع URL (للاستخدام في طرف CDN أو الخادم المصدر)
*/
verify(url) {
const urlObj = new URL(url)
const signature = urlObj.searchParams.get('sign')
const timestamp = parseInt(urlObj.searchParams.get('t'))
const pathname = urlObj.pathname
// التحقق من انتهاء الصلاحية
if (timestamp < Math.floor(Date.now() / 1000)) {
return { valid: false, error: 'URL expired' }
}
// التحقق من التوقيع
const signStr = `${pathname}-${timestamp}-${this.key}`
const expectedSign = this._md5(signStr)
if (signature !== expectedSign) {
return { valid: false, error: 'Invalid signature' }
}
return { valid: true }
}
_md5(str) {
// في المشاريع الفعلية، استخدم crypto-js أو مكتبات MD5 أخرى
// هذا مثال فقط
return require('crypto').createHash('md5').update(str).digest('hex')
}
}
// مثال استخدام
const auth = new URLAuth({
key: 'your-secret-key-only-known-by-server',
expireTime: 3600 // ساعة واحدة صلاحية
})
// جانب الخادم ينشئ URL موقعًا
const signedUrl = auth.sign(
'https://cdn.example.com/private/document.pdf',
7200
)
// النتيجة: https://cdn.example.com/private/document.pdf?sign=xxxxx&t=1699123456
// طرف CDN أو الخادم المصدر يتحقق
const result = auth.verify(signedUrl)
if (!result.valid) {
// إرجاع 403 Forbidden
}
// 3. القائمة البيضاء/السوداء لعناوين IP
const ipConfig = {
// السماح فقط لعناوين IP محددة (مناسب للأنظمة الداخلية)
whiteList: [
'192.168.1.0/24', // نطاق الشبكة الداخلية
'10.0.0.0/8'
],
// حظر عناوين IP محددة (حظر المهاجمين)
blackList: ['1.2.3.4', '5.6.7.8']
}
// 4. القائمة البيضاء/السوداء لـ UA (User-Agent)
const uaConfig = {
// حظر برامج الزحف/أدوات التنزيل
blackList: [
'Wget',
'curl',
'python-requests',
'Scrapy',
'AhrefsBot',
'SemrushBot'
],
// السماح فقط للمتصفحات (نمط صارم)
whiteList: [
'Mozilla/*', // المتصفحات الحديثة
'AppleWebKit/*'
]
}10. جدول المصطلحات
| المصطلح الإنجليزي | المقابل العربي | الشرح |
|---|---|---|
| Object Storage | التخزين الكائني | بنية تخزين بيانات تدير البيانات ككائنات، بدلاً من بنية نظام الملفات الهرمي. مناسبة لتخزين الصور والفيديو والنسخ الاحتياطي والبيانات غير المنظمة. |
| Bucket | حاوية التخزين | الحاوية العليا في التخزين الكائني، تُستخدم لتنظيم وعزل البيانات. لكل حاوية تحكم مستقل في الصلاحيات والتكوين. |
| Object | كائن/كائن ملف | الوحدة الأساسية في التخزين الكائني، تحتوي على البيانات نفسها والبيانات الوصفية (Metadata) ومفتاح فريد عالمي (Key). |
| CDN | شبكة توصيل المحتوى | Content Delivery Network، من خلال نشر عقد طرفية حول العالم، تخزين محتوى الموقع مؤقتًا في أقرب موقع للمستخدم، لتسريع سرعة الوصول. |
| Edge Node | عقدة طرفية | خوادم تخزين مؤقت منتشرة في مواقع مختلفة في شبكة CDN، تقدم خدمة وصول المحتوى مباشرة للمستخدمين. |
| Origin | الخادم المصدر | الخادم الذي تعود إليه CDN للحصول على المحتوى، يمكن أن يكون تخزينًا كائنيًا أو ECS أو خادمًا ذاتي البناء. |
| Cache Hit | إصابة الذاكرة المؤقتة | المحتوى المطلوب من المستخدم موجود مسبقًا في عقدة CDN الطرفية، يُعاد مباشرة دون حاجة للعودة إلى المصدر. |
| Cache Miss | عدم إصابة الذاكرة المؤقتة | العقدة الطرفية لا تحتوي على المحتوى المطلوب، تحتاج إلى العودة للمصدر للحصول عليه. |
| Hit Ratio | معدل الإصابة | نسبة مرات إصابة الذاكرة المؤقتة إلى إجمالي عدد الطلبات. كلما ارتفع معدل الإصابة، قلت العودة للمصدر، وقلت التكلفة. |
| TTL | مدة البقاء/وقت التخزين المؤقت | Time To Live، مدة صلاحية المحتوى المخزن مؤقتًا على عقدة CDN. بعد انتهاء الصلاحية، يحتاج إلى العودة للمصدر مرة أخرى. |
| Back to Source | العودة إلى المصدر | عملية طلب عقدة CDN الطرفية للمحتوى من الخادم المصدر. |
| Purge/Refresh | مسح الذاكرة المؤقتة | إجبار ذاكرة CDN المؤقتة على عدم الصلاحية، ليحصل الطلب التالي على أحدث محتوى من المصدر. |
| Preheat | تسخين | قبل النشر الرسمي، دفع المحتوى بنشاط إلى عقد CDN، ليتمكن المستخدم من إصابة الذاكرة المؤقتة في أول زيارة. |
| CORS | مشاركة الموارد عبر الأصول | Cross-Origin Resource Sharing، آلية أمان في المتصفح، تتحكم في وصول الموارد بين النطاقات المختلفة. |
| Referer | صفحة المصدر | حقل في رأس طلب HTTP، يشير إلى الصفحة التي جاء منها الطلب. يُستخدم لمنع سرقة الروابط. |
| STS | خدمة الرمز الآمن | Security Token Service، خدمة تصدر بيانات اعتماد وصول مؤقتة، تُستخدم في سيناريوهات مثل الرفع المباشر من الواجهة الأمامية. |
| Multipart Upload | رفع مجزأ | تقسيم الملفات الكبيرة إلى أجزاء صغيرة متعددة للرفع المتوازي، مع دعم استئناف الرفع بعد الانقطاع، مما يحسن كفاءة وموثوقية الرفع. |
| ETag | علامة الكيان | رأس استجابة HTTP، يُستخدم لتعريف إصدار محدد من المورد، شائع الاستخدام في التحقق من الذاكرة المؤقتة. |
| S3 API | واجهة S3 المتوافقة | مواصفة API للتخزين الكائني من AWS S3، معظم مزودي السحابة للتخزين الكائني متوافقون مع هذه الواجهة. |
| Canonical Query String | سلسلة استعلام موحدة | جزء من سلسلة التوقيع، تُستخدم لحساب توقيع الطلب، لضمان عدم التلاعب بالطلب. |
الخلاصة: القواعد الذهبية للتخزين الكائني + CDN
- الرفع عبر المسار المباشر: الملفات الكبيرة بالتجزئة، الأمان بـ STS
- التخزين المؤقت متعدد الطبقات: المتصفح -> CDN -> الخادم المصدر، طبقة تلو الأخرى
- خدمة المستخدم من أقرب نقطة: DNS ذكي + تغطية عقد عالمية
- الأمان بلا تهاون: HTTPS + منع سرقة الروابط + التحكم في الوصول
- مراقبة التكاليف: معدل الإصابة، عرض النطاق، تقسيم التخزين، تحسين مستمر
هذه البنية تدعم الغالبية العظمى من وصول الموارد الثابتة على الإنترنت، وفهمها يعني أنك فهمت حجر الأساس لتحسين أداء الويب الحديث.