Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makalede çeşitli önbelleğe alma mekanizmaları hakkında bilgi ediniyorsunuz. Önbelleğe alma, verileri ara katmanda depolayarak sonraki veri almaları daha hızlı hale getirme işlemidir. Kavramsal olarak önbelleğe alma, performans iyileştirme stratejisi ve tasarım konusunda dikkat edilmesi gereken bir konudur. Önbelleğe alma, seyrek değişen (veya alınması pahalı) verileri daha hazır hale getirerek uygulama performansını önemli ölçüde artırabilir. Bu makalede üç önbelleğe alma yaklaşımı tanıtılarak her birine örnek kaynak kodu sağlanır:
- Microsoft.Extensions.Caching.Memory: Tek sunuculu senaryolar için bellek içi önbelleğe alma
- Microsoft.Extensions.Caching.Hybrid: Bellek içi ve dağıtılmış önbelleğe alma özelliklerini ek özelliklerle birleştiren karma önbelleğe alma
- Microsoft.Extensions.Caching.Distributed: Çok sunuculu senaryolar için dağıtılmış önbelleğe alma
Önemli
.NET içinde, biri MemoryCache ad alanında, diğeri System.Runtime.Caching ad alanında bulunan iki Microsoft.Extensions.Caching sınıf vardır.
Bu makale önbelleğe almaya odaklansa da NuGet paketini içermez System.Runtime.Caching .
MemoryCache ile ilgili tüm başvurular Microsoft.Extensions.Caching ad alanı içindedir.
Microsoft.Extensions.* Tüm paketler bağımlılık ekleme (DI) hazır duruma gelir.
IMemoryCache, HybridCacheve IDistributedCache arabirimleri hizmet olarak kullanılabilir.
Bellek içi önbellek
Bu bölümde Microsoft.Extensions.Caching.Memory paketi hakkında bilgi ediniyorsunuz.
IMemoryCache'nin mevcut uygulaması, ConcurrentDictionary<TKey,TValue> üzerinde zengin özellikli bir API sunan bir sarmalayıcıdır. Önbellekteki girdiler ile ICacheEntry temsil edilir ve herhangi biri objectolabilir. Bellek içi önbellek çözümü, önbelleğe alınan verilerin uygulama işleminde bellek kiraladığı tek bir sunucuda çalışan uygulamalar için mükemmeldir.
Tavsiye
Çok sunuculu önbelleğe alma senaryoları için, bellek içi önbelleğe almaya alternatif olarak Dağıtılmış önbelleğe alma yaklaşımını göz önünde bulundurun.
Bellek içi önbelleğe alma API'si
Önbelleğin tüketicisi hem kayan hem de mutlak süre sonu üzerinde denetime sahiptir:
- ICacheEntry.AbsoluteExpiration
- ICacheEntry.AbsoluteExpirationRelativeToNow
- ICacheEntry.SlidingExpiration
Son kullanma süresinin ayarlanması, önbellekteki girişlerin belirtilen süre içinde erişilmediklerinde silineceği anlamına gelir. Tüketiciler, MemoryCacheEntryOptions aracılığıyla önbellek girdilerini denetlemek için ek seçeneklere sahiptir. Her ICacheEntry bir MemoryCacheEntryOptions ile eşleştirilir, bu da IChangeToken ile süre sonu çıkarma işlevselliğini, CacheItemPriority ile öncelik ayarlarını ve ICacheEntry.Size öğesini denetlemeyi sağlar. İlgili uzantı yöntemleri şunlardır:
- MemoryCacheEntryExtensions.AddExpirationToken
- MemoryCacheEntryExtensions.RegisterPostEvictionCallback
- MemoryCacheEntryExtensions.SetSize
- MemoryCacheEntryExtensions.SetPriority
Bellek içi önbellek örneği
Varsayılan IMemoryCache uygulamayı kullanmak için uzantı yöntemini çağırarak AddMemoryCache tüm gerekli hizmetleri DI'ye kaydedin. Aşağıdaki kod örneğinde, GENEL ana bilgisayar DI işlevselliğini kullanıma açmak için kullanılır:
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
using IHost host = builder.Build();
.NET iş yükünüze bağlı olarak, oluşturucu enjeksiyonu gibi farklı yöntemlerle IMemoryCache'e erişebilirsiniz. Bu örnekte, IServiceProvider örneğini host üzerinde kullanarak genel GetRequiredService<T>(IServiceProvider) uzantı yöntemini çağırırsınız.
IMemoryCache cache =
host.Services.GetRequiredService<IMemoryCache>();
Bellek içi önbelleğe alma hizmetleri kayıtlı ve DI aracılığıyla çözümlenmiş durumdayken önbelleğe almaya başlamaya hazırsınız. Bu örnek, İngilizce 'A' ile 'Z' alfabesindeki harfler arasında yinelenir.
record AlphabetLetter türü harfle ilgili başvuruyu içerir ve bir mesaj üretir.
file record AlphabetLetter(char Letter)
{
internal string Message =>
$"The '{Letter}' character is the {Letter - 64} letter in the English alphabet.";
}
Tavsiye
file erişim belirleyicisi AlphabetLetter türünde kullanılır, çünkü bu tür Program.cs dosyası içinde tanımlanmış ve yalnızca bu dosyadan erişilebilmektedir. Daha fazla bilgi için bkz. dosya (C# Başvurusu). Kaynak kodunun tamamını görmek için Program.cs bölümüne bakın.
Örnek, alfabe harflerini yineleyen bir yardımcı işlev içerir:
static async ValueTask IterateAlphabetAsync(
Func<char, Task> asyncFunc)
{
for (char letter = 'A'; letter <= 'Z'; ++letter)
{
await asyncFunc(letter);
}
Console.WriteLine();
}
Yukarıdaki C# kodunda:
-
Func<char, Task> asyncFuncher yinelemede, mevcutletteriletilerek bekleniyor. - Tüm harfler işlendikten sonra konsola boş bir satır yazılır.
Önbelleğe öğe eklemek için Create veya Set API'lerinden birini çağırın.
var addLettersToCacheTask = IterateAlphabetAsync(letter =>
{
MemoryCacheEntryOptions options = new()
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
};
_ = options.RegisterPostEvictionCallback(OnPostEviction);
AlphabetLetter alphabetLetter =
cache.Set(
letter, new AlphabetLetter(letter), options);
Console.WriteLine($"{alphabetLetter.Letter} was cached.");
return Task.Delay(
TimeSpan.FromMilliseconds(MillisecondsDelayAfterAdd));
});
await addLettersToCacheTask;
Yukarıdaki C# kodunda:
- Değişken
addLettersToCacheTask'ye devredilir veIterateAlphabetAsyncbeklenir. -
Func<char, Task> asyncFunclambda ile argüman edilir. -
MemoryCacheEntryOptionsörneği, şu an itibarıyla mutlak bir son kullanma tarihine sahip olarak oluşturulur. - Tahliye sonrası geri çağırma işlemi kaydedildi.
- Bir
AlphabetLetternesne örneği oluşturulur ve ve Setile birlikteletteriçineoptionsgeçirilir. - Harf konsola önbelleğe alınmış olarak yazılır.
- Son olarak, bir Task.Delay döndürülür.
Alfabedeki her harf için, son kullanma tarihi ve silme sonrası geri çağırma işlemi ile bir önbellek girişi yazılır.
Çıkarma sonrası geri çağırma, çıkarılan değerin detaylarını konsola yazar.
static void OnPostEviction(
object key, object? letter, EvictionReason reason, object? state)
{
if (letter is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{alphabetLetter.Letter} was evicted for {reason}.");
}
};
Artık önbellek dolduruldu, ancak bu kez IterateAlphabetAsync yerine IMemoryCache.TryGetValue çağrısını bekliyorsunuz.
var readLettersFromCacheTask = IterateAlphabetAsync(letter =>
{
if (cache.TryGetValue(letter, out object? value) &&
value is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{letter} is still in cache. {alphabetLetter.Message}");
}
return Task.CompletedTask;
});
await readLettersFromCacheTask;
Eğer cache, letter anahtarını içeriyorsa ve value, bir AlphabetLetter örneğiyse, konsola yazdırılır.
letter Anahtar önbellekte olmadığında çıkarıldı ve çıkarılma sonrası geri çağırma işlevi tetiklendi.
Ek uzantı yöntemleri
IMemoryCache işlevsellik açısından birçok uzantı yöntemi sunar ve bu yöntemler arasında zaman uyumsuz bir GetOrCreateAsync bulunmaktadır:
- CacheExtensions.Get
- CacheExtensions.GetOrCreate
- CacheExtensions.GetOrCreateAsync
- CacheExtensions.Set
- CacheExtensions.TryGetValue
Hepsini bir araya getirin
Örnek uygulama kaynak kodunun tamamı üst düzey bir programdır ve iki NuGet paketi gerektirir:
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
using IHost host = builder.Build();
IMemoryCache cache =
host.Services.GetRequiredService<IMemoryCache>();
const int MillisecondsDelayAfterAdd = 50;
const int MillisecondsAbsoluteExpiration = 750;
static void OnPostEviction(
object key, object? letter, EvictionReason reason, object? state)
{
if (letter is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{alphabetLetter.Letter} was evicted for {reason}.");
}
};
static async ValueTask IterateAlphabetAsync(
Func<char, Task> asyncFunc)
{
for (char letter = 'A'; letter <= 'Z'; ++letter)
{
await asyncFunc(letter);
}
Console.WriteLine();
}
var addLettersToCacheTask = IterateAlphabetAsync(letter =>
{
MemoryCacheEntryOptions options = new()
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
};
_ = options.RegisterPostEvictionCallback(OnPostEviction);
AlphabetLetter alphabetLetter =
cache.Set(
letter, new AlphabetLetter(letter), options);
Console.WriteLine($"{alphabetLetter.Letter} was cached.");
return Task.Delay(
TimeSpan.FromMilliseconds(MillisecondsDelayAfterAdd));
});
await addLettersToCacheTask;
var readLettersFromCacheTask = IterateAlphabetAsync(letter =>
{
if (cache.TryGetValue(letter, out object? value) &&
value is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{letter} is still in cache. {alphabetLetter.Message}");
}
return Task.CompletedTask;
});
await readLettersFromCacheTask;
await host.RunAsync();
file record AlphabetLetter(char Letter)
{
internal string Message =>
$"The '{Letter}' character is the {Letter - 64} letter in the English alphabet.";
}
Önbelleğe alınan girdilerin süre sonu ve çıkarma davranışındaki değişiklikleri gözlemlemek için MillisecondsDelayAfterAdd ve MillisecondsAbsoluteExpiration değerlerini ayarlayabilirsiniz. Aşağıda, bu kodun çalıştırılmasından elde edilen örnek çıkış verilmiştir. (.NET olaylarının belirsiz doğası nedeniyle çıkışınız farklı olabilir.)
A was cached.
B was cached.
C was cached.
D was cached.
E was cached.
F was cached.
G was cached.
H was cached.
I was cached.
J was cached.
K was cached.
L was cached.
M was cached.
N was cached.
O was cached.
P was cached.
Q was cached.
R was cached.
S was cached.
T was cached.
U was cached.
V was cached.
W was cached.
X was cached.
Y was cached.
Z was cached.
A was evicted for Expired.
C was evicted for Expired.
B was evicted for Expired.
E was evicted for Expired.
D was evicted for Expired.
F was evicted for Expired.
H was evicted for Expired.
K was evicted for Expired.
L was evicted for Expired.
J was evicted for Expired.
G was evicted for Expired.
M was evicted for Expired.
N was evicted for Expired.
I was evicted for Expired.
P was evicted for Expired.
R was evicted for Expired.
O was evicted for Expired.
Q was evicted for Expired.
S is still in cache. The 'S' character is the 19 letter in the English alphabet.
T is still in cache. The 'T' character is the 20 letter in the English alphabet.
U is still in cache. The 'U' character is the 21 letter in the English alphabet.
V is still in cache. The 'V' character is the 22 letter in the English alphabet.
W is still in cache. The 'W' character is the 23 letter in the English alphabet.
X is still in cache. The 'X' character is the 24 letter in the English alphabet.
Y is still in cache. The 'Y' character is the 25 letter in the English alphabet.
Z is still in cache. The 'Z' character is the 26 letter in the English alphabet.
Mutlak süre sonu (MemoryCacheEntryOptions.AbsoluteExpirationRelativeToNow) ayarlandığından, önbelleğe alınan tüm öğeler sonunda çıkarılır.
İşçi Servisi önbellekleme
Verileri önbelleğe almaya yönelik yaygın stratejilerden biri, önbelleği tüketen veri hizmetlerinden bağımsız olarak güncelleştirmektir.
Çalışan Hizmeti şablonu, BackgroundService diğer uygulama kodundan bağımsız olarak (veya arka planda) çalıştığı için harika bir örnektir. uygulamasını barındıran bir IHostedServiceuygulama çalışmaya başladığında, buna karşılık gelen uygulama (bu örnekte BackgroundService veya "çalışan") aynı işlemde çalışmaya başlar. Bu barındırılan hizmetler, uzantı metoduyla singleton olarak DI'ye AddHostedService<THostedService>(IServiceCollection) kaydedilir. Diğer hizmetler herhangi bir hizmet ömrüyle DI'ye kaydedilebilir.
Önemli
Hizmet ömürlerinin anlaşılması önemlidir. Bellek içi önbelleğe alma hizmetlerinin tümünü kaydetmek için AddMemoryCache çağırdığınızda, hizmetler birer singleton olarak kaydedilir.
Fotoğraf hizmeti senaryosu
HTTP üzerinden erişilebilen üçüncü taraf API'sini kullanan bir fotoğraf hizmeti geliştirdiğinizi düşünün. Bu fotoğraf verileri sık sık değişmez, ancak çok fazladır. Her fotoğraf basit bir record ile temsil edilir:
namespace CachingExamples.Memory;
public readonly record struct Photo(
int AlbumId,
int Id,
string Title,
string Url,
string ThumbnailUrl);
Aşağıdaki örnekte, DI'ye kayıtlı birkaç hizmet görürsünüz. Her hizmetin tek bir sorumluluğu vardır.
using CachingExamples.Memory;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
builder.Services.AddHttpClient<CacheWorker>();
builder.Services.AddHostedService<CacheWorker>();
builder.Services.AddScoped<PhotoService>();
builder.Services.AddSingleton(typeof(CacheSignal<>));
using IHost host = builder.Build();
await host.StartAsync();
Yukarıdaki C# kodunda:
- Genel konak varsayılan değerlerle oluşturulur.
- Bellek içi önbellek hizmetleri AddMemoryCache olarak kaydedilir.
-
HttpClientörneği,CacheWorkerile AddHttpClient<TClient>(IServiceCollection) sınıfı için kaydedilir. -
CacheWorkersınıfı AddHostedService<THostedService>(IServiceCollection) ile kaydedilir. -
PhotoServicesınıfı AddScoped<TService>(IServiceCollection) ile kaydedilir. -
CacheSignal<T>sınıfı AddSingleton ile kaydedilir. -
hostoluşturucudan örneği oluşturulur ve zaman uyumsuz olarak başlatılır.
PhotoService verilen ölçütlere (veyafilter) uyan fotoğrafları almakla sorumludur:
using Microsoft.Extensions.Caching.Memory;
namespace CachingExamples.Memory;
public sealed class PhotoService(
IMemoryCache cache,
CacheSignal<Photo> cacheSignal,
ILogger<PhotoService> logger)
{
public async IAsyncEnumerable<Photo> GetPhotosAsync(Func<Photo, bool>? filter = default)
{
try
{
await cacheSignal.WaitAsync();
Photo[] photos =
(await cache.GetOrCreateAsync(
"Photos", _ =>
{
logger.LogWarning("This should never happen!");
return Task.FromResult(Array.Empty<Photo>());
}))!;
// If no filter is provided, use a pass-thru.
filter ??= _ => true;
foreach (Photo photo in photos)
{
if (!default(Photo).Equals(photo) && filter(photo))
{
yield return photo;
}
}
}
finally
{
cacheSignal.Release();
}
}
}
Yukarıdaki C# kodunda:
- Oluşturucu bir
IMemoryCache,CacheSignal<Photo>veILoggergerektirir. - Yöntemi
GetPhotosAsync:- Bir
Func<Photo, bool> filterparametre tanımlar ve döndürürIAsyncEnumerable<Photo>. -
_cacheSignal.WaitAsync()öğesini çağırır ve yayımlanmasını bekler; bu, önbelleğe erişmeden önce önbelleğin doldurulmasını sağlar. -
_cache.GetOrCreateAsync()çağrısını yapar ve önbellekteki tüm fotoğrafları zaman uyumsuz bir şekilde alır. - Bağımsız
factorydeğişken bir uyarı kaydeder ve boş bir fotoğraf dizisi döndürür; bu hiçbir zaman gerçekleşmemelidir. - Önbellekteki her fotoğraf tek tek işlenir, filtrelenir ve
yield returnile somutlaştırılır. - Son olarak önbellek sinyali sıfırlanır.
- Bir
Bu hizmetin tüketicileri, GetPhotosAsync yöntemini çağırmak ve fotoğrafları buna göre işlemek için serbesttir. Önbellek fotoğrafları içerdiğinden hayır HttpClient gerekli değildir.
Zaman uyumsuz sinyal, genel tür kısıtlamalı tekil bir örnek içinde kapsüllenmiş SemaphoreSlim örneğine dayanır.
CacheSignal<T> bir örneğine dayanan SemaphoreSlim üzerinde çalışır.
namespace CachingExamples.Memory;
public sealed class CacheSignal<T>
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
/// <summary>
/// Exposes a <see cref="Task"/> that represents the asynchronous wait operation.
/// When signaled (consumer calls <see cref="Release"/>), the
/// <see cref="Task.Status"/> is set as <see cref="TaskStatus.RanToCompletion"/>.
/// </summary>
public Task WaitAsync() => _semaphore.WaitAsync();
/// <summary>
/// Exposes the ability to signal the release of the <see cref="WaitAsync"/>'s operation.
/// Callers who were waiting, will be able to continue.
/// </summary>
public void Release() => _semaphore.Release();
}
Yukarıdaki C# kodunda, dekoratör deseni bir örneğini SemaphoreSlimsarmak için kullanılır.
CacheSignal<T> tekil olarak kaydedildiğinden, tüm hizmet ömrü boyunca herhangi bir genel türle (bu örnekte, Photo) kullanılabilir. Önbelleğin tohumlanması için sinyal göndermekten sorumludur.
CacheWorker, BackgroundService sınıfının bir alt sınıfıdır:
using System.Net.Http.Json;
using Microsoft.Extensions.Caching.Memory;
namespace CachingExamples.Memory;
public sealed class CacheWorker(
ILogger<CacheWorker> logger,
HttpClient httpClient,
CacheSignal<Photo> cacheSignal,
IMemoryCache cache) : BackgroundService
{
private readonly TimeSpan _updateInterval = TimeSpan.FromHours(3);
private bool _isCacheInitialized = false;
private const string Url = "https://jsonplaceholder.typicode.com/photos";
public override async Task StartAsync(CancellationToken cancellationToken)
{
await cacheSignal.WaitAsync();
await base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
logger.LogInformation("Updating cache.");
try
{
Photo[]? photos =
await httpClient.GetFromJsonAsync<Photo[]>(
Url, stoppingToken);
if (photos is { Length: > 0 })
{
cache.Set("Photos", photos);
logger.LogInformation(
"Cache updated with {Count:#,#} photos.", photos.Length);
}
else
{
logger.LogWarning(
"Unable to fetch photos to update cache.");
}
}
finally
{
if (!_isCacheInitialized)
{
cacheSignal.Release();
_isCacheInitialized = true;
}
}
try
{
logger.LogInformation(
"Will attempt to update the cache in {Hours} hours from now.",
_updateInterval.Hours);
await Task.Delay(_updateInterval, stoppingToken);
}
catch (OperationCanceledException)
{
logger.LogWarning("Cancellation acknowledged: shutting down.");
break;
}
}
}
}
Yukarıdaki C# kodunda:
- Oluşturucu bir
ILogger,HttpClientveIMemoryCachegerektirir. -
_updateIntervalüç saat için tanımlanır. - Yöntemi
ExecuteAsync:- Uygulama çalışırken döngüler.
-
"https://jsonplaceholder.typicode.com/photos"için bir HTTP isteği yapar ve yanıtıPhotoobjeleri olarak eşler. - Fotoğraf dizisi,
IMemoryCache'da"Photos"anahtarının altında yerleştirilir. -
_cacheSignal.Release()çağrılır ve sinyali bekleyen tüm tüketiciler serbest bırakılır. - Çağrı Task.Delay, güncelleme aralığına göre bekleniyor.
- Üç saat geciktirildikten sonra önbellek yeniden güncelleştirilir.
Aynı süreçteki tüketiciler IMemoryCache fotoğrafları isteyebilir, ancak önbelleği güncellemekten sorumlu olan CacheWorker'dır.
Harmanlamalı önbellekleme
Kitaplık, HybridCache mevcut önbelleğe alma API'leriyle ilgili yaygın zorlukları giderirken bellek içi ve dağıtılmış önbelleğe almanın avantajlarını birleştirir. .NET 9'da kullanıma sunulan HybridCache, önbelleğe alma uygulamasını basitleştiren ve aşırı yük koruması ile yapılandırılabilir serileştirme gibi dahili özellikler içeren birleşik bir API sağlar.
Temel özellikler
HybridCacheve IMemoryCache ayrı olarak kullanımına IDistributedCache göre çeşitli avantajlar sunar:
- İki düzeyli önbelleğe alma: Hem bellek içi (L1) hem de dağıtılmış (L2) önbellek katmanlarını otomatik olarak yönetir. Veriler önce hız için bellek içi önbellekten, sonra gerekirse dağıtılmış önbellekten ve son olarak kaynaktan alınır.
- Damgalı koruma: Birden çok eşzamanlı isteğin aynı pahalı işlemi yürütmesini engeller. Yalnızca bir istek verileri getirirken diğerleri sonucu bekler.
- Yapılandırılabilir serileştirme: JSON (varsayılan), protobuf ve XML gibi birden çok serileştirme biçimlerini destekler.
- Etiket tabanlı geçersizleştirme: Verimli toplu geçersizleştirme için ilgili önbellek girdilerini etiketlerle gruplandırır.
-
Basitleştirilmiş API:
GetOrCreateAsyncYöntemi önbellek eksiklerini, serileştirmeyi ve depolamayı otomatik olarak işler.
HybridCache ne zaman kullanılır?
Şu durumlarda kullanmayı HybridCache göz önünde bulundurun:
- Çok sunuculu bir ortamda hem yerel (bellek içi) hem de dağıtılmış önbelleğe ihtiyacınız vardır.
- Önbellek saldırganı senaryolarına karşı koruma istiyorsunuz.
- Manuel olarak
IMemoryCacheveIDistributedCachekoordine etmek yerine basitleştirilmiş bir API'yi tercih ediyorsunuz. - İlgili girdiler için etiket tabanlı önbellek geçersiz kılınması gerekir.
Tavsiye
Basit önbelleğe alma gereksinimleri olan tek sunuculu uygulamalar için bellek içi önbelleğe alma yeterli olabilir. Damgalı koruma veya etiket tabanlı geçersizleştirme gerektirmeyen çok sunuculu uygulamalar için dağıtılmış önbelleğe almayı göz önünde bulundurun.
HybridCache kurulumu
HybridCache kullanmak için Microsoft.Extensions.Caching.Hybrid NuGet paketini yükleyin:
dotnet add package Microsoft.Extensions.Caching.Hybrid
HybridCache komutunu çağırarak AddHybridCachehizmeti DI ile kaydedin:
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHybridCache();
Yukarıdaki kod varsayılan seçeneklerle birlikte kaydeder HybridCache . Genel seçenekleri de yapılandırabilirsiniz:
var builderWithOptions = Host.CreateApplicationBuilder(args);
builderWithOptions.Services.AddHybridCache(options =>
{
options.MaximumPayloadBytes = 1024 * 1024; // 1 MB
options.MaximumKeyLength = 1024;
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(5),
LocalCacheExpiration = TimeSpan.FromMinutes(2)
};
});
Temel kullanım
ile HybridCache etkileşim kurmanın birincil yöntemidir GetOrCreateAsync. Bu yöntem, belirtilen anahtara sahip bir girdi için önbelleği denetler ve bulunamazsa verileri almak için fabrika yöntemini çağırır:
async Task<WeatherData> GetWeatherDataAsync(HybridCache cache, string city)
{
return await cache.GetOrCreateAsync(
$"weather:{city}",
async cancellationToken =>
{
// Simulate fetching from an external API
await Task.Delay(100, cancellationToken);
return new WeatherData(city, 72, "Sunny");
}
);
}
Yukarıdaki C# kodunda:
-
GetOrCreateAsyncyöntemi benzersiz bir anahtar ve bir fabrika yöntemi alır. - Veriler önbellekte değilse, verileri almak için fabrika yöntemi çağrılır.
- Veriler hem bellek içi hem de dağıtılmış önbelleklerde otomatik olarak depolanır.
- Fabrika yöntemini yalnızca bir eşzamanlı istek yürütür; diğerleri sonucu bekler.
Giriş seçenekleri
kullanarak HybridCacheEntryOptionsbelirli önbellek girdileri için genel varsayılanları geçersiz kılabilirsiniz:
async Task<WeatherData> GetWeatherWithOptionsAsync(HybridCache cache, string city)
{
var entryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(10),
LocalCacheExpiration = TimeSpan.FromMinutes(5)
};
return await cache.GetOrCreateAsync(
$"weather:{city}",
async cancellationToken => new WeatherData(city, 72, "Sunny"),
entryOptions
);
}
Giriş seçenekleri şunları yapılandırmanıza olanak sağlar:
- HybridCacheEntryOptions.Expiration: Girdinin dağıtılmış önbellekte ne kadar süreyle önbelleğe alınması gerektiği.
- HybridCacheEntryOptions.LocalCacheExpiration: Girdinin yerel bellekte ne kadar süreyle önbelleğe alınması gerektiği.
- HybridCacheEntryOptions.Flags: Önbellek davranışını denetlemek için ek bayraklar.
Etiket tabanlı geçersizleştirme
Etiketler, ilgili önbellek girdilerini gruplandırmanıza ve bunları birlikte geçersiz kılmanıza olanak sağlar. Bu, ilgili verilerin bir birim olarak yenilenmesi gereken senaryolar için kullanışlıdır:
async Task<CustomerData> GetCustomerAsync(HybridCache cache, int customerId)
{
var tags = new[] { "customer", $"customer:{customerId}" };
return await cache.GetOrCreateAsync(
$"customer:{customerId}",
async cancellationToken => new CustomerData(customerId, "John Doe", "john@example.com"),
new HybridCacheEntryOptions { Expiration = TimeSpan.FromMinutes(30) },
tags
);
}
Belirli bir etikete sahip tüm girişleri geçersiz kılma:
async Task InvalidateCustomerCacheAsync(HybridCache cache, int customerId)
{
await cache.RemoveByTagAsync($"customer:{customerId}");
}
Aynı anda birden çok etiketi de geçersiz kılabilirsiniz:
async Task InvalidateAllCustomersAsync(HybridCache cache)
{
await cache.RemoveByTagAsync(new[] { "customer", "orders" });
}
Uyarı
Etiket tabanlı geçersizleştirme mantıksal bir işlemdir. Önbellekteki değerleri etkin bir şekilde kaldırmaz, ancak etiketli girişlerin önbellek eksikleri olarak değerlendirilmesini sağlar. Kayıtlar, yapılandırılmış yaşam süreleri dolduğunda sona erer.
Önbellek girdilerini kaldırma
Belirli bir önbellek girdisini anahtara göre kaldırmak için yöntemini RemoveAsync kullanın:
async Task RemoveWeatherDataAsync(HybridCache cache, string city)
{
await cache.RemoveAsync($"weather:{city}");
}
Önbelleğe alınan tüm girişleri geçersiz kılmaya yönelik ayrılmış joker karakter etiketini "*"kullanın:
async Task InvalidateAllCacheAsync(HybridCache cache)
{
await cache.RemoveByTagAsync("*");
}
Serialization
Dağıtılmış önbelleğe alma senaryoları için HybridCache serileştirme gerekir. Varsayılan olarak, `string` ve `byte[]` etiketlerini dahili olarak işler ve diğer türler için `System.Text.Json` kullanır. Özel serileştiricileri belirli türler için yapılandırabilir veya genel amaçlı seri hale getirici kullanabilirsiniz:
// Custom serialization example
// Note: This requires implementing a custom IHybridCacheSerializer<T>
var builderWithSerializer = Host.CreateApplicationBuilder(args);
builderWithSerializer.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(10),
LocalCacheExpiration = TimeSpan.FromMinutes(5)
};
});
// To add a custom serializer, uncomment and provide your implementation:
// .AddSerializer<WeatherData, CustomWeatherDataSerializer>();
Dağıtılmış önbelleği yapılandırma
HybridCache , dağıtılmış (L2) önbelleği için yapılandırılmış IDistributedCache uygulamayı kullanır. Yapılandırılmamış olsa bile, IDistributedCache yine de bellek içi önbellekleme ve yığılma koruması sağlar. Redis'i dağıtılmış önbellek olarak eklemek için:
// Distributed cache with Redis
var builderWithRedis = Host.CreateApplicationBuilder(args);
builderWithRedis.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
});
builderWithRedis.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(30),
LocalCacheExpiration = TimeSpan.FromMinutes(5)
};
});
Dağıtılmış önbellek uygulamaları hakkında daha fazla bilgi için bkz. Dağıtılmış önbelleğe alma.
Dağıtık önbellekleme
Bazı senaryolarda, birden çok uygulama sunucusu için olduğu gibi dağıtılmış önbellek gerekir. Dağıtılmış önbellek, bellek içi önbelleğe alma yaklaşımından daha yüksek ölçek genişletmeyi destekler. Dağıtılmış önbellek kullanmak, önbellek belleğini harici bir sürece aktarır, ancak ek ağ G/Ç gerektirir ve biraz daha fazla gecikme süresi (nominal olsa bile) ortaya çıkarır.
Dağıtılmış önbelleğe alma soyutlamaları NuGet paketinin Microsoft.Extensions.Caching.Memory bir parçasıdır ve bir AddDistributedMemoryCache uzantı yöntemi bile vardır.
Dikkat
AddDistributedMemoryCache yalnızca geliştirme veya test senaryolarında kullanılmalıdır ve uygulanabilir bir üretim uygulaması değildir .
Aşağıdaki paketlerden herhangi bir kullanılabilir uygulamasını IDistributedCache göz önünde bulundurun:
Microsoft.Extensions.Caching.SqlServerMicrosoft.Extensions.Caching.StackExchangeRedisNCache.Microsoft.Extensions.Caching.OpenSource
Dağıtılmış önbelleğe alma API'si
Dağıtılmış önbelleğe alma API'leri, bellek içi önbelleğe alma API'lerinden biraz daha temeldir. Anahtar-değer çiftleri biraz daha temeldir. Bellek içi önbelleğe alma anahtarları bir objecttabanlıyken, dağıtılmış anahtarlar bir string'dır. Bellek içi önbelleğe alma ile, değer kesin türde bir genel değer olabilirken, dağıtılmış önbelleğe almadaki değerler byte[] olarak saklanır. Bu, çeşitli uygulamaların kesin olarak belirlenmiş genel değerleri kullanıma sunmadığını söylemek değildir, ancak bu bir uygulama ayrıntısıdır.
Değer oluşturma
Dağıtılmış önbellekte değer oluşturmak için ayarlanan API'lerden birini çağırın:
Bellek içi önbellek örneğindeki AlphabetLetter kaydını kullanarak, nesneyi JSON olarak serileştirip string'yi byte[] olarak kodlayabilirsiniz.
DistributedCacheEntryOptions options = new()
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
};
AlphabetLetter alphabetLetter = new(letter);
string json = JsonSerializer.Serialize(alphabetLetter);
byte[] bytes = Encoding.UTF8.GetBytes(json);
await cache.SetAsync(letter.ToString(), bytes, options);
Bellek içi önbellekleme gibi önbellek girişleri de önbellekte varlıklarının ince bir şekilde ayarlanmasına yardımcı olacak seçeneklere sahip olabilir. Bu durumda DistributedCacheEntryOptions.
Uzantı yöntemleri oluşturma
Değer oluşturmak için birkaç kolaylık tabanlı uzantı yöntemi vardır. Bu yöntemler, nesnelerin string temsillerinin bir byte[] içine kodlanmasını önlemeye yardımcı olur.
Değerleri okuma
Dağıtılmış önbellekteki değerleri okumak için API'lerden birini çağırın Get :
AlphabetLetter? alphabetLetter = null;
byte[]? bytes = await cache.GetAsync(letter.ToString());
if (bytes is { Length: > 0 })
{
string json = Encoding.UTF8.GetString(bytes);
alphabetLetter = JsonSerializer.Deserialize<AlphabetLetter>(json);
}
Önbellek girdisi önbellekten okunduktan sonra UTF8 kodlanmış string gösterimini byte[]'den alabilirsiniz.
Uzantı yöntemlerini inceleme
Değerleri okumak için birkaç kolaylık tabanlı uzantı yöntemi vardır. Bu yöntemler byte[]'nin nesne temsillerine string kod çözülmesini önlemeye yardımcı olur.
Değerleri güncelleştirme
Dağıtılmış önbellekteki değerleri tek bir API çağrısıyla güncelleştirmenin hiçbir yolu yoktur. Bunun yerine, değerlerin kayan süre sonu değerlerini yenileme API'lerinden biriyle sıfırlayabilir:
Gerçek değerin güncelleştirilmesi gerekiyorsa, değeri silip yeniden eklemeniz gerekir.
Değerleri silme
Dağıtılmış önbellekteki değerleri silmek için API'lerden birini çağırın Remove :
Tavsiye
Bu API'lerin zaman uyumlu sürümleri olsa da, dağıtılmış önbellek uygulamalarının ağ G/Ç'sine bağlı olduğunu göz önünde bulundurun. Bu nedenle, genellikle zaman uyumsuz API'lerin kullanılması tercih edilir.