یک سایت ویدیویی با ترافیک بالا، پرس‌وجوهای (queries) پایگاه داده را برای فید صفحه ترند از ۴۰۰۰ مورد در دقیقه به کمتر از ۵۰ مورد کاهش داد و زمان پاسخ‌گویی صدک ۹۵ام خود را از ۳۸۰ میلی‌ثانیه به ۴۰ میلی‌ثانیه رساند؛ این کار با تغییر استراتژی از کش کردن کل صفحه به کش کردن قطعه‌ای (fragment caching) با استفاده از Varnish و Edge Side Includes (ESI) انجام شد.

چرا سایت به استراتژی کش متفاوتی نیاز داشت

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

  • کش کردن کل صفحه و ریسک ارائه داده‌های شخصی قدیمی (stale) به کاربران وارد شده.
  • دور زدن کامل کش و اجازه دادن به هر درخواست برای فشار آوردن به پایگاه داده.

هر دو رویکرد تجربه کاربری را مختل می‌کردند. تیم به سراغ ESI رفت؛ تکنیکی که به یک ریورس‌پراکسی (reverse-proxy) اجازه می‌دهد یک صفحه را از قطعاتی که به‌طور مستقل در لبه شبکه (edge of the network) کش شده‌اند، بازسازی کند.

نحوه پیاده‌سازی کش قطعه‌ای

Varnish، شتاب‌دهنده متن‌باز HTTP، با صفحه مانند یک اسکلت برخورد کرد که دارای سه بخش قابل جایگزینی است:

  • شبکه ویدیو (Video grid) – لیست پرهزینه و منطقه‌ای ویدیوهای ترند. برای ۶۰ ثانیه کش می‌شود زیرا مکرراً تغییر می‌کند اما برای همه بازدیدکنندگان ناشناس یکسان است.
  • تغییردهنده زبان (Language switcher) – یک المان رابط کاربری (UI) استاتیک که به‌ندرت تغییر می‌کند. برای ۲۴ ساعت کش می‌شود.
  • هدر (Header) – تنها قطعه واقعاً شخصی (نام کاربر، آواتار، اعلان‌ها). هرگز کش نمی‌شود؛ Varnish هر بار درخواست را به سرور اپلیکیشن ارسال می‌کند.

وقتی درخواستی می‌رسد، Varnish اسکلت کش‌شده را ارائه می‌دهد، دو قطعه کش‌شده را از ذخیره محلی خود فراخوانی می‌کند و هدر زنده را از سمت بک‌اند (backend) جایگذاری می‌کند.

اعداد مهم

پس از این تغییر:

  • بار پایگاه داده برای صفحه ترند از ۴۰۰۰ پرس‌وجو در دقیقه به کمتر از ۵۰ کاهش یافت.
  • تأخیر (latency) صدک ۹۵ام از ۳۸۰ میلی‌ثانیه به ۴۰ میلی‌ثانیه کاهش یافت.

سه درس کاربردی از این پیاده‌سازی

۱. دوره‌های مهلت (Grace periods) از نوسانات ناشی از عدم وجود در کش جلوگیری می‌کنند وقتی زمان انقضای (TTL) یک قطعه تمام می‌شود، Varnish به‌طور معمول برای دریافت محتوای تازه متوقف می‌شود که باعث ایجاد یک جهش در تأخیر می‌شود؛ این اتفاق می‌تواند منجر به پدیده «گله خروشان» (thundering herd) از فراخوانی‌های همزمان به بک‌اند شود. با پیکربندی یک دوره مهلت، Varnish به ارائه همان قطعه قدیمی ادامه می‌دهد در حالی که به‌طور بی‌صدا در پس‌زمینه کش را به‌روزرسانی می‌کند. کاربران هیچ وقفه‌ای حس نمی‌کنند و بک‌اند نیز نرخ درخواست‌های ثابت و قابل مدیریتی را مشاهده می‌کند.

۲. حذف کوکی‌ها برای قطعات ناشناس کوکی‌های متصل به هر درخواست باعث می‌شوند Varnish با هر درخواست به‌صورت یک مورد منحصربه‌فرد برخورد کند و این موضوع باعث از بین رفتن اثر کش می‌شود. تیم کوکی‌ها را برای شبکه ویدیو و تغییردهنده زبان حذف کرد تا اجازه دهد این قطعات به‌طور تهاجمی (aggressively) کش شوند. تنها قطعه هدر حاوی کوکی است که باعث حفظ شخصی‌سازی بدون قربانی کردن کارایی کش می‌شود.

۳. کلیدهای جایگزین (Surrogate keys) امکان پاکسازی فوری را فراهم می‌کنند گاهی اوقات یک ویدیو باید بلافاصله حذف شود (مثلاً به دلیل مسائل کپی‌رایت). انتظار برای انقضای ۶۰ ثانیه‌ای TTL قابل قبول نیست. با برچسب‌گذاری هر قطعه کش‌شده با یک کلید جایگزین (surrogate key) که منعکس‌کننده شناسه‌های (IDs) ویدیوی مربوطه است، تیم تنها با یک دستور پاکسازی (purge)، تمام نسخه‌های یک ویدیوی خاص را در تمام گره‌های لبه (edge nodes) فوراً باطل می‌کند. این کار از اسکن کامل کش جلوگیری کرده و انطباق سایت را حفظ می‌کند.

نتیجه‌گیری: کش قطعه‌ای با استفاده از Varnish و ESI، یک صفحه یکپارچه و وابسته به پایگاه داده را به مجموعه‌ای از قطعات سبک و قابل استفاده مجدد تبدیل می‌کند که بار بک‌اند و تأخیر را به شدت کاهش داده و در عین حال شخصی‌سازی برای هر کاربر را حفظ می‌کند.