이 문서에서는 다양한 캐싱 메커니즘에 대해 알아봅니다. 캐싱은 중간 계층에 데이터를 저장하여 후속 데이터 검색을 더 빠르게 만드는 작업입니다. 개념적으로 캐싱은 성능 최적화 전략 및 디자인 고려 사항입니다. 캐싱은 자주 변경되지 않거나 검색 비용이 많이 드는 데이터를 더 쉽게 사용할 수 있게 함으로써 앱 성능을 크게 향상시킬 수 있습니다. 이 문서에서는 두 가지 기본 유형의 캐싱을 소개하고 두 가지 모두에 대한 샘플 소스 코드를 제공합니다.
중요합니다
.NET 내에는 두 개의 MemoryCache
클래스가 System.Runtime.Caching
네임스페이스와 Microsoft.Extensions.Caching
네임스페이스에 각각 하나씩 있습니다.
이 문서에서는 캐싱에 중점을 두지만 NuGet 패키지는 System.Runtime.Caching
포함하지 않습니다. 모든 MemoryCache
참조는 Microsoft.Extensions.Caching
네임스페이스 내에 있습니다.
모든 Microsoft.Extensions.*
패키지는 종속성 주입(DI)에 사용할 준비가 되어 있으며, IMemoryCache 및 IDistributedCache 인터페이스를 각각 서비스로 사용할 수 있습니다.
메모리 내 캐싱
이 섹션에서는 Microsoft.Extensions.Caching.Memory 패키지에 대해 알아봅니다. 현재 구현된 IMemoryCache는 ConcurrentDictionary<TKey,TValue> 주위에 래퍼를 구현한 것으로, 기능이 풍부한 API를 제공합니다. 캐시 내의 항목은 다음과 같이 ICacheEntry로 표시되며, 어떤 object
일 수도 있습니다. 메모리 내 캐시 솔루션은 캐시된 모든 데이터가 앱 프로세스에서 메모리를 임대하는 단일 서버에서 실행되는 앱에 적합합니다.
팁 (조언)
다중 서버 캐싱 시나리오의 경우 메모리 내 캐싱 대신 분산 캐싱 방법을 고려합니다.
메모리 내 캐싱 API
캐시의 소비자는 슬라이딩 및 절대 만료를 모두 제어할 수 있습니다.
- ICacheEntry.AbsoluteExpiration
- ICacheEntry.AbsoluteExpirationRelativeToNow
- ICacheEntry.SlidingExpiration
만료를 설정하면 만료 시간 할당 내에 액세스하지 않으면 캐시의 항목이 제거 됩니다. 소비자는 캐시 항목을 제어할 수 있는 추가 옵션을 MemoryCacheEntryOptions를 통해 이용할 수 있습니다. 각각의 ICacheEntry는 MemoryCacheEntryOptions와 짝을 이루며, IChangeToken를 통해 만료 제거 기능을 노출하고, CacheItemPriority를 통해 우선 순위 설정을 제공하며, ICacheEntry.Size를 제어합니다. 다음 확장 메서드를 고려합니다.
- MemoryCacheEntryExtensions.AddExpirationToken
- MemoryCacheEntryExtensions.RegisterPostEvictionCallback
- MemoryCacheEntryExtensions.SetSize
- MemoryCacheEntryExtensions.SetPriority
메모리 내 캐시 예제
기본 IMemoryCache 구현을 사용하려면 확장 메서드를 AddMemoryCache 호출하여 필요한 모든 서비스를 DI에 등록합니다. 다음 코드 샘플에서 제네릭 호스트는 DI 기능을 노출하는 데 사용됩니다.
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 워크로드에 따라 IMemoryCache
에 접근하는 방법이 다를 수 있으며, 그 예로 생성자 주입이 있습니다. 이 샘플에서는 IServiceProvider
에서 host
인스턴스를 사용하고 제네릭 GetRequiredService<T>(IServiceProvider) 확장 메서드를 호출합니다.
IMemoryCache cache =
host.Services.GetRequiredService<IMemoryCache>();
메모리 내 캐싱 서비스를 등록하고 DI를 통해 확인하면 캐싱을 시작할 준비가 된 것입니다. 이 샘플은 영어 알파벳의 'A'부터 'Z'까지의 각 문자를 순차적으로 반복합니다. 이 형식은 record AlphabetLetter
문자에 대한 참조를 유지하고 메시지를 생성합니다.
file record AlphabetLetter(char Letter)
{
internal string Message =>
$"The '{Letter}' character is the {Letter - 64} letter in the English alphabet.";
}
팁 (조언)
file
파일 내에서 정의되고 액세스되기 때문에 AlphabetLetter
형식에 액세스 한정자가 사용됩니다. 자세한 내용은 파일(C# 참조)을 참조하세요. 전체 소스 코드를 보려면 Program.cs 섹션을 참조하세요.
샘플에는 알파벳 문자를 반복하는 도우미 함수가 포함되어 있습니다.
static async ValueTask IterateAlphabetAsync(
Func<char, Task> asyncFunc)
{
for (char letter = 'A'; letter <= 'Z'; ++letter)
{
await asyncFunc(letter);
}
Console.WriteLine();
}
위의 C# 코드에서:
- 각
Func<char, Task> asyncFunc
반복에서 대기하여 현재letter
를 전달합니다. - 모든 문자가 처리되면 콘솔에 빈 줄이 기록됩니다.
캐시에 항목을 추가하려면 다음 중 하나 또는 Create
API를 Set
호출합니다.
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;
위의 C# 코드에서:
- 변수
addLettersToCacheTask
가IterateAlphabetAsync
에게 위임되고 대기됩니다. -
Func<char, Task> asyncFunc
람다로 주장된다. - 현재 시점을 기준으로
MemoryCacheEntryOptions
가 절대 만료로 인스턴스화됩니다. - 퇴거 후 콜백이 등록됩니다.
-
AlphabetLetter
개체가 인스턴스화된 후, Set에letter
및options
와 함께 전달됩니다. - 문자는 캐시되는 것으로 콘솔에 기록됩니다.
- 마지막으로 하나가 Task.Delay 반환됩니다.
알파벳의 각 문자에 대해, 만료와 제거 후 콜백이 포함된 캐시 항목이 작성됩니다.
제거 후 콜백은 제거된 값의 세부 정보를 콘솔에 기록합니다.
static void OnPostEviction(
object key, object? letter, EvictionReason reason, object? state)
{
if (letter is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{alphabetLetter.Letter} was evicted for {reason}.");
}
};
이렇게 캐시가 채워졌으므로, 이제 IterateAlphabetAsync
에 대한 또 다른 호출이 기대됩니다. 하지만 이번에는 IMemoryCache.TryGetValue을 호출합니다.
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;
cache
가 letter
키를 포함하고 있으며, 만약 value
가 AlphabetLetter
의 인스턴스일 경우, 콘솔에 기록됩니다.
letter
키가 캐시에 없으면 제거되고 제거 후 콜백이 호출되었습니다.
추가 확장 메서드
IMemoryCache
와 GetOrCreateAsync
를 비롯한 많은 편리한 확장 메서드가 비동기로 함께 제공됩니다.
- CacheExtensions.Get
- CacheExtensions.GetOrCreate
- CacheExtensions.GetOrCreateAsync
- CacheExtensions.Set
- CacheExtensions.TryGetValue
전부 합치세요
전체 샘플 앱 소스 코드는 최상위 프로그램이며 두 개의 NuGet 패키지가 필요합니다.
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.";
}
캐시된 항목의 만료 및 제거에 대한 동작 변화를 관찰할 수 있도록 MillisecondsDelayAfterAdd
및 MillisecondsAbsoluteExpiration
값을 자유롭게 조정하세요. 다음은 이 코드를 실행하는 샘플 출력입니다. .NET 이벤트의 비결정적 특성으로 인해 출력이 다를 수 있습니다.
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.
절대 만료(MemoryCacheEntryOptions.AbsoluteExpirationRelativeToNow)가 설정되었으므로 캐시된 모든 항목은 결국 제거됩니다.
작업 서비스 캐싱
데이터를 캐싱하기 위한 일반적인 전략 중 하나는 캐시를 소비하는 데이터 서비스와 독립적으로 업데이트하는 것입니다.
작업자 서비스 템플릿은 다른 애플리케이션 코드와 독립적으로(또는 백그라운드에서) 실행되므로 BackgroundService 좋은 예입니다. 애플리케이션이 구현 IHostedService을 호스트하는 실행을 시작하면 해당 구현(이 경우 BackgroundService
"작업자")이 동일한 프로세스에서 실행되기 시작합니다. 이러한 호스티드 서비스는 확장 메서드를 통해 AddHostedService<THostedService>(IServiceCollection) DI에 싱글톤으로 등록됩니다. 다른 서비스는 모든 서비스 수명 동안 DI에 등록할 수 있습니다.
중요합니다
서비스 수명은 이해하는 데 매우 중요합니다. 모든 메모리 내 캐싱 서비스를 등록하기 위해 호출 AddMemoryCache 하면 서비스가 싱글톤으로 등록됩니다.
사진 서비스 시나리오
HTTP를 통해 액세스할 수 있는 타사 API를 사용하는 사진 서비스를 개발하고 있다고 상상해 보십시오. 이 사진 데이터는 자주 변경되지 않지만 많은 데이터가 있습니다. 각 사진은 간단한 record
다음으로 표시됩니다.
namespace CachingExamples.Memory;
public readonly record struct Photo(
int AlbumId,
int Id,
string Title,
string Url,
string ThumbnailUrl);
다음 예제에서는 여러 서비스가 DI에 등록되는 것을 볼 수 있습니다. 각 서비스에는 단일 책임이 있습니다.
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();
위의 C# 코드에서:
- 제네릭 호스트는 기본값으로 만들어집니다.
- 메모리 내 캐싱 서비스는 AddMemoryCache에 등록됩니다.
-
HttpClient
인스턴스가CacheWorker
를 사용하여 AddHttpClient<TClient>(IServiceCollection) 클래스에 등록됩니다. -
CacheWorker
클래스가 AddHostedService<THostedService>(IServiceCollection)에 등록되어 있습니다. -
PhotoService
클래스가 AddScoped<TService>(IServiceCollection)에 등록되어 있습니다. -
CacheSignal<T>
클래스가 AddSingleton에 등록되어 있습니다. -
host
는 빌더에서 인스턴스화되고 비동기적으로 시작됩니다.
지정된 PhotoService
조건(또는 filter
)에 맞는 사진을 가져오는 책임이 있습니다.
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();
}
}
}
위의 C# 코드에서:
- 생성자에는
IMemoryCache
,CacheSignal<Photo>
, 및ILogger
. - 메서드:
GetPhotosAsync
-
Func<Photo, bool> filter
매개 변수를 정의하고IAsyncEnumerable<Photo>
을 반환합니다. - 호출하고
_cacheSignal.WaitAsync()
가 해제되기를 기다립니다. 이렇게 하면 캐시에 액세스하기 전에 캐시가 채워집니다. - 캐시에 있는 모든 사진을 비동기적으로 가져오는 호출
_cache.GetOrCreateAsync()
입니다. - 인수는
factory
경고를 기록하고 빈 사진 배열을 반환합니다. 이렇게 하면 안 됩니다. - 캐시에 있는 각 사진은
yield return
을 사용하여 반복되고, 필터링되며, 구체화됩니다. - 마지막으로 캐시 신호가 다시 설정됩니다.
-
이 서비스의 소비자는 자유롭게 메서드를 호출 GetPhotosAsync
하고 그에 따라 사진을 처리할 수 있습니다. 필요한 HttpClient
것은 없습니까? 캐시에 사진이 포함되어 있습니다.
비동기 신호는 제네릭 형식 제한 싱글톤 내의 캡슐화된 SemaphoreSlim 인스턴스를 기반으로 합니다.
CacheSignal<T>
은/는 SemaphoreSlim
인스턴스에 의존합니다.
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();
}
위의 C# 코드에서 데코레이터 패턴은 인스턴스 SemaphoreSlim
를 래핑하는 데 사용됩니다.
CacheSignal<T>
이 싱글톤으로 등록되어 있으므로, 모든 제네릭 형식의 서비스 수명 전반에 걸쳐 사용할 수 있습니다. 이 경우에는 Photo
. 캐시 시딩을 시작하는 신호를 담당합니다.
의 CacheWorker
하위 클래스입니다.BackgroundService
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;
}
}
}
}
위의 C# 코드에서:
- 생성자에는
ILogger
,HttpClient
, 및IMemoryCache
. -
_updateInterval
3시간 동안 정의됩니다. - 메서드:
ExecuteAsync
- 앱이 실행되는 동안 반복합니다.
- HTTP 요청을 수행하고
"https://jsonplaceholder.typicode.com/photos"
응답을 개체 배열Photo
로 매핑합니다. - 사진 배열은
IMemoryCache
내에서"Photos"
키 아래에 배치됩니다. -
_cacheSignal.Release()
가 호출되면 신호를 기다리고 있던 모든 소비자가 해제됩니다. - 업데이트 간격이 Task.Delay 지정된 경우 호출이 대기됩니다.
- 3시간 동안 지연된 후 캐시가 다시 업데이트됩니다.
동일한 프로세스의 소비자는 IMemoryCache
에게 사진을 요청할 수 있지만, CacheWorker
는 캐시를 업데이트할 책임이 있습니다.
분산 캐싱
일부 시나리오에서는 분산 캐시가 필요합니다. 예를 들어 여러 앱 서버가 있는 경우입니다. 분산 캐시는 메모리 내 캐싱 방법보다 더 높은 스케일 아웃을 지원합니다. 분산 캐시를 사용하면 캐시 메모리가 외부 프로세스로 오프로드되지만 추가 네트워크 I/O가 필요하고 약간의 대기 시간이 발생합니다(명목상인 경우에도).
분산 캐싱 추상화는 NuGet 패키지의 Microsoft.Extensions.Caching.Memory
일부이며 확장 메서드도 AddDistributedMemoryCache
있습니다.
주의
개발 AddDistributedMemoryCache 및/또는 테스트 시나리오에서만 사용해야 하며 실행 가능한 프로덕션 구현은 아닙니다 .
다음 패키지에서 사용할 수 있는 IDistributedCache
의 어떤 구현이든 고려해 보세요.
Microsoft.Extensions.Caching.SqlServer
Microsoft.Extensions.Caching.StackExchangeRedis
NCache.Microsoft.Extensions.Caching.OpenSource
분산 캐싱 API
분산 캐싱 API는 메모리 내 캐싱 API보다 약간 더 기본적입니다. 키-값 쌍은 좀 더 기본적입니다. 메모리 내 캐싱 키는 object
을 기반으로 하며, 반면에 분산 키는 string
입니다. 메모리 내 캐싱을 사용하면 값이 강력한 형식의 제네릭일 수 있지만 분산 캐싱의 값은 다음과 같이 byte[]
유지됩니다. 다양한 구현이 강력한 형식의 제네릭 값을 노출하더라도 그것은 구현 세부 사항일 뿐입니다.
값 만들기
분산 캐시에 값을 만들려면 집합 API 중 하나를 호출합니다.
AlphabetLetter
메모리 내 캐시 예제의 레코드를 사용하여 객체를 JSON으로 직렬화한 다음 string
를 byte[]
로 인코딩할 수 있습니다.
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);
메모리 내 캐싱과 마찬가지로 캐시 항목에는 캐시의 존재를 미세 조정하는 데 도움이 되는 옵션이 있을 수 있습니다. 이 경우 DistributedCacheEntryOptions.
확장 메서드 만들기
값을 생성하기 위한 몇 가지 편의 기반 확장 메서드가 있으며, 이는 개체 표현을 string
에서 byte[]
로 인코딩하는 것을 방지하는 데 도움이 됩니다.
값 읽기
분산 캐시에서 값을 읽으려면 가져오기 API 중 하나를 호출합니다.
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);
}
캐시 항목을 캐시에서 읽은 후에는 다음에서 UTF8로 인코딩된 표현을 string
가져올 수 있습니다. byte[]
확장 메서드 읽기
값을 읽기 위한 편의성 중심 확장 메서드가 여러 가지 있습니다. 이러한 메서드는 byte[]
을 개체의 string
표현으로 디코딩하지 않도록 도와줍니다.
값 업데이트
단일 API 호출을 사용하여 분산 캐시의 값을 업데이트할 수 있는 방법은 없습니다. 대신 값은 새로 고침 API 중 하나를 사용하여 슬라이딩 만료를 다시 설정할 수 있습니다.
실제 값을 업데이트해야 하는 경우 값을 삭제한 다음 다시 추가해야 합니다.
값 삭제
분산 캐시의 값을 삭제하려면 제거 API 중 하나를 호출합니다.
팁 (조언)
앞서 언급한 API의 동기 버전이 있지만 분산 캐시의 구현이 네트워크 I/O에 의존한다는 사실을 고려하세요. 이러한 이유로 비동기 API를 사용하는 것이 일반적으로 더 선호됩니다.
참고하십시오
.NET