ASP.NET Core'de bellek içi önbelleğe alma

Rick Anderson, John Luo ve Steve Smith tarafından

Önbelleğe alma, içerik oluşturmak için gereken çalışmayı azaltarak uygulamanın performansını ve ölçeklenebilirliğini önemli ölçüde artırabilir. Önbelleğe alma, seyrek değişen ve oluşturulması pahalı olan verilerle en iyi şekilde çalışır. Önbelleğe alma, kaynaktan çok daha hızlı döndürülebilen verilerin bir kopyasını oluşturur. Uygulamalar hiçbir zaman önbelleğe alınmış verilere bağımlı olmayacak şekilde yazılmalı ve test edilmelidir.

ASP.NET Core birkaç farklı önbelleği destekler. En basit önbellek tabanlıdır IMemoryCache. IMemoryCache , web sunucusunun belleğinde depolanan bir önbelleği temsil eder. Bir sunucu grubunda (birden çok sunucu) çalışan uygulamalar, bellek içi önbelleği kullanırken oturumların yapışkan olmasını sağlamalıdır. Yapışkan oturumlar, bir istemciden gelen isteklerin tümünün aynı sunucuya gitmesini sağlar. Örneğin, Azure Web uygulamaları tüm istekleri aynı sunucuya yönlendirmek için Uygulama İsteği Yönlendirmesi'ni (ARR) kullanır.

Bir web grubundaki yapışkan olmayan oturumlar, önbellek tutarlılığı sorunlarını önlemek için dağıtılmış bir önbellek gerektirir. Bazı uygulamalarda, dağıtılmış önbellek bellek içi önbellekten daha yüksek ölçek genişletmeyi destekleyebilir. Dağıtılmış önbellek kullanmak, önbellek belleğini bir dış işleme boşaltır.

Bellek içi önbellek herhangi bir nesneyi depolayabilir. Dağıtılmış önbellek arabirimi ile byte[]sınırlıdır. Bellek içi ve dağıtılmış önbellek deposu, öğeleri anahtar-değer çiftleri olarak önbelleğe alır.

System.Runtime.Caching/MemoryCache

System.Runtime.Caching/MemoryCache (NuGet paketi) ile kullanılabilir:

  • .NET Standard 2.0 veya üzeri.
  • .NET Standard 2.0 veya üzerini hedefleyen herhangi bir .NET uygulaması. Örneğin, 3.1 veya sonraki bir sürümü ASP.NET Core.
  • .NET Framework 4.5 veya üzeri.

Microsoft.Extensions.Caching.Memory/ (bu makalede açıklanmıştır) ASP.NET Core ile daha iyi tümleştirildiğinden önerilirSystem.Runtime.Caching/MemoryCache.IMemoryCache Örneğin, IMemoryCache ASP.NET Core bağımlılık ekleme ile yerel olarak çalışır.

kodu ASP.NET 4.x'ten ASP.NET Core taşıma sırasında uyumluluk köprüsü olarak kullanınSystem.Runtime.Caching/MemoryCache.

Önbellek yönergeleri

  • Kod her zaman verileri getirmek için bir geri dönüş seçeneğine sahip olmalı ve önbelleğe alınmış bir değerin kullanılabilir olmasına bağlı olmamalıdır .
  • Önbellekte az miktarda kaynak ve bellek kullanılır. Önbellek büyümesini sınırla:
    • Önbelleğe dış giriş eklemeyin . Örneğin, kullanıcı tarafından sağlanan rastgele girişin önbellek anahtarı olarak kullanılması önerilmez çünkü giriş öngörülemeyen miktarda bellek tüketebilir.
    • Önbellek büyümesini sınırlamak için süre sonu kullanın.
    • Önbellek boyutunu sınırlamak için SetSize, Size ve SizeLimit kullanın. ASP.NET Core çalışma zamanı, bellek baskısına bağlı olarak önbellek boyutunu sınırlamaz. Önbellek boyutunu sınırlamak geliştiriciye bağlı.

IMemoryCache kullanma

Uyarı

Bağımlılık Ekleme'denpaylaşılan bir bellek önbelleği kullanmak ve önbellek boyutunu sınırlamak için , Sizeveya SizeLimit çağrısı SetSizeyapmak uygulamanın başarısız olmasına neden olabilir. Önbellekte boyut sınırı ayarlandığında, tüm girdiler eklenirken bir boyut belirtmelidir. Geliştiriciler paylaşılan önbelleği kullananlar üzerinde tam denetime sahip olmayabileceği için bu sorunlara yol açabilir. Önbelleği sınırlamak için , Sizeveya SizeLimit kullanırkenSetSize, önbelleğe almak için bir önbellek tekil oluşturun. Daha fazla bilgi ve örnek için bkz. Önbellek boyutunu sınırlamak için SetSize, Size ve SizeLimit kullanma. Paylaşılan önbellek, diğer çerçeveler veya kitaplıklar tarafından paylaşılan önbellektir.

Bellek içi önbelleğe alma, Bağımlılık Ekleme kullanılarak bir uygulamadan başvuruda bulunan bir hizmettir. Oluşturucudaki IMemoryCache örneği isteyin:

public class IndexModel : PageModel
{
    private readonly IMemoryCache _memoryCache;

