Ocelot ETag Caching
Predpokladám, že na Slovensku / v Čechách nie je moc ľudí čo využívajú Ocelot API Gateway, ale keď už teda mám napísaný post, tak ho hodím aj sem 😊.
Knižnica Kros.Ocelot.ETagCaching
prináša do Ocelot API Gatewaya ETag kešovanie. ETag kešovanie je mechanizmus, ktorý umožňuje klientom overiť, či sú údaje uložené v keši stále aktuálne, bez toho, aby museli celý zdroj znovu stiahnuť. Ak sa údaje nezmenili, server odpovie so stavom 304 Not Modified
a vyzve klienta aby použil údaje z keše, čím sa ušetrí bandwidth a zníži zaťaženie servera.
Prečo používať ETag kešovanie?
ETag kešovanie je obzvlášť užitočné v scenároch, v ktorých sa údaje menia zriedkavo, ale sú často požadované. Optimalizuje využitie siete a zlepšuje čas odozvy. Použitím ETag si klient môže zabezpečiť, že bude mať vždy k dispozícii najnovšiu verziu údajov.
Ako to funguje?
Pri ukladaní do keše sa používajú dve hlavičky HTTP:
ETag
: Jedinečný identifikátor, zvyčajne guid alebo hash.cache-control
: Dáva klientovi pokyn, že odpoveď sa môže ukladať do keše. Pre ukladanie do keše by mala byť nastavená na hodnotuprivate
.
Keď klient dostane odpoveď s týmito hlavičkami, uloží údaje a hodnotu ETag do keše. Pri ďalších požiadavkách klient odošle hlavičku If-None-Match
s hodnotou ETag. Server potom porovná ETag s aktuálnou verziou údajov. Ak sa zhodujú, server vráti stav 304 Not Modified
, čo znamená, že klient by mal použiť údaje uložené v medzipamäti.
Implementácia v Ocelot
Knižnica Kros.Ocelot.ETagCaching
sa využíva Ocelot middlewares. Sama zabezpečí generovanie, ukladanie a overovanie ETag. Tu je návod, ako začať:
Konfigurácia Ocelot
Nakonfiguruj smerovania v súbore ocelot.json
a špecifikuj politiky pre kešovanie:
{
"Routes": [
{
"Key": "getAllProducts",
"DownstreamPathTemplate": "/api/products/",
"UpstreamPathTemplate": "/products/",
"CachePolicy": "getAllProducts" // 👈 Cache policy key
},
{
"Key": "getProduct",
"DownstreamPathTemplate": "/api/products/{id}",
"UpstreamPathTemplate": "/products/{id}",
"CachePolicy": "getProduct" // 👈 Cache policy key
},
{
"Key": "deleteProduct",
"DownstreamPathTemplate": "/api/products/{id}",
"UpstreamPathTemplate": "/products/{id}",
"InvalidateCachePolicy": "invalidateProductCachePolicy"
}
]
}
Program.cs Configuration
Nakonfiguruj pravidlá Program.cs
:
// 👇 Define policies
builder.Services.AddOcelotETagCaching((c) =>
{
// 👇 Simple policy with expiration and tag templates
c.AddPolicy("getAllProducts", p =>
{
p.Expire(TimeSpan.FromMinutes(5));
p.TagTemplates("products:{tenantId}", "all", "tenantAll:{tenantId}");
});
// 👇 Policy with custom cache key, ETag generator, and cache control
c.AddPolicy("getProduct", p =>
{
p.Expire(TimeSpan.FromMinutes(5));
p.TagTemplates("product:{tenantId}:{id}", "tenant:{tenantId}:all", "all");
p.CacheKey(context => context.Request.Headers.GetValues("id").FirstOrDefault());
p.ETag(context => new($""{Guid.NewGuid()}""));
p.CacheControl(new() { Public = false });
});
});
A pridaj middleware.
app.UseOcelot(c => { // 👇 Pridať middleware caching ETag c.AddETagCaching(); }).Wait();
Tag templates a invalidovanie keše
Tag templates sa používajú na generovanie tagov na základe parametrov požiadavky, čo uľahčuje invalidovanie konkrétnych položiek keše. Napríklad pre cestu /api/{tenantId}/products/{id}
a tag template product:{tenantId}:{id}
bude tag product:1:2
.
Automatické invalidovanie keše
Definujte policy pre invalidáciu v ocelot.json
:
{
"Key": "deleteProduct",
"UpstreamHttpMethod": [ "Delete" ],
"DownstreamPathTemplate": "/api/products/{id}",
"UpstreamPathTemplate": "/products/{id}",
"InvalidateCachePolicy": "invalidateProductCachePolicy"
// 👆 Invalidate cache policy key
}
A nakonfiguruj ich v súbore Program.cs
:
builder.Services.AddOcelotETagCaching(conf =>
{
// 👇 Define invalidate cache policy
conf.AddInvalidatePolicy("invalidateProductCachePolicy", builder =>
{
// 👇 Define tag templates to invalidate
builder.TagTemplates("product:{tenantId}", "product:{tenantId}:{id}");
});
});
Manuálne invalidovanie
Ručne môžeš zneplatniť záznamy keše pomocou IOutputCacheStore
:
public class ProductsService {
private readonly IOutputCacheStore _outputCacheStore;
public ProductsService(IOutputCacheStore outputCacheStore)
{
_outputCacheStore = outputCacheStore;
}
public async Task DeleteProduct(int tenantId, int id)
{
await _outputCacheStore.InvalidateAsync(
$"product:{tenantId}", $"product:{tenantId}:{id}");
// 👆 Invalidate cache entries by tags
}
}
Redis Integration
V predvolenom nastavení knižnica používa InMemoryCacheStore
, ale môžeš ju nakonfigurovať tak, aby používala Redis na distribuované ukladanie do keše:
builder.Services.AddStackExchangeRedisOutputCache(options =>
{
options.Configuration
= builder.Configuration.GetConnectionString("MyRedisConStr");
options.InstanceName = "SampleInstance";
});