HybridCache در ASP.NET Core؛ معماری کش چندلایه برای سرویسهای سریع و مقیاسپذیر
HybridCache در ASP.NET Core؛ معماری کش چندلایه برای سرویسهای سریع و مقیاسپذیر
خلاصه: HybridCache در اکوسیستم .NET یک API یکپارچه برای ترکیب کش درونپردازشی و کش توزیعشده ارائه میکند. این قابلیت علاوه بر سادهسازی الگوی Cache-Aside، با جلوگیری از Cache Stampede، سریالسازی قابلتنظیم و پشتیبانی از Redis، SQL Server و PostgreSQL، پیادهسازی کش را برای سرویسهای پرترافیک قابلاعتمادتر میسازد.
ایده اصلی:
HybridCache یک لایه انتزاعی استاندارد برای ترکیب دو سطح کش است. سطح اول در حافظه همان نمونه برنامه قرار دارد و کمترین latency را ارائه میدهد؛ سطح دوم از طریق IDistributedCache به backendهایی مانند Redis، SQL Server یا PostgreSQL متصل میشود. متد GetOrCreateAsync ابتدا این دو سطح را بررسی میکند و تنها در صورت cache miss کامل، factory را اجرا میکند. مهمترین ویژگی آن، ادغام فراخوانیهای همزمان برای یک کلید است؛ بنابراین هنگام منقضیشدن داده، صدها درخواست همزمان یک کوئری یا API call تکراری ایجاد نمیکنند.
چرا این موضوع مهم است؟:
در معماریهای ابری، افزایش تعداد replicaها معمولاً باعث میشود کش محلی بهتنهایی کافی نباشد و استفاده مستقیم از کش توزیعشده نیز latency و هزینه بیشتری ایجاد کند. HybridCache این دو نیاز را در قالب یک الگوی قابلاستفاده مجدد ترکیب میکند. نتیجه میتواند کاهش فشار روی دیتابیس، کاهش زمان پاسخ، کاهش مصرف شبکه و کنترل بهتر هزینه زیرساخت باشد. جلوگیری از Cache Stampede نیز در زمان انقضای همزمان دادههای محبوب اهمیت زیادی دارد؛ زیرا بدون آن، یک موج درخواست میتواند backend، دیتابیس یا سرویس خارجی را تحت فشار قرار دهد. این قابلیت همچنین مسیر مهاجرت از کدهای دستی و پراکنده کش را سادهتر میکند.
مثال واقعی:
فرض کنید API فروشگاه برای هر درخواست، جزئیات محصول را از PostgreSQL میخواند و اطلاعات یک محصول پرفروش همزمان توسط هزار کاربر درخواست میشود. در این سناریو میتوان HybridCache را با Redis بهعنوان کش ثانویه ثبت کرد و کلیدهایی مانند product:123 را با انقضای پنج دقیقهای ذخیره کرد. نخستین درخواست پس از cache miss داده را از دیتابیس میگیرد؛ درخواستهای همزمان برای همان کلید منتظر همان factory میمانند و دوباره کوئری اجرا نمیکنند. نمونههای دیگر برنامه نیز پس از آن، داده را از Redis دریافت میکنند و هر نمونه برای درخواستهای بعدی، نسخه سریعتر حافظه محلی خود را خواهد داشت.
نکات کلیدی برای توسعهدهندهها:
- کش دوسطحی: حافظه محلی بهعنوان L1 و backend توزیعشده بهعنوان L2.
- جلوگیری داخلی از Cache Stampede برای یک کلید مشترک.
- پشتیبانی از Redis، SQL Server و PostgreSQL از طریق IDistributedCache.
- پشتیبانی از TTL مستقل، tag-based invalidation و serializer سفارشی.
- مناسب برای دادههای پرتکرار، نسبتاً پایدار و عملیات گرانقیمت.
گامهای پیشنهادی برای پیادهسازی:
- پکیج Microsoft.Extensions.Caching.Hybrid را نصب و AddHybridCache را ثبت کنید.
- یک backend توزیعشده مانند Redis یا PostgreSQL را با IDistributedCache پیکربندی کنید.
- برای هر نوع داده، کلید پایدار، کوتاه و دارای namespace مشخص طراحی کنید.
- با GetOrCreateAsync، منبع داده و CancellationToken را بهصورت asynchronous متصل کنید.
- TTL، اندازه payload، serializer، hit ratio و زمان factory را در محیط آزمایشی اندازهگیری کنید.
اشتباهات رایج:
- استفاده از کلیدهای مبهم، بسیار طولانی یا بدون tenant و نسخه.
- ذخیرهکردن دادههای حساس بدون رمزنگاری یا کنترل دسترسی مناسب.
- فرض اینکه invalidation حافظه محلی همه replicaها را همزمان پاک میکند.
- قرار دادن objectهای mutable در حالت reuse بدون بررسی thread safety.
- استفاده از کش برای پنهانکردن query کند یا نبودن index مناسب.
نکات معماری:
- HybridCache برای Cache-Aside و خواندن دادههای پرتکرار مناسبتر از session state است.
- TTL سطح محلی را کوتاهتر و TTL سطح توزیعشده را متناسب با تازگی داده تنظیم کنید.
- برای multi-tenant بودن، tenant، نسخه schema و نوع داده را در کلید لحاظ کنید.
- ابطال tagها باید بخشی از جریان تغییر داده و قرارداد دامنه باشد، نه یک کار دستی.
نکات امنیتی و کارایی:
- کلیدها را از ورودی خام کاربر نسازید و طول و کاراکترهای آنها را محدود کنید.
- دادههای خصوصی را با TTL کوتاه، سطح دسترسی مناسب و در صورت نیاز رمزنگاری ذخیره کنید.
- برای payloadهای بزرگ، سقف اندازه و serializer کارآمد مانند protobuf را بررسی کنید.
- متریکهای hit، miss، latency، factory duration، حجم cache و خطای backend را پایش کنید.
برداشت من از این مطلب این است که:
HybridCache را نباید فقط یک جایگزین کوتاهتر برای IDistributedCache دانست؛ ارزش اصلی آن در هماهنگکردن کش محلی، کش توزیعشده و عملیات بازسازی داده است. برای استفاده تولیدی، ابتدا الگوی کلید و مالکیت داده را مشخص کنید، سپس TTL محلی را کوتاهتر از TTL توزیعشده تنظیم کنید تا latency کاهش یابد اما سازگاری نسبی حفظ شود. برای دادههای immutable یا thread-safe، reuse کردن objectها میتواند هزینه deserialization را کم کند. در کنار آن باید hit ratio، cache miss، زمان factory، اندازه payload و خطاهای backend را اندازهگیری کرد. کش نباید جایگزین اصلاح query، indexگذاری یا طراحی مناسب دیتابیس شود.
منبع اصلی: https://learn.microsoft.com/en-us/aspnet/core/performance/caching/hybrid?view=aspnetcore-10.0
لینکهای مرتبط:
https://learn.microsoft.com/en-us/aspnet/core/performance/caching/overview
https://learn.microsoft.com/en-us/dotnet/core/extensions/caching
https://devblogs.microsoft.com/dotnet/high-performance-distributed-caching-dotnet-postgres-azure/
https://github.com/dotnet/aspnetcore/issues/54647
هنوز دیدگاهی تایید نشده است.