    public IndexModel(IMemoryCache memoryCache) =>
        _memoryCache = memoryCache;

    // ...

Aşağıdaki kod, bir saatin önbellekte olup olmadığını denetlemek için kullanır TryGetValue . Bir süre önbelleğe alınmazsa yeni bir giriş oluşturulur ve ile Setönbelleğe eklenir:

public void OnGet()
{
    CurrentDateTime = DateTime.Now;

    if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
    {
        cacheValue = CurrentDateTime;

        var cacheEntryOptions = new MemoryCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(3));

        _memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
    }

    CacheCurrentDateTime = cacheValue;
}

Yukarıdaki kodda, önbellek girişi üç saniyelik kayan süre sonu ile yapılandırılır. Önbellek girdisine üç saniyeden fazla erişilmezse önbellekten çıkarılır. Önbellek girdisine her erişildiğinde, önbellekte 3 saniye daha kalır. CacheKeys sınıfı, indirme örneğinin bir parçasıdır.

Geçerli saat ve önbelleğe alınan süre görüntülenir:

<ul>
    <li>Current Time: @Model.CurrentDateTime</li>
    <li>Cached Time: @Model.CacheCurrentDateTime</li>
</ul>

Aşağıdaki kod, verileri olmadan MemoryCacheEntryOptionsgöreli bir süre için önbelleğe almak için uzantı yöntemini kullanırSet:

_memoryCache.Set(CacheKeys.Entry, DateTime.Now, TimeSpan.FromDays(1));

Önceki kodda, önbellek girdisi bir günlük göreli süre sonu ile yapılandırılır. Önbellek girdisi, bu zaman aşımı süresi içinde erişilmiş olsa bile önbellekten bir gün sonra çıkarılır.

Aşağıdaki kod, verileri önbelleğe almak için ve GetOrCreateAsync kullanırGetOrCreate.

public void OnGetCacheGetOrCreate()
{
    var cachedValue = _memoryCache.GetOrCreate(
        CacheKeys.Entry,
        cacheEntry =>
        {
            cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
            return DateTime.Now;
        });

    // ...
}

public async Task OnGetCacheGetOrCreateAsync()
{
    var cachedValue = await _memoryCache.GetOrCreateAsync(
        CacheKeys.Entry,
        cacheEntry =>
        {
            cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
            return Task.FromResult(DateTime.Now);
        });

    // ...
}

Önbelleğe alınan zamanı getirmek için aşağıdaki kod çağrıları Get :

var cacheEntry = _memoryCache.Get<DateTime?>(CacheKeys.Entry);

Aşağıdaki kod, mutlak süre sonu olan önbelleğe alınmış bir öğeyi alır veya oluşturur:

var cachedValue = _memoryCache.GetOrCreate(
    CacheKeys.Entry,
    cacheEntry =>
    {
        cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
        return DateTime.Now;
    });

Yalnızca kayan süre sonu olan önbelleğe alınmış bir öğe kümesinin süresi hiç dolmama riski vardır. Önbelleğe alınan öğeye kayan süre sonu aralığı içinde tekrar tekrar erişilirse öğenin süresi hiçbir zaman dolmaz. Öğenin süresinin dolduğundan emin olmak için kayan süre sonunu mutlak süre sonuyla birleştirin. Mutlak süre sonu, öğenin ne kadar süre önbelleğe alınabileceğine ilişkin bir üst sınır ayarlar ve kayan süre sonu aralığı içinde istenmezse öğenin süresinin daha erken dolmasına izin verir. Kayan süre sonu aralığı veya mutlak süre sonu süresi geçerse, öğe önbellekten çıkarılır.

Aşağıdaki kod hem kayan hem de mutlak süre sonu olan önbelleğe alınmış bir öğe alır veya oluşturur:

var cachedValue = _memoryCache.GetOrCreate(
    CacheKeys.CallbackEntry,
    cacheEntry =>
    {
        cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
        cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
        return DateTime.Now;
    });

Yukarıdaki kod, verilerin mutlak süreden daha uzun süre önbelleğe alınmayacağını garanti eder.

GetOrCreate, GetOrCreateAsyncve Get sınıfındaki CacheExtensions uzantı yöntemleridir. Bu yöntemler özelliğini genişletir IMemoryCache.

MemoryCacheEntryOptions

Aşağıdaki örnek:

  • Önbellek önceliğini olarak CacheItemPriority.NeverRemoveayarlar.
  • Girdi önbellekten çıkarıldıktan sonra çağrılan bir PostEvictionDelegate ayarlar. Geri çağırma, öğeyi önbellekten kaldıran koddan farklı bir iş parçacığında çalıştırılır.
public void OnGetCacheRegisterPostEvictionCallback()
{
    var memoryCacheEntryOptions = new MemoryCacheEntryOptions()
        .SetPriority(CacheItemPriority.NeverRemove)
        .RegisterPostEvictionCallback(PostEvictionCallback, _memoryCache);

    _memoryCache.Set(CacheKeys.CallbackEntry, DateTime.Now, memoryCacheEntryOptions);
}

