Cache چیست؟ انواع Cache، کاربردها و اینکه چه زمانی واقعاً به آن نیاز داریم
کش چیست، تفاوت Browser و CDN و Application و Database Cache، نقش Redis و HTTP Cache-Control و TTL، سختی invalidation، دادهٔ کهنه، و اینکه چه زمانی کش لازم نیست یا مشکل میسازد.
بنیانگذار و مهندس محصول
وقتی صفحهای دیر باز میشود، نسخهٔ اول معمولاً این است: «یک Cache بگذارید.» گاهی درست است. گاهی فقط لایهٔ تازهای از دادهٔ کهنه، باگ امنیتی و هزینهٔ عملیاتی میسازد — بدون اینکه گلوگاه واقعی لمس شود.
کش (Cache) کپیِ موقتِ نتیجهای است که تولید دوبارهاش گران است: پرسوجوی پایگاه داده، رندر HTML، پاسخ API، یا فایل استاتیک. هدف کاهش تأخیر و بار مبدأ است، نه جایگزینی منبع حقیقت. این راهنما تعریف، Hit/Miss، لایهها، TTL، ابطال، کهنگی، و خطی را میگذارد که کش از کمک به آسیب عبور میکند.
پاسخ کوتاه
کش ذخیرهٔ نزدیکتر و معمولاً فرّاری است که پاسخ قبلی را دوباره به کار میبرد تا مبدأ کار تکراری نکند. پیدا شدن پاسخ Cache Hit است؛ نبودنش Cache Miss است و باید از منبع اصلی ساخته شود. ارزش کش با نرخ Hit، هزینهٔ Miss و تحمل کهنگی تعیین میشود — نه با وجود Redis در معماری.
کش مرورگر و CDN برای دارایی عمومی قویاند. کش برنامه و Redis برای خواندن پرتکرار روی دادهٔ نسبتاً پایدار مناسباند. HTTP Caching طبق RFC 9111 با Cache-Control تازگی، اعتبارسنجی و اشتراکپذیری را کنترل میکند. کش را وقتی اضافه کنید که اندازهگیری گلوگاه مبدأ یا شبکه را نشان دهد و کهنگی قابلقبول تعریف شده باشد.
کش سرعت میخرد و تازگی میفروشد. اگر قیمت تازگی را ندانید، معامله را نباختهاید — اصلاً معامله را نفهمیدهاید.
کش چه مشکلی را حل میکند؟
هر درخواست میتواند از شبکه بگذرد، سرور را بیدار کند، نشست را باز کند، به پایگاه برود و قالب را رندر کند. اگر هزار کاربر همان کاتالوگ را ببینند، تکرار این مسیر اسراف است. مشکل «کندی» بهتنهایی نیست؛ تکرار کار گران است. اگر خواندن یک ردیف ایندکسشده روی ماشین خلوت ارزان باشد، پیچیدگی کش از سودش بیشتر میشود.
کش منبع حقیقت نیست. سفارش، موجودی قطعی و ماندهٔ حساب باید در پایگاه با دوام بمانند. کش میتواند نمای سریع همان داده را بدهد، به شرط سیاست انقضا و ابطال روشن. یکی دانستن این دو لایه، در طراحی و در حادثه، گران تمام میشود.
Cache Hit، Cache Miss و معنی عملی نرخ
Hit یعنی پاسخ از کش آمده و مسیر سنگین تکرار نشده. Miss یعنی چیزی قابلاستفاده نبود و باید ساخته شود؛ بعد معمولاً برای بعد ذخیره میشود. نسبت Hit به کل درخواستها نرخ اصابت است. نرخ ۹۵٪ فقط وقتی باارزش است که ۵٪ باقی سیستم را خفه نکند. اگر Missها بعد از انقضای یک کلید محبوب همزمان رخ دهند، مبدأ همان باری را میبیند که کش پنهان میکرد؛ به این هجوم Cache Stampede یا Thundering Herd میگویند.
معیار بهتر از درصد خام: تأخیر صدک ۹۵ مسیر خواندن، بار مبدأ قبل و بعد، و پنجرهٔ قابلتحمل کهنگی. کشی که Hit زیاد دارد ولی قیمت کهنه نشان میدهد، از نظر محصول شکست است حتی اگر نمودار زیرساخت سبز باشد.
لایههای کش؛ یک چیز نیستند
کلمهٔ «کش» چند مکان متفاوت را میپوشاند. ابطال، دامنهٔ اشتراک و پیامد امنیتیشان یکی نیست. بپرسید: این کپی مال یک کاربر است یا همه؟ نزدیک مرورگر است یا نزدیک سرور؟ با HTTP کنترل میشود یا با کد برنامه؟
کش مرورگر (Browser Cache)
مرورگر پاسخ را برای همان کاربر نگه میدارد. راهنمای HTTP caching در MDN این را کش خصوصی (private cache) مینامد: مناسب دارایی و حتی پاسخ شخصی، چون با دیگران به اشتراک گذاشته نمیشود. CSS و جاوااسکریپت با نام فایل هششده و max-age بلند نمونهٔ کلاسیکاند. کاربر با بارگذاری مجدد سخت کش محلی را دور میزند و گاهی سرور را مقصر میداند. کنترل با Cache-Control است، نه با امید به خالی کردن کش توسط کاربر.
کش CDN و کش اشتراکی
شبکهٔ تحویل محتوا (CDN) و پراکسی معکوس کش اشتراکی (shared cache) میسازند: یک پاسخ برای چند کاربر. برای تصویر، فایل نسخهدار و صفحهٔ عمومی مناسب است. برای سبد خرید، داشبورد ورودشده، یا پاسخ Authorizationدار بدون دستور صریح public خطرناک است. RFC 9111 بین کش خصوصی و اشتراکی خط میکشد. پاسخ شخصی باید private باشد. بعضی CDNها با هدر اختصاصی یا API پاکسازی ابطال فعال میدهند؛ این مسئولیت Cache-Control را برنمیدارد.
کش HTTP و Cache-Control
RFC 9111 (ژوئن ۲۰۲۲، جانشین RFC 7234) ذخیره، تازگی، اعتبارسنجی و ابطال HTTP را تعریف میکند. MDN همان مدل را برای وب شرح میدهد. اگر Cache-Control نباشد، کش ممکن است با کش اکتشافی (heuristic caching) عمری حدس بزند — معمولاً نامطلوب. عملاً هر پاسخ باید هدر صریح داشته باشد.
max-age تازگی را به ثانیه میبندد. no-cache یعنی قبل از استفاده باید با مبدأ اعتبارسنجی شود — نه «اصلاً ذخیره نکن». no-store یعنی عمداً ذخیره نشود. private یعنی فقط کش کاربر. public به کش اشتراکی اجازه میدهد حتی با Authorization ذخیره کند. s-maxage عمر را برای کش اشتراکی جدا میکند. must-revalidate بعد از کهنه شدن، استفاده بدون اعتبارسنجی را منع میکند.
پاسخ کهنه دور ریخته نمیشود؛ با ETag و If-None-Match یا Last-Modified و If-Modified-Since اعتبارسنجی میشود. اگر عوض نشده باشد مبدأ 304 Not Modified میدهد و بدنه تکرار نمیشود. HTML اصلی اغلب no-cache بهعلاوهٔ همین اعتبارسنجها میگیرد؛ فایل هششده میتواند max-age یکساله و در صورت نیاز immutable داشته باشد.
کش برنامه (Application Cache)
برنامه نتیجه را در حافظهٔ فرایند، Redis یا یک نقشهٔ محلی نگه میدارد: خروجی پرسوجو، پیکربندی، یا HTML رندرشده. کنترل با کد است. مزیت: کلید دقیق و ابطال هنگام نوشتن. هزینه: دو نسخه شدن منطق و ناسازگاری بین نمونهها. کش درونفرایندی با ریاستارت خالی میشود. پشت بارمتعادلکننده هر نمونه حافظهٔ جدا دارد؛ همان کاربر ممکن است یک بار تازه و یک بار کهنه ببیند. آنجا کش توزیعشده معنا دارد — اگر اصلاً به کش نیاز باشد.
کش پایگاه داده (Database Cache)
موتور رابطهای خودش بافر صفحه و گاهی کش طرح اجرا دارد؛ این با کش جلوی پایگاه فرق میکند. اول ایندکس و پرسوجوی بد را درست کنید. کش نتیجه وقتی معنا دارد که همان SQL با همان پارامتر تکرار شود و نوشتن کلید را باطل کند. فیلتر منحصربهفرد هر درخواست فضای کلید را منفجر میکند و Hit نمیآید؛ مدل خواندن را عوض کنید، نه اینکه لایه اضافه کنید.
Redis: لایهٔ سریع، نه دفترکل
Redis ذخیرهٔ درحافظه است و الگوی cache-aside را خوب پشتیبانی میکند: بخوان؛ اگر نبود از پایگاه بیاور و با TTL بنویس؛ هنگام بهروزرسانی کلید را پاک یا بازنویسی کن. مستندات Redis همین را برای کاتالوگ، پروفایل و API تکرارشونده میگوید — وقتی خواندن زیاد است و پنجرهٔ کهنگی قابلقبول. نشست و محدودیت نرخ هم همان معامله را دارند: حافظه گران است و eviction خاموش Miss ناگهانی میسازد. برای ماندهٔ مالی یا سفارش قطعی منبع حقیقت نباشد مگر دوام را عمداً طراحی کرده باشید.
TTL یعنی چه و چرا عدد جادویی وجود ندارد
زمان زندگی (TTL) سقف عمر ورودی است. در HTTP معادل freshness lifetime است: max-age یا s-maxage. در Redis همان EXPIRE. TTL کهنگی را محدود میکند؛ صحت را تضمین نمیکند. کوتاهبودن بیش از حد Hit را میکشد. بلندبودن پنجرهٔ اشتباه را بزرگ میکند. عدد از تحمل کسبوکار میآید: قیمت تا پنج دقیقه؟ موجودی لحظهٔ پرداخت؟ بنر صفحهٔ اصلی؟ یک «سیصد ثانیه برای همه» یعنی بعضی داده خطرناک کهنه است و بعضی زودتر از لازم میمیرد.
TTL جایگزین ابطال هنگام نوشتن نیست. اگر محصول ویرایش شد و کلید شناخته شده است، همان لحظه پاکش کنید. TTL تور نجات است برای وقتی ابطال جا ماند.
ابطال کش: چرا اینقدر سخت است
جملهٔ فیل کارلتون (Phil Karlton) میگوید در علوم کامپیوتر دو چیز سخت است: ابطال کش (cache invalidation) و نامگذاری. نقلقول را شوخی اسلاید نکنید؛ مکانیکش مشخص است.
سختی از سه جا میآید. اول، باید بدانید کدام کلیدها با یک نوشتن باطل شدهاند. تغییر قیمت ممکن است کارت محصول، فهرست دسته، جستوجو، فید CDN و قطعهٔ HTML را لمس کند. اگر نام کلید قرارداد روشنی نداشته باشد — همان سخت بودن نامگذاری — یا زیاد پاک میکنید یا کم. دوم، چند لایه همزمان کپی دارند. RFC 9111 میگوید درخواست ناامن مثل POST یا PUT فقط کشهای سر راه را باطل میکند، نه همهٔ جهان را. سوم، همزمانی: بین نوشتن پایگاه و پاک کردن کش، خوانندهٔ موازی نسخهٔ قدیم را دوباره گرم میکند.
استراتژی واقعی ترکیبی است: کلید نسخهدار (cache busting) برای فایل استاتیک، ابطال هنگام نوشتن برای موجودیت مشخص، TTL کوتاه بهعنوان سقف، و برای HTML عمومی گاهی purge روی CDN. اگر فهرست کلیدهای وابسته به یک نوشتن را روی کاغذ ندارید، برای کش آن داده آماده نیستید.
دادهٔ کهنه چه شکلی به کسبوکار میزند
stale data کپیای است که با منبع حقیقت یکی نیست، ولی هنوز سرو میشود. تعداد بازدید تقریبی معمولاً بیضرر است. قیمت، کد تخفیف، موجودی و وضعیت پرداخت مستقیم به پول وصلاند. مثال فروشگاه: HTML محصول ده دقیقه روی CDN مانده؛ تبلیغ قیمت جدید را میگوید و کارت کششده قیمت قدیم را. یک کاربر اعتماد میبازد؛ دیگری به پرداخت میرسد و سفارش رد میشود.
شکل بیصداتر: کش اشتراکی صفحهٔ شخصی را به کاربر دیگر میدهد. این کهنگی نیست؛ نشت است. RFC 9111 و MDN برای همین private و منع پیشفرض ذخیرهٔ پاسخ Authorizationدار را گذاشتهاند.
چه زمانی واقعاً به کش نیاز داریم
کش را بعد از مشاهده اضافه کنید، نه بهعنوان تزئین معماری.
- یک خواندن مشخص تکرار میشود و هزینهٔ مبدأ در اندازهگیری دیده میشود.
- داده بین دو خواندن پایدار است، یا کهنگیاش در آن بازه قابلقبول است.
- دارایی تغییرناپذیر دارید: فایل با هش در نام و max-age بلند.
- مخاطب از مبدأ دور است و CDN فاصله را کم میکند.
- اوج ترافیک مشخص است و نمیخواهید پایگاه را برای همان اوج بزرگ کنید.
لایه را با داده جور کنید. فایل استاتیک را در Redis نگذارید. سبد شخصی را در CDN عمومی نگذارید.
چه زمانی کش لازم نیست
نبود کش عیب نیست. پنل داخلی با بیست کاربر و پایگاه سالم با افزودن Redis فقط نگهداری و مسیر باگ میگیرد. اول ایندکس و پرسوجو. اگر هر درخواست دادهٔ همان لحظه را میخواهد — موجودی تسویه، بلیت، انتقال وجه — کش خواندنیِ طولانی خلاف نیاز است. الگوی نوشتن زیاد با کلید یکبارمصرف هم Hit نمیسازد.
دادهٔ کوچکی که در حافظهٔ یک فرایند جا میشود گاهی فقط یک متغیر است. آوردنش پشت Redis توزیعشده پیچیدگی را جلو میاندازد. وقتی گلوگاه ندارید معماری مقیاس فرضی نسازید.
چه زمانی کش خودش مشکل میسازد
کش بد از نبود کش خطرناکتر است، چون سیستم «کار میکند» — فقط غلط.
- پاسخ شخصی یا Authorizationدار بدون private روی کش اشتراکی.
- قیمت یا موجودی با TTL بلند و بدون ابطال هنگام نوشتن.
- چند لایه بدون نقشهٔ کلید: مرورگر، CDN و Redis هر کدام نسخهای جدا.
- انقضای همزمان کلید محبوب و هجوم به مبدأ.
- رفع هر باگ با «کش را خالی کن» بهجای قاعده.
- یکی دانستن no-cache و no-store.
اگر خالی کردن کش قدم اول هر حادثه است، لایه زودتر از قاعدهاش آمده است.
مثالهای واقعی
فروشگاه: تصویر و CSS/JS هششده روی CDN با max-age بلند. HTML محصول با max-age کوتاه یا purge هنگام ویرایش. موجودی نمایشی حداکثر یک دقیقه در Redis. موجودی رزرو از پایگاه با تراکنش.
رسانه: مقالهٔ منتشرشده روی CDN تا ویرایش یا خبر فوری purge شود. صفحهٔ اصلی TTL کوتاهتر دارد. پیشنویس باید private یا no-store باشد. داشبورد SaaS ورودشده private است؛ جمع گزارش در Redis با کلید سازمان مفید است، کل صفحه روی CDN معمولاً نه. اپ داخلی خلوت: اگر فهرست در کسری از ثانیه میآید Redis پیش از اندازهگیری اضافه است؛ گزارش سنگین ماهانه با TTL ساعتی منطقیتر از کش همهٔ CRUD است.
جدول تصمیم لایه
«بهتر» یعنی تناسب با نوع داده و دامنهٔ اشتراک.
| لایه | چه چیزی را نگه میدارد | قوت | ریسک اصلی | نشانهٔ تناسب |
|---|---|---|---|---|
| Browser Cache | پاسخ همان کاربر | بدون هزینهٔ سرور | کهنگی محلی | فایل نسخهدار |
| CDN / shared HTTP | پاسخ عمومی | فاصله و بار مبدأ | نشت پاسخ شخصی | رسانه و فایل هششده |
| HTTP validators | ETag / Last-Modified | 304 بهجای بدنه | شرطی ناقص | HTML با no-cache |
| Application / Redis | شیء یا پرسوجو | کلید و ابطال نوشتن | stampede؛ حافظه | خواندن پرتکرار |
| Database buffer | صفحهٔ داخلی موتور | شفاف برای برنامه | پوشاندن ایندکس بد | جایگزین لایهٔ بالا نیست |
کش، خزش و سئو
موتور جستوجو همان HTTP را میبیند. اعتبارسنجها بازخزش را کارآمد میکنند؛ صفحهٔ کهنهٔ خطا با وضعیت ۲۰۰ ایندکس را منحرف میکند. کش دارایی عمومی LCP را واقعاً بهتر میکند. کش تهاجمی HTML اگر نسخهٔ ناقص به خزنده بدهد، عملکرد را با پیداشدن عوض کرده است. الگوی MDN برای صفحهٔ عمومی: HTML با no-cache و ETag؛ دارایی با URL عوضشونده و max-age بلند.
اشتباهات رایج
- Redis قبل از دیدن گلوگاه.
- یکی فرض کردن no-cache و no-store.
- پاسخ نشستدار روی CDN بدون private.
- یک TTL برای قیمت و فایل استاتیک.
- نبود نام هششده برای CSS/JS.
- ابطال فقط با صبر تا TTL برای دادهٔ پولی.
- نقلقول کارلتون بهجای نقشهٔ کلید.
جمعبندی
کش کپی موقت کار گران است. Hit ارزان میخرد؛ Miss و کهنگی قیمتش را میسازند. مرورگر خصوصی است، CDN اشتراکی، Redis برنامه، بافر پایگاه داخلی. HTTP را با RFC 9111 و MDN کنترل کنید. TTL سقف است نه سیاست صحت. ابطال سخت است چون وابستگی کلید، چند لایه و مسابقهٔ نوشتن واقعیاند.
اول منبع حقیقت و تحمل کهنگی را بنویسید؛ بعد لایه را انتخاب کنید. جایی که کهنگی غیرقابلقبول است کش نگذارید. جایی که تکرار کار گران است و داده آرام است، کش را با اندازه بگذارید — نه بهعنوان نشانهٔ بلوغ معماری.
پرسشهای متداول
آیا هر وبسایتی به Redis نیاز دارد؟
خیر. بسیاری از سایتها با کش مرورگر، هدر HTTP و در صورت نیاز CDN تمام میشوند. Redis وقتی توجیه دارد که خواندن پرتکرار از مبدأ گران باشد و ابطال تعریفشده باشد.
تفاوت no-cache و no-store چیست؟
طبق RFC 9111 و MDN، no-cache ذخیره را اجازه میدهد ولی استفاده را به اعتبارسنجی موفق مشروط میکند. no-store میگوید عمداً ذخیره نشود. برای صفحهٔ ورودشده معمولاً private بهعلاوهٔ no-cache بهتر از افراط در no-store است.
چرا کاربر بعد از انتشار نسخهٔ قدیم را میبیند؟
یک لایه هنوز کپی دارد: مرورگر با max-age باقی، CDN بدون purge، یا HTML بدون هش در نام فایل. زنجیره را از URL تا هدر تا کلید دنبال کنید.
کش همان پایگاه سریع است؟
خیر. پایگاه دوام و قید را دارد. کش سرعت تکرار را. از دست رفتن کش باید قابلبازسازی باشد؛ از دست رفتن دفترکل سفارش نه.
از کجا بفهمیم کش زودتر از نیاز آمده؟
هر باگ با خالی کردن کش «درست» میشود، نقشهٔ کلید نیست، پاسخ شخصی از CDN آمده، یا مبدأ بعد از انقضای دستهای کلید میافتد.
منابع و مراجع
- MDN — HTTP caching: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching
- MDN — Cache-Control header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control
- RFC 9111 — HTTP Caching: https://www.rfc-editor.org/rfc/rfc9111.html
- RFC 9111 — وضعیت استاندارد: https://www.rfc-editor.org/info/rfc9111
- Redis documentation: https://redis.io/docs/latest/
- Redis — cache-aside: https://redis.io/docs/latest/develop/use-cases/cache-aside/
نویسنده
بنیانگذار و مهندس محصول
سهیل ابراهیمپور بنیانگذار FutureForge است. روی طراحی محصول، معماری و استقرار نرمافزار سفارشی کار میکند.
اگر در انتخاب معماری یا مسیر توسعه مطمئن نیستید، میتوانید درباره پروژه صحبت کنیم.
مسئله و محدودیت را بنویسید. اگر تطابق داشته باشیم، برای گفتگو هماهنگ میکنیم.