آنچه Next.js به‌صورت پیش‌فرض در اختیار شما قرار می‌دهد

  • کش داده (Data cache) – در Next.js 13 به بالا، هر فراخوانی fetch() در یک حافظه کشِ مخصوص هر درخواست (per-request memory cache) قرار می‌گیرد. افزودن گزینه revalidate به زمان اجرا (runtime) می‌گوید که داده‌ها را پس از یک بازه زمانی مشخص به‌روزرسانی کند؛ این کار باعث می‌شود یک فراخوانی API گرم (hot) تنها در صورت نیاز به یک فراخوانی سرد (cold) تبدیل شود.
  • کش کامل مسیر (Full-route cache) – این فریم‌ورک HTML رندر شده و داده‌های مورد نیاز برای یک مسیر کامل را ذخیره می‌کند. بازدیدکنندگان مجدد، انتقال آنی را تجربه می‌کنند زیرا سرور از رندر مجدد صرف‌نظر می‌کند.
  • ISR – صفحات استاتیک در پس‌زمینه بازسازی می‌شوند، در حالی که نسخه قدیمی همچنان به پاسخگویی به ترافیک ادامه می‌دهد. این قابلیت به شما اجازه می‌دهد یک سایت بزرگ را بدون نیاز به بازسازی کامل (rebuild) در هر بار تغییر محتوا، استاتیک نگه دارید.
  • تابع cache() در Server Component – ابزار کمکی cache در React، محاسبات سنگین یا اتصالات پایگاه داده را برای مدت زمان یک درخواست واحد ذخیره (memoize) می‌کند و از انجام کارهای تکراری در درخت کامپوننت‌های یک صفحه جلوگیری می‌نماید.

این کش‌ها مشکل «اولین برخورد» (first-hit) را حل می‌کنند، اما همچنان درون فرآیند Node قرار دارند. برای محافظت از سرور و پایگاه داده، لایه‌های کش را به سمت بیرون گسترش دهید.

لایه‌های خارجی که می‌توانید اضافه کنید

لایه چه چیزی را ذخیره می‌کند ابزار معمول چگونه کمک می‌کند
CDN دارایی‌های استاتیک، HTML، JSON مربوط به API Cloudflare, Akamai, AWS CloudFront محتوا را به مکان‌های لبه (edge locations) منتقل می‌کند و زمان رفت و برگشت (round-trip) به کاربر را کاهش می‌دهد
Reverse proxy پاسخ‌های کامل صفحه پیش از رسیدن به Node Nginx, Varnish صفحات کش‌شده را مستقیماً ارائه می‌دهد و بار روی نمونه (instance) Next.js را کاهش می‌دهد
کش در سطح اپلیکیشن نتایج پرس‌وجوهای سنگین پایگاه داده یا فراخوانی‌های API Redis, Memcached یک ذخیره‌ساز سریع کلید-مقدار (key-value) فراهم می‌کند که با ری‌استارت شدن سرور از بین نمی‌رود و می‌تواند بین چندین نمونه اپلیکیشن به اشتراک گذاشته شود

هر لایه از پایگاه داده اصلی فاصله بیشتری دارد، بنابراین اگر در یک سطح کش یافت نشود (miss)، این موضوع به لایه بعدی سرایت می‌کند و در نهایت، تنها زمانی به پایگاه داده می‌رسد که کاملاً ضروری باشد.

تازه نگه داشتن کش‌ها

