وقتی میگیم کش اولین چیزی که به ذهن خیلیامون میاد اینه کل صفحه HTML سایت که خروجی سایتمون هست رو کش کنیم. اگه وبلاگ داشته باشید و خیلی ساده بخواید لود سایت رو کمتر باشه تا میتونید با این حرکت به منظورتون برسید. اما یک سوال در نظر بگیرید.
سایت ایی مثل Twitter که هر بار Refresh میکنید اش یک جواب جدید به ما میده چطور کش رو انجام میده؟ اصلا چطور میشه کش داینامیک داشت؟ Best Practice های کش برای این کار چطور هستن؟
ما میخوایم یک وبسایت داشته باشیم که توش کاربر ها مطلب منتشر میکنن. هر لحظه ممکنه مطلب جدید منتشر بشه. اگه من یک مطلب منتشر کردم توی تایم لاین همه کسایی که من رو فالو کردن نمایش داده بشه ( پس قابلیت فالو کردن باید داشته باشه ).
نکته بعدی اینه که میخوایم سایتمون سریع باشه. نمیخوایم کش چند ساعتی داشته باشیم! طوری که اگه تعداد فالوئینگ های من منطقی بود هر بار رفرش کنم سایت رو احتمالا مطلب جدیدی برام لود بشه.
ساده ترین روش کش رو در نظر بگیریم. من بیام تمام پیام خروجی API رو برای هر کاربر کش کنم! یعنی من وقتی خواستم تایم لاین رو بگیرم یک کوئری بزنه توی MySQL و برام تایم لاینم رو بسازه. بعد که رفرش کردم دوباره اون رو نشون بده. قاعدتا لود سایت کمتر میشه ولی این مخالف حرفیه که توی توضیحات هدف سایت گفته بودیم.
پس کش کردن کل تایم لاین به ازای هر کاربر کار منطقی ایی نیست. باید یک فکر دیگه ایی کرد.
بیاید ببینیم تایم لاین من از چی تشکیل شده؟ یک لیست از پست ها. درسته؟ خب میتونیم این رو بشکونیم! جای اینکه کل تایم لاین رو کش کنیم پست ها رو کش میکنیم. چه اتفاقی میوفته؟ کوئری ایی که به دیتابیس میزنیم فقط id پست های جدید رو میگیره و از طریق اون آی دی میتونیم کل پست رو از کش بخونیم. لود دیتابیس خیلی کمتر میشه.
اما شاید خود پست رو بقیه بتونن لایک کنن. یا بتونن کامنت بذارن. اگه همشون با هم کش کنیم هر بار کسی کامنت میفرسته باید کلی صبر کنه تا کش دوباره ساخته شه تا کامنتش نمایش داده بشه. پس بهتره پست رو هم بشکونیم. یک کش میذاریم برای توضیحات مثل Text و تصویر و سازنده پست و ... که معمولا تغییر نمیکنن. اگر هم تغییر کنن مثلا Text رو آپدیت میکنیم.
یک کش جدید نیاز داریم که لیست کامنت ها رو توی خودش بر اساس یک پست نگه داره. این کش هم فقط id کامنت ها رو نگه میداره و اگر کامنت جدیدی اضافه شه این id جدید به کش اضافه میشه. خود کامنت ها هم جدا جدا کش میشن و براساس اون آی دی ها میتونیم به کامنت دسترسی داشته باشیم.
مرتب تر ترتیب کش ها رو بگم. ( جلوی هر مورد نمونه کش ایی که میخوایم توی ردیس ذخیره کنیم نوشته شده )
این چیزی که گفتم میشه کلی بالا پایین شه. نکته ایی که هست کلیت ایده رو منتقل میکنه که ما قرار چیکار کنیم.
ما میخوایم از Redis استفاده کنیم. چون خیلی خفنه. توی همین مثال خودش رو نشون میده که چرا خفنه. ما نمیایم لیست آی دی پست های تایم لاین یک نفر رو به صورت json ذخیره کنیم! میایم از data type های ردیس استفاده میکنیم. سریع تره. تست هاش انجام شده و خودش رو ثابت کرده.
برای لیست ها همون طوری که از اسم اش میاد از دیتاتایپ لیست استفاده میکنیم. یعنی هر شخص به عنوان لیست یک تایم لاین توی ردیس داره. حالا پست جدید میاد. چیکار میکنیم؟ درست حدس زدید. به آخر لیست آی دی پست جدید اضافه میکنیم. به همین راحتی!
حالا دیتاهایی مثل postinfo رو چطور ذخیره کنیم؟ دو تا راه حل داریم. استفاده از hash ردیس یا اینکه تبدیل به بایت کنیم اطلاعات postinfo رو و توی ردیس ذخیره کنیم.
در مورد این میشه خیلی صحبت کرد. اما خلاصش اینه که وقتی از هش استفاده میکنید برای دسترسی به تمام اطلاعات پست باید تمام فیلد های هش رو پرواید کنید که زمانی که میگیره خیلی بیشتر از اینه JSON یا بایت بگیرید و تبدیلش کنید به آبجکت. اگر نیاز بود هر بار فقط یکی از فیلد های یک پست که توی postinfo ذخیره شده رو دربیاریم استفاده از هش منطقی تر بود. چون سریع تر میشد.
برای postlikes باید یک فکری هم بکنیم که یه نفر دوبار پست رو لایک نکنه. یعنی اگه پست رو لایک کرده بهش نشون بدیم. برای این کار از لیست استفاده نمیکنیم. چرا؟ چون هر بار باید چک کنیم آی دیمون توی لیست هست یا نه و این یعنی o(n) که زیاده. ما میتونیم از Sorted Set استفاده میکنیم که cost اضافه کردن و دریافت o(log n) هست. یا اگه فضای اضافه داشته باشیم کنارش یک Hash هم میذاریم که بررسی آیا لایک کرده یا نه o)1( باشه.
میخوایم یک پست جدید بسازیم و انتظار داریم توی تایم لاین تک تک کسایی که ما رو فالو کردن اضافه شه. چه اتفاقی میوفته؟
حالا خودتون میتونید حدس بزنید وقتی یک کامنت جدید اضافه میشه به پست چه اتفاقی میوفته؟
این چیزی که ما درموردش صحبت کردیم تقریبا کاریه که توییتر انجام میده. البته خیلی باید Tune بشه و چالش های دیگه ایی بخصوص توی Scale کردن بوجود میاد. مثلا وقتی لیدی گاگا با 5 میلیون فالوئر پست بزنه چطور آی دی پست رو به آخر تایم لاین 5 میلیون نفر اضافه کنیم طوری که سرورمون نخوابه =))