private static void PostEvictionCallback(
    object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
{
    var memoryCache = (IMemoryCache)state;

    memoryCache.Set(
        CacheKeys.CallbackMessage,
        $"Entry {cacheKey} was evicted: {evictionReason}.");
}

Önbellek boyutunu sınırlamak için SetSize, Size ve SizeLimit kullanma

Bir MemoryCache örnek isteğe bağlı olarak bir boyut sınırı belirtebilir ve zorunlu kılabilir. Önbelleğin girdilerin boyutunu ölçme mekanizması olmadığından önbellek boyutu sınırı tanımlı bir ölçü birimine sahip değildir. Önbellek boyutu sınırı ayarlanırsa, tüm girdilerin boyut belirtmesi gerekir. ASP.NET Core çalışma zamanı, bellek baskısına bağlı olarak önbellek boyutunu sınırlamaz. Önbellek boyutunu sınırlamak geliştiriciye bağlı. Belirtilen boyut, geliştiricinin seçtiği birimler cinsindendir.

Örnek:

  • Web uygulaması öncelikli olarak dizeleri önbelleğe aldıysa, her önbellek girdisi boyutu dize uzunluğu olabilir.
  • Uygulama tüm girişlerin boyutunu 1 olarak belirtebilir ve boyut sınırı girdi sayısıdır.

SizeLimit Ayarlanmadıysa, önbellek bağlı olmadan büyür. sistem belleği düşük olduğunda ASP.NET Core çalışma zamanı önbelleği kırpmaz. Uygulamalar şu şekilde tasarlanmalıdır:

  • Önbellek büyümesini sınırlayın.
  • Çağrı Compact veya Remove kullanılabilir bellek sınırlı olduğunda.

Aşağıdaki kod, bağımlılık ekleme ile erişilebilen bir birimsiz sabit boyut MemoryCache oluşturur:

public class MyMemoryCache
{
    public MemoryCache Cache { get; } = new MemoryCache(
        new MemoryCacheOptions
        {
            SizeLimit = 1024
        });
}

SizeLimit birimleri yoktur. Önbellek boyutu sınırı ayarlandıysa, önbelleğe alınan girdilerin boyutu en uygun olarak değerlendirdikleri birimlerde belirtmesi gerekir. Önbellek örneğinin tüm kullanıcıları aynı birim sistemini kullanmalıdır. Önbelleğe alınan girdi boyutlarının toplamı tarafından SizeLimitbelirtilen değeri aşarsa bir giriş önbelleğe alınmaz. Önbellek boyutu sınırı ayarlı değilse, girdide ayarlanan önbellek boyutu yoksayılır.

Aşağıdaki kod bağımlılık ekleme kapsayıcısıyla kaydedilirMyMemoryCache:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddSingleton<MyMemoryCache>();

MyMemoryCache , bu boyut sınırlı önbelleğin farkında olan ve önbellek girişi boyutunu uygun şekilde ayarlamayı bilen bileşenler için bağımsız bir bellek önbelleği olarak oluşturulur.

Önbellek girişinin boyutu uzantı yöntemi veya Size özelliği kullanılarak SetSize ayarlanabilir:

if (!_myMemoryCache.Cache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
    var cacheEntryOptions = new MemoryCacheEntryOptions()
        .SetSize(1);

    // cacheEntryOptions.Size = 1;

    _myMemoryCache.Cache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}

Yukarıdaki kodda vurgulanan iki satır, önbellek girişinin boyutunu ayarlama işleminin sonucuyla aynı sonucu elde ediyor. SetSize , zincirleme çağrıları sırasında new MemoryCacheOptions()kolaylık sağlamak için sağlanır.

MemoryCache.Compact

MemoryCache.Compact önbelleğin belirtilen yüzdesini aşağıdaki sırayla kaldırmaya çalışır:

  • Süresi dolan tüm öğeler.
  • Önceliğe göre öğeler. En düşük öncelikli öğeler önce kaldırılır.
  • En son kullanılan nesneler.
  • En erken mutlak süre sonu olan öğeler.
  • En erken kayan süre sonu olan öğeler.

Önceliğe NeverRemove sahip sabitlenmiş öğeler hiçbir zaman kaldırılmaz. Aşağıdaki kod bir önbellek öğesini kaldırır ve önbelleğe alınan girişlerin %25'ini kaldırmaya çağırır Compact :

_myMemoryCache.Cache.Remove(CacheKeys.Entry);
_myMemoryCache.Cache.Compact(.25);

Daha fazla bilgi için bkz. GitHub'da sıkıştırma kaynağı.

Önbellek bağımlılıkları

Aşağıdaki örnekte, bağımlı bir girdinin süresi dolarsa önbellek girişinin süresinin nasıl dolmasına ilişkin bilgi verilmiştir. Önbelleğe alınan öğeye bir CancellationChangeToken eklenir. üzerinde CancellationTokenSourceçağrıldığındaCancel, her iki önbellek girdisi de çıkarılır:

public void OnGetCacheCreateDependent()
{
    var cancellationTokenSource = new CancellationTokenSource();

    _memoryCache.Set(
        CacheKeys.DependentCancellationTokenSource,
        cancellationTokenSource);

    using var parentCacheEntry = _memoryCache.CreateEntry(CacheKeys.Parent);

    parentCacheEntry.Value = DateTime.Now;

    _memoryCache.Set(
        CacheKeys.Child,
        DateTime.Now,
        new CancellationChangeToken(cancellationTokenSource.Token));
}

public void OnGetCacheRemoveDependent()
{
    var cancellationTokenSource = _memoryCache.Get<CancellationTokenSource>(
        CacheKeys.DependentCancellationTokenSource);

    cancellationTokenSource.Cancel();
}

kullanmak CancellationTokenSource , birden çok önbellek girişinin grup olarak çıkarılmasını sağlar. using Yukarıdaki koddaki desenle, kapsamın using içinde oluşturulan önbellek girdileri tetikleyicileri ve süre sonu ayarlarını devralır.

Ek notlar

  • Süre sonu arka planda gerçekleşmez. Süresi dolan öğeler için önbelleği etkin bir şekilde tarar zamanlayıcı yoktur. Önbellekteki (Get, , Remove) herhangi bir etkinlik, Setsüresi dolan öğeler için arka plan taraması tetikleyebilir. (CancelAfter) üzerindeki CancellationTokenSource bir zamanlayıcı da girdiyi kaldırır ve süresi dolan öğeler için bir tarama tetikler. Aşağıdaki örnekte kayıtlı belirteç için kullanılır CancellationTokenSource(TimeSpan) . Bu belirteç tetiklendiğinde, girişi hemen kaldırır ve çıkarma geri çağırmalarını başlatır:

    if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
    {
        cacheValue = DateTime.Now;
    
        var cancellationTokenSource = new CancellationTokenSource(
            TimeSpan.FromSeconds(10));
    
        var cacheEntryOptions = new MemoryCacheEntryOptions()
            .AddExpirationToken(
                new CancellationChangeToken(cancellationTokenSource.Token));
    
        _memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
    }
    
  • Önbellek öğesini yeniden doldurmaya yönelik bir geri arama kullanırken:

    • Geri arama tamamlanmadığından birden çok istek önbelleğe alınmış anahtar değerini boş bulabilir.
    • Bu, önbelleğe alınan öğenin birkaç iş parçacığının yeniden doldurulmasıyla sonuçlanabilir.
  • Bir önbellek girişi başka bir giriş oluşturmak için kullanıldığında, alt öğe üst girdinin süre sonu belirteçlerini ve zamana bağlı süre sonu ayarlarını kopyalar. Üst girişin el ile kaldırılması veya güncelleştirilmesiyle çocuğun süresi dolmaz.

  • Önbellek girdisi önbellekten çıkarıldıktan sonra tetiklenecek geri çağırmaları ayarlamak için kullanın PostEvictionCallbacks .

  • Çoğu uygulama IMemoryCache için etkindir. Örneğin, içinde , , , ve diğer Add{Service} birçok yöntemi Program.csçağırmak AddMvcöğesini etkinleştirirIMemoryCache. AddMvcCore().AddRazorViewEngineAddRazorPagesAddControllersWithViews Önceki Add{Service} yöntemlerden birini çağırmaz uygulamalar için çağrısı yapmak AddMemoryCacheProgram.csgerekebilir.

Arka plan önbelleği güncelleştirmesi

Önbelleği güncelleştirmek için gibi IHostedService bir arka plan hizmeti kullanın. Arka plan hizmeti girdileri yeniden derleyebilir ve ardından bunları yalnızca hazır olduklarında önbelleğe atayabilir.

Ek kaynaklar

Örnek kodu görüntüleme veya indirme (indirme)

Önbelleğe almayla ilgili temel bilgiler

Önbelleğe alma, içerik oluşturmak için gereken çalışmayı azaltarak uygulamanın performansını ve ölçeklenebilirliğini önemli ölçüde geliştirebilir. Önbelleğe alma, seyrek değişen ve oluşturulması pahalı olan verilerle en iyi sonucu verir. Önbelleğe alma, kaynaktan çok daha hızlı döndürülebilen verilerin bir kopyasını oluşturur. Uygulamalar hiçbir zaman önbelleğe alınmış verilere bağımlı olmayacak şekilde yazılmalı ve test edilmelidir.

ASP.NET Core birkaç farklı önbelleği destekler. En basit önbellek, temel alır IMemoryCache. IMemoryCache , web sunucusunun belleğinde depolanan bir önbelleği temsil eder. Bir sunucu grubunda (birden çok sunucu) çalışan uygulamalar, bellek içi önbelleği kullanırken oturumların yapışkan olmasını sağlamalıdır. Yapışkan oturumlar, bir istemciden gelen sonraki isteklerin tümünün aynı sunucuya gitmesini sağlar. Örneğin, Azure Web uygulamaları sonraki tüm istekleri aynı sunucuya yönlendirmek için Uygulama İsteği Yönlendirmesi'ni (ARR) kullanır.

Bir web grubundaki yapışkan olmayan oturumlar, önbellek tutarlılığı sorunlarını önlemek için dağıtılmış bir önbellek gerektirir. Bazı uygulamalarda, dağıtılmış önbellek bellek içi önbellekten daha yüksek ölçek genişletmeyi destekleyebilir. Dağıtılmış önbellek kullanmak, önbellek belleğini bir dış işleme boşaltır.

Bellek içi önbellek herhangi bir nesneyi depolayabilir. Dağıtılmış önbellek arabirimi ile byte[]sınırlıdır. Bellek içi ve dağıtılmış önbellek deposu önbellek öğelerini anahtar-değer çiftleri olarak depolar.

System.Runtime.Caching/MemoryCache

System.Runtime.Caching/MemoryCache (NuGet paketi) ile kullanılabilir:

  • .NET Standard 2.0 veya üzeri.
  • .NET Standard 2.0 veya üstünü hedefleyen herhangi bir .NET uygulaması. Örneğin, 3.1 veya sonraki bir sürümü ASP.NET Core.
  • .NET Framework 4.5 veya üzeri.

ASP.NET Core ile daha iyi tümleştirildiğinden Microsoft.Extensions.Caching.Memory/IMemoryCache (bu makalede açıklanmıştır) önerilirSystem.Runtime.Caching/MemoryCache. Örneğin, IMemoryCache ASP.NET Core bağımlılık ekleme ile yerel olarak çalışır.

kodu ASP.NET 4.x'ten ASP.NET Core'a aktarırken uyumluluk köprüsü olarak kullanınSystem.Runtime.Caching/MemoryCache.

Önbellek yönergeleri

  • Kod her zaman verileri getirmek için bir geri dönüş seçeneğine sahip olmalı ve önbelleğe alınmış bir değerin kullanılabilir olmasına bağlı olmamalıdır .
  • Önbellekte az miktarda kaynak ve bellek kullanılır. Önbellek büyümesini sınırla:

IMemoryCache kullanma

Uyarı

Bağımlılık Ekleme'denpaylaşılan bir bellek önbelleği kullanmak ve önbellek boyutunu sınırlamak için , Sizeveya SizeLimit çağrısı SetSizeyapmak uygulamanın başarısız olmasına neden olabilir. Önbellekte boyut sınırı ayarlandığında, tüm girdiler eklenirken bir boyut belirtmelidir. Geliştiriciler paylaşılan önbelleği kullananlar üzerinde tam denetime sahip olmadığından bu sorunlara yol açabilir. Önbelleği sınırlamak için , Sizeveya SizeLimit kullanırkenSetSize, önbelleğe almak için bir önbellek teklisi oluşturun. Daha fazla bilgi ve örnek için bkz. Önbellek boyutunu sınırlamak için SetSize, Size ve SizeLimit kullanma. Paylaşılan önbellek, diğer çerçeveler veya kitaplıklar tarafından paylaşılan önbellektir.

Bellek içi önbelleğe alma, Bağımlılık Ekleme kullanılarak bir uygulamadan başvuruda bulunan bir hizmettir. Oluşturucudaki IMemoryCache örneği isteyin:

public class HomeController : Controller
{
    private IMemoryCache _cache;

    public HomeController(IMemoryCache memoryCache)
    {
        _cache = memoryCache;
    }

Aşağıdaki kod, bir zamanın önbellekte olup olmadığını denetlemek için kullanır TryGetValue . Bir zaman önbelleğe alınmadıysa yeni bir giriş oluşturulur ve ile Setönbelleğe eklenir. CacheKeys sınıfı, indirme örneğinin bir parçasıdır.

public static class CacheKeys
{
    public static string Entry => "_Entry";
    public static string CallbackEntry => "_Callback";
    public static string CallbackMessage => "_CallbackMessage";
    public static string Parent => "_Parent";
    public static string Child => "_Child";
    public static string DependentMessage => "_DependentMessage";
    public static string DependentCTS => "_DependentCTS";
    public static string Ticks => "_Ticks";
    public static string CancelMsg => "_CancelMsg";
    public static string CancelTokenSource => "_CancelTokenSource";
}
public IActionResult CacheTryGetValueSet()
{
    DateTime cacheEntry;

    // Look for cache key.
    if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
    {
        // Key not in cache, so get data.
        cacheEntry = DateTime.Now;

        // Set cache options.
        var cacheEntryOptions = new MemoryCacheEntryOptions()
            // Keep in cache for this time, reset time if accessed.
            .SetSlidingExpiration(TimeSpan.FromSeconds(3));

        // Save data in cache.
        _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
    }

    return View("Cache", cacheEntry);
}

Geçerli saat ve önbelleğe alınan süre görüntülenir:

@model DateTime?

<div>
    <h2>Actions</h2>
    <ul>
        <li><a asp-controller="Home" asp-action="CacheTryGetValueSet">TryGetValue and Set</a></li>
        <li><a asp-controller="Home" asp-action="CacheGet">Get</a></li>
        <li><a asp-controller="Home" asp-action="CacheGetOrCreate">GetOrCreate</a></li>
        <li><a asp-controller="Home" asp-action="CacheGetOrCreateAsynchronous">CacheGetOrCreateAsynchronous</a></li>
        <li><a asp-controller="Home" asp-action="CacheRemove">Remove</a></li>
        <li><a asp-controller="Home" asp-action="CacheGetOrCreateAbs">CacheGetOrCreateAbs</a></li>
        <li><a asp-controller="Home" asp-action="CacheGetOrCreateAbsSliding">CacheGetOrCreateAbsSliding</a></li>

    </ul>
</div>

<h3>Current Time: @DateTime.Now.TimeOfDay.ToString()</h3>
<h3>Cached Time: @(Model == null ? "No cached entry found" : Model.Value.TimeOfDay.ToString())</h3>

Aşağıdaki kod, nesnesini oluşturmadan MemoryCacheEntryOptions verileri göreli bir süre için önbelleğe almak için uzantı yöntemini kullanırSet:

public IActionResult SetCacheRelativeExpiration()
{
    DateTime cacheEntry;

    // Look for cache key.
    if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
    {
        // Key not in cache, so get data.
        cacheEntry = DateTime.Now;

        // Save data in cache and set the relative expiration time to one day
        _cache.Set(CacheKeys.Entry, cacheEntry, TimeSpan.FromDays(1));
    }

    return View("Cache", cacheEntry);
}

Zaman aşımı süresi içinde istekler olduğunda önbelleğe alınan DateTime değer önbellekte kalır.

Aşağıdaki kod, verileri önbelleğe almak için ve GetOrCreateAsync kullanırGetOrCreate.

public IActionResult CacheGetOrCreate()
{
    var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
    {
        entry.SlidingExpiration = TimeSpan.FromSeconds(3);
        return DateTime.Now;
    });

    return View("Cache", cacheEntry);
}

public async Task<IActionResult> CacheGetOrCreateAsynchronous()
{
    var cacheEntry = await
        _cache.GetOrCreateAsync(CacheKeys.Entry, entry =>
        {
            entry.SlidingExpiration = TimeSpan.FromSeconds(3);
            return Task.FromResult(DateTime.Now);
        });

    return View("Cache", cacheEntry);
}

Aşağıdaki kod önbelleğe alınmış zamanı getirmek için çağrı Get yapar:

public IActionResult CacheGet()
{
    var cacheEntry = _cache.Get<DateTime?>(CacheKeys.Entry);
    return View("Cache", cacheEntry);
}

Aşağıdaki kod, mutlak süre sonu olan önbelleğe alınmış bir öğeyi alır veya oluşturur:

public IActionResult CacheGetOrCreateAbs()
{
    var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
    {
        entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
        return DateTime.Now;
    });

    return View("Cache", cacheEntry);
}

