Caching یا کشینگ به معنی ذخیره‌سازی موقت خروجی محاسبات یا داده‌های پرمصرف برای کاهش زمان پاسخ و فشار روی منبع اصلی است. کش می‌تواند در مرورگر، CDN، برنامه، حافظه سرور یا دیتابیس وجود داشته باشد.

چه چیزی را کش کنیم؟

در یک فروشگاه، فهرست دسته‌بندی‌ها و محصول پرفروش برای کش مناسب‌اند، ولی قیمت نهایی پرداخت و موجودی حساس باید سیاست تازگی داده روشنی داشته باشند. کش، منبع نهایی حقیقت نیست مگر اینکه معماری صریحاً خلاف آن را طراحی کرده باشد.

ابزارها و لایه‌ها

ابزار یا لایهکاربردنکته
ردیسکش توزیع‌شده، صف، داده ساختمندپشتیبانی TTL و انواع داده
مم‌کش‌دیکش ساده توزیع‌شده در حافظهساختار ساده و سرعت بالا
APCuکش محلی پروسس‌های PHPاشتراک بین سرورها ندارد
Caffeineکش پرکاربرد در JVMمناسب کش درون برنامه جاوا
IMemoryCacheکش درون پردازش در ASP.NET Coreدر چند سرور نیازمند راهبرد تکمیلی
شبکه توزیع محتواکش دارایی و بعضی پاسخ‌های HTTPمدیریت هدر و Purge
Varnish / NginxReverse Proxy Cacheمناسب پاسخ‌های قابل کش

نمونه لاراول با Cache::remember

use Illuminate\Support\Facades\Cache;
$products = Cache::remember('catalog:featured', 300, function () {
    return Product::query()->where('featured', true)->get();
});
Cache::forget('catalog:featured');

Python با Redis

import redis
client = redis.Redis(host='localhost', port=6379, decode_responses=True)
key = 'catalog:featured'
value = client.get(key)
if value is None:
    value = '{"products":[1,2,3]}'  # computed from the source
    client.set(key, value, ex=300)

Go با Redis

ctx := context.Background()
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
if err := rdb.Set(ctx, "catalog:featured", "cached result", 5*time.Minute).Err(); err != nil {
    log.Fatal(err)
}
value, err := rdb.Get(ctx, "catalog:featured").Result()

ASP.NET Core با IMemoryCache

builder.Services.AddMemoryCache();
// In a service receiving IMemoryCache cache via DI:
var products = cache.GetOrCreate("featured-products", entry => {
    entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
    return LoadFeaturedProducts();
});

روش‌های به‌روزرسانی کش

  • Cache-aside: برنامه ابتدا کش را می‌خواند و در Miss سراغ دیتابیس می‌رود.
  • Write-through: هنگام نوشتن، منبع و کش هماهنگ می‌شوند.
  • Write-behind: نوشتن در منبع اصلی با تاخیر انجام می‌شود و به تضمین ماندگاری نیاز دارد.
  • TTL و Invalidation: برای جلوگیری از باقی‌ماندن داده قدیمی باید سیاست روشن باشد.

نکته فنی

وقتی کلید پرطرفدار همزمان برای هزار درخواست منقضی شود، کش استمپید رخ می‌دهد. قفل بازسازی، Jitter در TTL و Stale-While-Revalidate از راهکارها هستند. برای آشنایی با راهکارهای مقابله و مثال قفل‌گذاری، صفحه کش استمپید را مطالعه کنید.

اصطلاحات مرتبط: کش اینولیدیشن، کش استمپید، ردیس، مم‌کش‌دی، هدرهای HTTP، کنترل کش HTTP، شبکه توزیع محتوا.

برای بررسی راهکارهای قفل کش، زمان انقضای تصادفی و بازسازی پیش‌دستانه، مقاله روش‌های جلوگیری از Cache Stampede همراه با مثال در باورژن را مطالعه کنید.