استراتژی کش و نقش Redis

کش سادهترین راه سریعکردن یک سامانه است و سادهترین راه ساختن باگهایی که بازتولیدشان سخت است. هر دو جمله درستاند و فاصلهشان در چند تصمیم است.
اول: مطمئن شوید مسئله کندی خواندن است
قبل از هر کشی، بفهمید وقت کجا میرود. تیمهایی را دیدهایم که لایهٔ کش کاملی ساختهاند و بعد معلوم شده کندی از یک کوئری بدون ایندکس بوده.
کش، کوئری بد را سریع نمیکند؛ فقط پنهانش میکند تا روزی که کش خالی شود و همهچیز با هم بیفتد روی پایگاه داده.
کجا کش بگذارید
از نزدیکترین به کاربر شروع کنید. هر لایه که جلوتر باشد، بار کمتری به عقب میرسد.
مرورگر. برای فایلهای ثابت — تصویر، CSS، جاوااسکریپت. ارزانترین کش موجود و با تنظیم درست هدرها به دست میآید.
CDN. برای صفحهها و فایلهایی که برای همه یکساناند.
کش برنامه. جایی که Redis مینشیند: نتیجهٔ کوئریها، نشست کاربران، شمارندهها.
کش پایگاه داده. خودش دارد و معمولاً دست شما نیست.
چه چیزی ارزش کشکردن دارد
معیار ساده: چیزی که زیاد خوانده میشود و کم عوض میشود.
نامزدهای خوب: دستهٔ محصولات، تنظیمات سامانه، لیست قیمت، نتیجهٔ محاسبات سنگین، و دادهای که از سرویس بیرونی میآید و گران است.
نامزدهای بد: چیزی که هر بار عوض میشود، و چیزی که اگر لحظهای کهنه باشد پول جابهجا میشود. ماندهٔ اعتبار مشتری را کش نکنید — یا اگر کردید، با عمر بسیار کوتاه و با آگاهی از اینکه در فروش اعتباری گفتیم که سفارش ثبتشده هم باید اعتبار را قفل کند.
باطلکردن، بخش سختش
کشکردن آسان است. تصمیم دربارهٔ اینکه کِی داده کهنه است، سخت است. سه راه:
انقضای زمانی. سادهترین و در بیشتر موارد کافی. «این را پنج دقیقه نگه دار.» شما در واقع دارید میگویید پنج دقیقه دادهٔ کهنه قابل قبول است — و این یک تصمیم کسبوکاری است، نه فنی. برای هر قلم جدا بگیریدش.
باطلکردن صریح. وقتی داده عوض شد، کش را پاک کن. دقیقتر، و باید همهجا یادتان بماند. اگر یک مسیر بهروزرسانی از قلم بیفتد، داده تا ابد کهنه میماند.
نسخه در کلید. بهجای پاککردن، کلید را عوض کنید — مثلاً شمارهٔ نسخهٔ محصول را در کلید بگذارید. نسخهٔ قدیمی خودش منقضی میشود. تمیزترین راه وقتی چند چیز به یک داده وابستهاند.
در عمل بیشتر سامانهها ترکیبی دارند: انقضای زمانی بهعنوان پایه، و باطلکردن صریح برای چیزهایی که کهنگیشان دیده میشود.
سه اشتباه که کش را به منبع باگ تبدیل میکند
کشکردن دادهٔ خاص کاربر با کلید مشترک. نتیجهاش این است که کاربر الف سبد خرید کاربر ب را میبیند. اگر داده به کاربر وابسته است، شناسهٔ کاربر باید در کلید باشد. این را جدی بگیرید؛ یک بار اتفاق افتادنش کافی است.
کشکردن پاسخ خطا. سرویس بیرونی خطا داد، خطا کش شد، و حالا تا انقضای کش همه خطا میگیرند حتی بعد از اینکه سرویس برگشته. فقط پاسخ موفق را کش کنید.
فرض اینکه کش همیشه هست. Redis هم میخوابد. اگر برنامه بدون کش کار نمیکند، شما کش نساختهاید، یک پایگاه دادهٔ دوم ساختهاید که پایداری ندارد. هر خواندن از کش باید مسیر بازگشت به منبع اصلی داشته باشد.
دو مسئله در بار بالا
هجوم پس از انقضا. کلید پرطرفداری منقضی میشود و هزار درخواست همزمان به پایگاه داده میروند تا دوباره بسازندش. راهش این است که فقط یکی اجازهٔ بازسازی داشته باشد و بقیه منتظر بمانند یا مقدار قدیمی را بگیرند.
انقضای همزمان. اگر همهٔ کلیدها را با یک عمر ثابت بگذارید، همه با هم منقضی میشوند. کمی تصادف در عمر — مثلاً پنج دقیقه بهعلاوهٔ چند ثانیهٔ تصادفی — این را پخش میکند.
Redis فقط کش نیست
چون بحث معمولاً با کش شروع میشود، بقیهٔ کاربردهایش نادیده میماند: نگهداری نشست کاربران، شمارنده و محدودیت نرخ، قفل توزیعشده، و صف سبک برای کارهای پسزمینه.
در کافهرسان هم برای همین ترکیب استفاده شد، نه فقط برای کش کردن کوئری.
چطور بفهمید کار میکند
نرخ اصابت — چند درصد درخواستها از کش جواب گرفتند. اگر این عدد پایین است، یا کلیدها بد انتخاب شدهاند یا عمرشان کوتاه است و کش فقط دارد هزینه اضافه میکند.
تأخیر پاسخ، قبل و بعد. اگر تفاوتی نیست، مسئله جای دیگری بوده.
و بار پایگاه داده، که هدف اصلی کاهشش بوده.
اگر این سه را قبل از افزودن کش اندازه نگرفته باشید، بعدش هم نمیتوانید بگویید کمک کرد یا نه — و کشی که نمیدانید کمک میکند، فقط یک لایهٔ اضافه است که باید نگهش دارید.