Yalnızca kayan süre sonu olan önbelleğe alınmış bir öğe kümesinin süresi hiç dolmama riski vardır. Önbelleğe alınan öğeye kayan süre sonu aralığı içinde tekrar tekrar erişilirse, öğenin süresi hiçbir zaman dolmaz. Öğenin süresinin dolduğundan emin olmak için kayan süre sonunu mutlak süre sonuyla birleştirin. Mutlak süre sonu, öğenin ne kadar süreyle önbelleğe alınabileceğine ilişkin bir üst sınır ayarlar ve kayan süre sonu aralığı içinde istenmezse öğenin süresinin daha erken dolmasına izin verir. Kayan süre sonu aralığı veya mutlak süre sonu süresi geçerse, öğe önbellekten çıkarılır.

Aşağıdaki kod hem kayan hem de mutlak süre sonu olan önbelleğe alınmış bir öğe alır veya oluşturur:

public IActionResult CacheGetOrCreateAbsSliding()
{
    var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
    {
        entry.SetSlidingExpiration(TimeSpan.FromSeconds(3));
        entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
        return DateTime.Now;
    });

    return View("Cache", cacheEntry);
}

Yukarıdaki kod, verilerin mutlak süreden daha uzun süre önbelleğe alınmayacak olmasını garanti eder.

