ASP.NET Core'da bellek içi önbellek

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 geliştirebilir. Ö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ülebilecek 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 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.

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çeği 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.

Runtime. Önbelleğe Alma/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, Core 3.1 veya sonraki bir sürümü ASP.NET.
  • .NET Framework 4.5 veya üzeri.

Microsoft.Extensions. Önbelleğe Alma. ASP.NET Core ile daha iyi tümleştirildiğinden bellek/IMemoryCache (bu makalede açıklanmıştırSystem.Runtime.Caching/MemoryCache) önerilir. Ö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ın System.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 kullanma.
    • Ö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'den paylaşı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 alma 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 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 zaman ö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;
}

Önceki 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 göreli bir süre için olmadan MemoryCacheEntryOptionsö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 sonuyla yapılandırılır. Önbellek girdisi, bu zaman aşımı süresi içinde erişilmiş olsa bile bir gün sonra önbellekten çı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ınmış 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 sonuyla önbelleğe alınmış bir öğe 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 altındadı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. Önbellekte girdilerin boyutunu ölçen bir mekanizma 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 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ştiriciye bağlı. Belirtilen boyut, geliştiricinin seçtiği birim 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. ASP.NET Core çalışma zamanı, sistem belleği düşük olduğunda önbelleği kırpmaz. Uygulamaların mimarisinin şu şekilde tasarlanması gerekir:

  • Önbellek büyümesini sınırlayın.
  • Arama 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 girdi ö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:

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ş boyutunu uygun şekilde ayarlamayı bilen bileşenler için bağımsız bir bellek önbelleği olarak oluşturulur.

Önbellek girdisinin 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 girdisinin boyutunun ayarlanmasıyla aynı sonucu elde ediyor. SetSize , çağrıları üzerine new MemoryCacheOptions()zincirleme sırasında 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 girdilerin %25'ini kaldırmak için çağrı Compact yapar:

_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 girişin süresi dolarsa önbellek girdisinin süresinin nasıl dolmasına neden olduğu gösterilmektedir. Ö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();
}

kullanarak CancellationTokenSource birden çok önbellek girdisi grup olarak çıkarılabilir. using Yukarıdaki koddaki desenle, kapsam içinde using 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 tarayan zamanlayıcı yoktur. Önbellekteki herhangi bir etkinlik (Get, Set, Remove) sü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))
            .RegisterPostEvictionCallback((key, value, reason, state) =>
            {
                ((CancellationTokenSource)state).Dispose();
            }, cancellationTokenSource);
    
        _memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
    }
    
  • Önbellek öğesini yeniden doldurmaya yönelik bir geri çağırma kullanılırken:

    • Geri çağırma 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 girdisi başka bir önbellek girişi 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 alt ç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ğırmamış uygulamalar için içinde çağrısı AddMemoryCacheProgram.csyapı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 sonra bunları yalnızca hazır olduklarında önbelleğe atayabilir.

Ek kaynaklar

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

temel Önbelleğe Alma

Ö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 şekilde çalışır. Önbelleğe Alma, kaynaktan çok daha hızlı döndürülebilecek 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.

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çeği 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.

Runtime. Önbelleğe Alma/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, Core 3.1 veya sonraki bir sürümü ASP.NET.
  • .NET Framework 4.5 veya üzeri.

Microsoft.Extensions. Önbelleğe Alma. ASP.NET Core ile daha iyi tümleştirildiğinden bellek/IMemoryCache (bu makalede açıklanmıştırSystem.Runtime.Caching/MemoryCache) önerilir. Ö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ın System.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:
    • Önbellek anahtarları olarak dış giriş kullanmayın.
    • Önbellek büyümesini sınırlamak için süre sonu kullanma.
    • Ö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'den paylaşı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 alma 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 saatin önbellekte olup olmadığını denetlemek için kullanır TryGetValue . Bir zaman önbelleğe alınmazsa 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);
}

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

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

Aşağıdaki kod, mutlak süre sonuyla önbelleğe alınmış bir öğe 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 altındadı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:

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ı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:

  • Kayan süre sonu 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 çağırma, öğ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

Bir MemoryCache örnek isteğe bağlı olarak bir boyut sınırı belirtebilir ve zorunlu kılabilir. Önbellekte girdilerin boyutunu ölçecek bir mekanizma 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 boyutu belirtmesi gerekir. ASP.NET Core çalışma zamanı, önbellek boyutunu bellek baskısına göre sınırlamaz. Önbellek boyutunu sınırlamak geliştiriciye bağlı. Belirtilen boyut, geliştiricinin seçtiği birim 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. ASP.NET Core çalışma zamanı, sistem belleği düşük olduğunda önbelleği kırpmaz. Uygulamaların mimarisinin şu şekilde tasarlanması gerekir:

  • Önbellek büyümesini sınırlayın.
  • Arama 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 girdi boyutlarının toplamı tarafından SizeLimitbelirtilen değeri aşarsa bir girdi ö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 boyut sınırlı önbelleğin 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 kodda kullanılı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 girdisinin 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 girişin süresi dolarsa önbellek girdisinin süresinin nasıl dolmasına neden olduğu gösterilmektedir. Ö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);
}

kullanarak CancellationTokenSource birden çok önbellek girdisi grup olarak çıkarılabilir. 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 herhangi bir etkinlik (Get, Set, Remove) sü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:

    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 çağırma kullanılırken:

    • Geri çağırma 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 girdisi başka bir önbellek girişi 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 alt çocuğun süresi dolmaz.

  • Önbellek girdisi önbellekten çıkarıldıktan sonra tetiklenecek geri çağırmaları ayarlamak için kullanın PostEvictionCallbacks . Örnek kodda, CancellationTokenSource.Dispose() tarafından kullanılan yönetilmeyen kaynakları serbest bırakmak için çağrılır CancellationTokenSource. Ancak, önbellek girdisi CancellationTokenSource tarafından kullanılmaya devam ettiğinden hemen atılmaz. CancellationToken, belirli bir süre sonra süresi dolan bir önbellek girdisi oluşturmak için öğesine geçirilirMemoryCacheEntryOptions. Bu nedenle Dispose , önbellek girdisi kaldırılana veya süresi dolana kadar çağrılmamalıdır. Örnek kod, önbellek girdisi çıkarıldığında çağrılacak bir geri çağırmayı kaydetmek için yöntemini çağırır RegisterPostEvictionCallback ve bu geri çağırmaya atılır CancellationTokenSource .

  • Ç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 sonra bunları yalnızca hazır olduklarında önbelleğe atayabilir.

Ek kaynaklar