ابطال کش (Invalidation) معمولاً تیم‌ها را به چالش می‌کشد. سه الگوی کاربردی به خوبی عمل می‌کنند:

  • مبتنی بر زمان (TTL) – یک زمان انقضای ثابت برای یک ورودی کش تعیین کنید. پیکربندی آن ساده است اما می‌تواند تا زمانی که تایمر تمام شود، داده‌های قدیمی را ارائه دهد.
  • رویداد-محور (Event-driven) – به CMS خود یا هر منبع داده‌ای که هنگام تغییر محتوا یک webhook ارسال می‌کند، متصل شوید. این webhook باعث پاکسازی (purge) ورودی کش مربوطه می‌شود.
  • مبتنی بر تگ (Tag-based) – یک تگ منطقی به گروهی از فراخوانی‌ها (مثلاً product-list) اختصاص دهید. وقتی هر آیتمی در آن گروه تغییر کند، یک فراخوانی واحد از revalidateTag('product-list') تمام ورودی‌هایی که دارای آن تگ هستند را پاک می‌کند.

ترکیب این روش‌ها به شما اجازه می‌دهد بین تازگی داده‌ها و نرخ برخورد با کش (cache-hit rates) تعادل برقرار کنید.

سلسله‌مراتبی که برای اکثر تیم‌ها کارآمد است

  1. کش مرورگر – دارایی‌های استاتیک (CSS، JS، تصاویر) دارای max-age طولانی هستند تا دستگاه کاربر دیگر هرگز از شبکه درخواست نکند.
  2. CDN – گره‌های لبه (Edge nodes)، صفحات کامل HTML و JSON مربوط به API را کش می‌کنند و به هدرهای Cache-Control که در Next.js تنظیم کرده‌اید، احترام می‌گذارند.
  3. Reverse proxy – یک نمونه Nginx یا Varnish در جلوی سرور Next.js قرار می‌گیرد و پاسخ‌های کش‌شده را برای مسیرهایی که به ندرت تغییر می‌کنند، ارائه می‌دهد.
  4. کش داخلی Next.js – کش‌های داده و مسیرِ این فریم‌ورک، وظیفه memoization در هر درخواست و ISR را بر عهده دارند.
  5. کش اپلیکیشن – Redis نتایج پرس‌وجوهای سنگین پایگاه داده را با کلیدهایی بر اساس پارامترهای پرس‌وجو یا تگ‌ها ذخیره می‌کند.
  6. پایگاه داده – منبع نهایی حقیقت (source of truth) که تنها در صورت عدم وجود داده در تمام سطوح بالاتر، از آن پرس‌وجو می‌شود.

وقتی درخواستی می‌رسد، این لیست را طی می‌کند تا زمانی که یک لایه به آن پاسخ دهد. سریع‌ترین پاسخ برنده است و پاسخ برای برخورد‌های بعدی، در طول زنجیره به سمت بالا نوشته (ذخیره) می‌شود.

جمع‌بندی و پیاده‌سازی

  1. هدرهای Cache-Control را در مسیرهای API خود تنظیم کنید
  2. CDN خود را پیکربندی کنید – کش کردن در لبه (edge caching) را برای نقاط انتهایی (endpoints) HTML و JSON فعال کنید و مطمئن شوید که CDN به Cache-Control احترام می‌گذارد.
  3. یک reverse proxy مستقر کنید – Nginx را در جلوی سرور Next.js خود قرار دهید.
  4. Redis را اضافه کنید – نتایج پرس‌وجوهای سنگین پایگاه داده را کش کنید.
  5. از revalidateTag در کامپوننت‌های خود استفاده کنید – تابع revalidateTag را برای پاکسازی کش داخلی Next.js برای یک تگ خاص فراخوانی کنید.

نکته نهایی

یک کش واحد در داخل Next.js سرعت اولین درخواست را بالا می‌برد، اما مقیاس‌پذیری واقعی از یک پشته (stack) منضبط حاصل می‌شود: مرورگر ← CDN ← reverse proxy ← فریم‌ورک ← Redis ← پایگاه داده. هر لایه را پیکربندی کنید، ابطال کش را با استفاده از زمان، رویدادها و تگ‌ها مدیریت کنید و معیارهای (metrics) خود را زیر نظر بگیرید. در این صورت، تأخیر (latency) پایین می‌ماند و بک‌اند شما در برابر جهش‌های ترافیکی مقاوم خواهد بود.