GetOrCreate, GetOrCreateAsyncve Get sınıfındaki CacheExtensions uzantı yöntemleridir. Bu yöntemler özelliğini genişletir IMemoryCache.

MemoryCacheEntryOptions

Aşağıdaki örnek:

  • Kayan sona erme süresini ayarlar. Önbelleğe alınan bu öğeye erişen istekler kayan süre sonu saatini sıfırlar.
  • Önbellek önceliğini olarak CacheItemPriority.NeverRemoveayarlar.
  • Girdi önbellekten çıkarıldıktan sonra çağrılacak bir PostEvictionDelegate ayarlar. Geri arama, öğeyi önbellekten kaldıran koddan farklı bir iş parçacığında çalıştırılır.
public IActionResult CreateCallbackEntry()
{
    var cacheEntryOptions = new MemoryCacheEntryOptions()
        // Pin to cache.
        .SetPriority(CacheItemPriority.NeverRemove)
        // Add eviction callback
        .RegisterPostEvictionCallback(callback: EvictionCallback, state: this);

    _cache.Set(CacheKeys.CallbackEntry, DateTime.Now, cacheEntryOptions);

    return RedirectToAction("GetCallbackEntry");
}

public IActionResult GetCallbackEntry()
{
    return View("Callback", new CallbackViewModel
    {
        CachedTime = _cache.Get<DateTime?>(CacheKeys.CallbackEntry),
        Message = _cache.Get<string>(CacheKeys.CallbackMessage)
    });
}

