كلاود
أدلة

استراتيجيات الكاش لتطبيقات الويب: دليل المطور

كلاود|٢١ فبراير ٢٠٢٦|آخر تحديث ٦ سبتمبر ٢٠٢٦|4 دقائق قراءة|٥٠١ مشاهدة
استراتيجيات الكاش لتطبيقات الويب: دليل المطور

Browser cache، CDN cache، application cache، database cache — 4 طبقات كاش. نشرح كل واحدة ومتى تستخدمها.

لماذا التخزين المؤقت ضروري؟

كل تطبيق ويب ناجح يصطدم في نهاية المطاف بنفس التحدي: عدد الزيارات يزيد، لكن قاعدة البيانات والسيرفر لا يتحملان. الحل ليس دائماً ترقية المواصفات — بل غالباً هو تطبيق استراتيجية تخزين مؤقت (caching) مدروسة.

التخزين المؤقت الجيد يخفض استهلاك الموارد بنسبة 70-90%، ويحسن زمن الاستجابة من مئات الملليثواني إلى دون 10ms.

المستويات السبعة للـ Caching

المستوى 1: Browser Cache

المتصفح يخزن الملفات محلياً على جهاز المستخدم.

# nginx: تحديد مدة cache للمتصفح
location ~* \.(css|js)$ {
 expires 1y;
 add_header Cache-Control "public, immutable";
}

location ~* \.(jpg|png|gif|webp)$ {
 expires 6M;
 add_header Cache-Control "public";
}

location = /index.html {
 expires -1;
 add_header Cache-Control "no-cache, no-store";
}

المستوى 2: CDN Cache

# Cloudflare Cache-Control headers
# يُعيد استخدام Nginx headers أعلاه
# أو تحديدها في Cloudflare Transform Rules

المستوى 3: Application Cache (Redis)

// Laravel: Cache الصفحات الكاملة
Route::get('/pricing', function {
 return Cache::remember('page:pricing', 3600, function {
 return Inertia::render('Pricing', [
 'plans' => Plan::with('features')->get,
 ]);
 });
});

// أو استخدام HTTP Cache Headers
return response
 ->view('pricing')
 ->header('Cache-Control', 'public, max-age=3600');

المستوى 4: Query Cache

// Cache نتائج الاستعلامات الثقيلة
$stats = Cache::remember('dashboard:stats', 300, function {
 return [
 'total_users' => User::count,
 'active_servers' => Server::where('status', 'active')->count,
 'monthly_revenue' => Invoice::thisMonth->sum('amount'),
 ];
});

// Cache مع Tags لإمكانية المسح الانتقائي
Cache::tags(['products'])->remember("product:{$id}", 86400, function use ($id) {
 return Product::with(['category', 'specs', 'pricing'])->find($id);
});

المستوى 5: Object Cache

// تخزين كائنات PHP مسبقاً
class UserRepository
{
 public function find(int $id): User
 {
 return Cache::remember(
 "user:{$id}",
 1800,
 fn => User::with('permissions', 'subscription')->findOrFail($id)
 );
 }

 public function clearCache(int $id): void
 {
 Cache::forget("user:{$id}");
 }
}

المستوى 6: Full-Page Cache

// Middleware للـ full-page cache
class CacheResponse
{
 public function handle(Request $request, Closure $next): Response
 {
 // لا تُخزن طلبات POST أو صفحات المستخدم
 if ($request->method !== 'GET' || $request->user) {
 return $next($request);
 }

 $cacheKey = 'page:' . md5($request->url);

 if (Cache::has($cacheKey)) {
 return response(Cache::get($cacheKey));
 }

 $response = $next($request);
 Cache::put($cacheKey, $response->getContent, 3600);

 return $response;
 }
}

المستوى 7: Computed/Memoization Cache

// Memoize نتائج حسابات ثقيلة في نفس الطلب
class PricingCalculator
{
 private array $memo = [];

 public function calculate(array $config): float
 {
 $key = md5(serialize($config));

 if (!isset($this->memo[$key])) {
 $this->memo[$key] = $this->doHeavyCalculation($config);
 }

 return $this->memo[$key];
 }
}

استراتيجيات الـ Cache Invalidation

1. TTL (Time-To-Live) — الأبسط

// البيانات تنتهي صلاحيتها تلقائياً بعد المدة
Cache::put('data', $value, 3600); // ساعة واحدة
Cache::put('data', $value, now->addDays(7)); // أسبوع

الإيجابيات: بسيط، لا يحتاج كوداً إضافياً السلبيات: بيانات قديمة حتى انتهاء الـ TTL

2. Cache Tags — للبيانات المترابطة

// تخزين
Cache::tags(['posts', "user:{$userId}"])->put(
 "posts:user:{$userId}",
 $posts,
 3600
);

// مسح كل cache مستخدم معين
Cache::tags(["user:{$userId}"])->flush;

// مسح كل posts
Cache::tags(['posts'])->flush;

3. Event-Driven Invalidation — الأدق

// عند تحديث المنتج، امسح cache تلقائياً
class Product extends Model
{
 protected static function booted: void
 {
 static::saved(function (Product $product) {
 Cache::forget("product:{$product->id}");
 Cache::tags(['products'])->flush;
 });
 }
}

جدول اختيار مدة الـ Cache

نوع البيانات مدة Cache المناسبة
إعدادات التطبيق 24 ساعة أو أكثر
قوائم المنتجات 1-6 ساعات
بيانات مستخدم 15-30 دقيقة
نتائج بحث 5-10 دقائق
إحصائيات لوحة تحكم 5 دقائق
بيانات الجلسة مدة الجلسة
بيانات API خارجية 1 دقيقة - 1 ساعة

Cache على سيرفرات كلاود

سيرفرات كلاود (cloud.net.sa) تستخدم SSD NVMe عالية السرعة، مما يجعل Redis يعمل بأقصى كفاءة. مع إضافة RAM بـ 600 ريال لكل 2GB، يمكنك توسيع Cache بسهولة حسب نمو تطبيقك.

التوصية: خصص على الأقل 20% من RAM للـ Redis cache. لسيرفر 8GB RAM، هذا يعني تخصيص 1.5-2GB لـ Redis.

# تعديل Redis maxmemory
redis-cli config set maxmemory 1500mb
redis-cli config set maxmemory-policy allkeys-lru

أخطاء Cache الشائعة

Cache Stampede

// المشكلة: ألف طلب في نفس اللحظة عند انتهاء Cache
// الحل: Cache Lock

$value = Cache::lock("rebuild:product:{$id}", 10)->get(function use ($id) {
 return Cache::remember("product:{$id}", 3600, function use ($id) {
 return Product::expensive->find($id);
 });
});

Cache Poisoning

// لا تخزن بيانات المستخدم في cache عام
// خطأ:
Cache::put('homepage', view('home', ['user' => auth->user]));

// صواب:
if (!auth->check) {
 Cache::put('homepage:guest', view('home'));
}

خلاصة

الـ Caching الجيد يحوّل تطبيقاً بطيئاً إلى تطبيق سريع بدون لمس الكود الأصلي في كثير من الأحيان. ابدأ بـ Query Cache، ثم Object Cache، وأخيراً Full-Page Cache إذا احتجت.


ابدأ الآن

جاهز تبني مشروعك؟ اختر خادمك السحابي بالمواصفات اللي يحتاجها تطبيقك، أو راجع الباقات والأسعار.

مشاركة