public IActionResult RemoveCallbackEntry()
{
    _cache.Remove(CacheKeys.CallbackEntry);
    return RedirectToAction("GetCallbackEntry");
}

private static void EvictionCallback(object key, object value,
    EvictionReason reason, object state)
{
    var message = $"Entry was evicted. Reason: {reason}.";
    ((HomeController)state)._cache.Set(CacheKeys.CallbackMessage, message);
}

Önbellek boyutunu sınırlamak için SetSize, Size ve SizeLimit kullanma

Örnek MemoryCache isteğe bağlı olarak bir boyut sınırı belirtebilir ve zorunlu kılabilir. Önbelleğin girdilerin boyutunu ölçme mekanizması olmadığından önbellek boyutu sınırı tanımlı bir ölçü birimine sahip değildir. Önbellek boyutu sınırı ayarlandıysa, tüm girdilerin boyutu belirtmesi gerekir. ASP.NET Core çalışma zamanı, bellek baskısına bağlı olarak önbellek boyutunu sınırlamaz. Önbellek boyutunu sınırlamak geliştiricinindir. Belirtilen boyut, geliştiricinin seçtiği birimler cinsindendir.

Örnek:

  • Web uygulaması birincil olarak dizeleri önbelleğe almaksa, her önbellek girdisi boyutu dize uzunluğu olabilir.
  • Uygulama tüm girişlerin boyutunu 1 olarak belirtebilir ve boyut sınırı girdi sayısıdır.

SizeLimit Ayarlanmadıysa, önbellek bağlı olmadan büyür. sistem belleği düşük olduğunda ASP.NET Core çalışma zamanı önbelleği kırpmaz. Uygulamalar şu şekilde tasarlanmalıdır:

  • Önbellek büyümesini sınırlayın.
  • Çağrı Compact veya Remove kullanılabilir bellek sınırlı olduğunda:

Aşağıdaki kod, bağımlılık ekleme ile erişilebilen bir birimsiz sabit boyut MemoryCache oluşturur:

// using Microsoft.Extensions.Caching.Memory;
public class MyMemoryCache 
{
    public MemoryCache Cache { get; private set; }
    public MyMemoryCache()
    {
        Cache = new MemoryCache(new MemoryCacheOptions
        {
            SizeLimit = 1024
        });
    }
}

SizeLimit birimleri yoktur. Önbellek boyutu sınırı ayarlandıysa, önbelleğe alınan girdilerin boyutu en uygun gördükleri birimlerde belirtmesi gerekir. Önbellek örneğinin tüm kullanıcıları aynı birim sistemini kullanmalıdır. Önbelleğe alınan giriş boyutlarının toplamı tarafından SizeLimitbelirtilen değeri aşarsa bir giriş önbelleğe alınmaz. Önbellek boyutu sınırı ayarlı değilse, girdide ayarlanan önbellek boyutu yoksayılır.

Aşağıdaki kod bağımlılık ekleme kapsayıcısıyla kaydolurMyMemoryCache.

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddSingleton<MyMemoryCache>();
}

MyMemoryCache , bu boyutun sınırlı önbelleğinin farkında olan ve önbellek giriş boyutunu uygun şekilde ayarlamayı bilen bileşenler için bağımsız bir bellek önbelleği olarak oluşturulur.

Aşağıdaki kod şunu kullanır:MyMemoryCache

public class SetSize : PageModel
{
    private MemoryCache _cache;
    public static readonly string MyKey = "_MyKey";

    public SetSize(MyMemoryCache memoryCache)
    {
        _cache = memoryCache.Cache;
    }

    [TempData]
    public string DateTime_Now { get; set; }

    public IActionResult OnGet()
    {
        if (!_cache.TryGetValue(MyKey, out string cacheEntry))
        {
            // Key not in cache, so get data.
            cacheEntry = DateTime.Now.TimeOfDay.ToString();

            var cacheEntryOptions = new MemoryCacheEntryOptions()
                // Set cache entry size by extension method.
                .SetSize(1)
                // Keep in cache for this time, reset time if accessed.
                .SetSlidingExpiration(TimeSpan.FromSeconds(3));

            // Set cache entry size via property.
            // cacheEntryOptions.Size = 1;

            // Save data in cache.
            _cache.Set(MyKey, cacheEntry, cacheEntryOptions);
        }

        DateTime_Now = cacheEntry;

        return RedirectToPage("./Index");
    }
}

Önbellek girişinin boyutu veya SetSize uzantı yöntemleri tarafından Size ayarlanabilir:

public IActionResult OnGet()
{
    if (!_cache.TryGetValue(MyKey, out string cacheEntry))
    {
        // Key not in cache, so get data.
        cacheEntry = DateTime.Now.TimeOfDay.ToString();

        var cacheEntryOptions = new MemoryCacheEntryOptions()
            // Set cache entry size by extension method.
            .SetSize(1)
            // Keep in cache for this time, reset time if accessed.
            .SetSlidingExpiration(TimeSpan.FromSeconds(3));

        // Set cache entry size via property.
        // cacheEntryOptions.Size = 1;

        // Save data in cache.
        _cache.Set(MyKey, cacheEntry, cacheEntryOptions);
    }

    DateTime_Now = cacheEntry;

    return RedirectToPage("./Index");
}

MemoryCache.Compact

MemoryCache.Compact önbelleğin belirtilen yüzdesini aşağıdaki sırayla kaldırmaya çalışır:

  • Süresi dolan tüm öğeler.
  • Önceliğe göre öğeler. En düşük öncelikli öğeler önce kaldırılır.
  • En son kullanılan nesneler.
  • En erken mutlak süre sonu olan öğeler.
  • En erken kayan süre sonu olan öğeler.

Önceliğe NeverRemove sahip sabitlenmiş öğeler hiçbir zaman kaldırılmaz. Aşağıdaki kod bir önbellek öğesini kaldırır ve öğesini çağırır Compact:

_cache.Remove(MyKey);

// Remove 33% of cached items.
_cache.Compact(.33);   
cache_size = _cache.Count;

Daha fazla bilgi için bkz. GitHub'da sıkıştırma kaynağı.

Önbellek bağımlılıkları

Aşağıdaki örnekte, bağımlı bir girdinin süresi dolarsa önbellek girişinin süresinin nasıl dolmasına ilişkin bilgi verilmiştir. Önbelleğe alınan öğeye bir CancellationChangeToken eklenir. üzerinde CancellationTokenSourceçağrıldığındaCancel, her iki önbellek girdisi de çıkarılır.

public IActionResult CreateDependentEntries()
{
    var cts = new CancellationTokenSource();
    _cache.Set(CacheKeys.DependentCTS, cts);

    using (var entry = _cache.CreateEntry(CacheKeys.Parent))
    {
        // expire this entry if the dependant entry expires.
        entry.Value = DateTime.Now;
        entry.RegisterPostEvictionCallback(DependentEvictionCallback, this);

        _cache.Set(CacheKeys.Child,
            DateTime.Now,
            new CancellationChangeToken(cts.Token));
    }

    return RedirectToAction("GetDependentEntries");
}

public IActionResult GetDependentEntries()
{
    return View("Dependent", new DependentViewModel
    {
        ParentCachedTime = _cache.Get<DateTime?>(CacheKeys.Parent),
        ChildCachedTime = _cache.Get<DateTime?>(CacheKeys.Child),
        Message = _cache.Get<string>(CacheKeys.DependentMessage)
    });
}

public IActionResult RemoveChildEntry()
{
    _cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel();
    return RedirectToAction("GetDependentEntries");
}

private static void DependentEvictionCallback(object key, object value,
    EvictionReason reason, object state)
{
    var message = $"Parent entry was evicted. Reason: {reason}.";
    ((HomeController)state)._cache.Set(CacheKeys.DependentMessage, message);
}

kullanmak CancellationTokenSource , birden çok önbellek girişinin grup olarak çıkarılmasını sağlar. using Yukarıdaki koddaki desenle, bloğun using içinde oluşturulan önbellek girdileri tetikleyicileri ve süre sonu ayarlarını devralır.

Ek notlar

  • Süre sonu arka planda gerçekleşmez. Süresi dolan öğeler için önbelleği etkin bir şekilde tarar zamanlayıcı yoktur. Önbellekteki (Get, , Remove) herhangi bir etkinlik, Setsüresi dolan öğeler için arka plan taraması tetikleyebilir. (CancelAfter) üzerindeki CancellationTokenSource bir zamanlayıcı da girdiyi kaldırır ve süresi dolan öğeler için bir tarama tetikler. Aşağıdaki örnekte kayıtlı belirteç için kullanılır CancellationTokenSource(TimeSpan) . Bu belirteç tetiklendiğinde girdiyi hemen kaldırır ve çıkarma geri çağırmalarını başlatır:

    public IActionResult CacheAutoExpiringTryGetValueSet()
    {
        DateTime cacheEntry;
    
        if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
        {
            cacheEntry = DateTime.Now;
    
            var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
    
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                .AddExpirationToken(new CancellationChangeToken(cts.Token));
    
            _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
        }
    
        return View("Cache", cacheEntry);
    }
    
  • Önbellek öğesini yeniden doldurmaya yönelik bir geri arama kullanırken:

    • Geri arama tamamlanmadığından birden çok istek önbelleğe alınmış anahtar değerini boş bulabilir.
    • Bu, önbelleğe alınan öğenin birkaç iş parçacığının yeniden doldurulmasıyla sonuçlanabilir.
  • Bir önbellek girişi başka bir giriş oluşturmak için kullanıldığında, alt öğe üst girdinin süre sonu belirteçlerini ve zamana bağlı süre sonu ayarlarını kopyalar. Üst girişin el ile kaldırılması veya güncelleştirilmesiyle çocuğun süresi dolmaz.

  • Önbellek girdisi önbellekten çıkarıldıktan sonra tetiklenecek geri çağırmaları ayarlamak için kullanın PostEvictionCallbacks .

  • Çoğu uygulama IMemoryCache için etkindir. Örneğin, içinde , , , ve diğer Add{Service} birçok yöntemi ConfigureServicesçağırmak AddMvcöğesini etkinleştirirIMemoryCache. AddMvcCore().AddRazorViewEngineAddRazorPagesAddControllersWithViews Önceki Add{Service} yöntemlerden birini çağırmayan uygulamalar için içinde çağrısı AddMemoryCacheConfigureServicesyapılması gerekebilir.

Arka plan önbelleği güncelleştirmesi

Önbelleği güncelleştirmek için gibi IHostedService bir arka plan hizmeti kullanın. Arka plan hizmeti girdileri yeniden derleyebilir ve ardından bunları yalnızca hazır olduklarında önbelleğe atayabilir.

Ek kaynaklar