Data-caching
YdeevneTeknik til at gemme ofte brugt data i hurtig lagring for at reducere latenstid og databasebelastning.
Beskrivelse
Caching er praksis hvor hyppigt tilgået data gemmes i et hurtigt lag (typisk in-memory) så fremtidige forespørgsler kan serveres meget hurtigere. I stedet for at forespørge databasen hver gang, tjekker man først cachen - hvis data findes (cache hit), returneres det direkte. Hvis ikke (cache miss), hentes data fra databasen og gemmes i cachen til næste gang. Populære caching-strategier inkluderer: Cache-Aside (applikation tjekker cache først), Write-Through (skriv til både cache og DB), Write-Behind (skriv til cache, DB asynkront) og Read-Through (cache selv henter fra DB). Almindelige caching-teknologier er Redis og Memcached. Vigtige overvejelser inkluderer cache eviction-politikker (LRU, LFU, FIFO), TTL (Time To Live) og cache-invalidering (det svære problem). Korrekt caching kan reducere latenstid fra 100ms til under 1ms og reducere databasebelastning med 90%+.
Problem
Databaseforespørgsler kan være langsomme - disk I/O, komplekse joins, aggregeringer. Når tusinder af brugere forespørger samme data (f.eks. produktkatalog, artikler), bombarderer de databasen med identiske forespørgsler. Dette spilder ressourcer og giver dårlig ydeevne.
Løsning
Cache hyppigt tilgået data i RAM. Første forespørgsel henter fra databasen og gemmer i cache. De næste 1000 forespørgsler serveres direkte fra cache med sub-millisekund latenstid. Databasebelastning reduceres drastisk.
Eksempel
// Cache-Aside Pattern (Lazy Loading)
class ProductService {
constructor(db, cache) {
this.db = db;
this.cache = cache; // Redis client
}
async getProduct(productId) {
const cacheKey = `product:${productId}`;
// 1. Check cache først
let product = await this.cache.get(cacheKey);
if (product) {
console.log('Cache HIT');
return JSON.parse(product);
}
// 2. Cache MISS - hent fra database
console.log('Cache MISS - querying database');
product = await this.db.query(
'SELECT * FROM products WHERE id = $1',
[productId]
);
// 3. Gem i cache med TTL (1 time)
await this.cache.setex(
cacheKey,
3600, // TTL i sekunder
JSON.stringify(product)
);
return product;
}
async updateProduct(productId, data) {
// Update database
await this.db.query(
'UPDATE products SET name=$1, price=$2 WHERE id=$3',
[data.name, data.price, productId]
);
// Cache Invalidation - fjern cached version
await this.cache.del(`product:${productId}`);
// Næste read vil cache miss og hente fresh data
}
}
-----------------------------------------------------
// Write-Through Cache
async function saveUser(userId, userData) {
// Skriv til BÅDE database OG cache
await Promise.all([
db.query('INSERT INTO users VALUES ($1, $2)', [userId, userData]),
cache.set(`user:${userId}`, JSON.stringify(userData))
]);
// Cache er altid synchronized med database
}
-----------------------------------------------------
// Cache with TTL and Layers
class CacheService {
async getPopularProducts() {
const cacheKey = 'products:popular';
// L1: In-memory cache (meget hurtig)
if (this.memoryCache.has(cacheKey)) {
return this.memoryCache.get(cacheKey);
}
// L2: Redis cache
const redisData = await redis.get(cacheKey);
if (redisData) {
this.memoryCache.set(cacheKey, JSON.parse(redisData));
return JSON.parse(redisData);
}
// L3: Database (slowest)
const dbData = await db.query(`
SELECT * FROM products
ORDER BY sales_count DESC
LIMIT 20
`);
// Cache i begge layers
await redis.setex(cacheKey, 300, JSON.stringify(dbData));
this.memoryCache.set(cacheKey, dbData);
return dbData;
}
}Fordele
- ✓Drastisk reduceret latenstid (100ms → 1ms)
- ✓Reduceret databasebelastning (90%+ reduktion)
- ✓Bedre skalering af læsetunge arbejdsbyrder
- ✓Lavere hostingomkostninger (færre DB-ressourcer)
- ✓Forbedret brugeroplevelse
Udfordringer
- ⚠Cache-invalidering er svært ('sværeste problem')
- ⚠Forældet data hvis ikke invalideret korrekt
- ⚠Ekstra kompleksitet og bevægelige dele
- ⚠Hukommelsesomkostninger for cache-lag
- ⚠Kold cache-ydeevne (efter genstart)
Anvendelsesområder
- •Forsidens indhold og navigation
- •Produktkataloger i e-handel
- •Brugersessioner og autentificeringstokens
- •API rate limiting-tællere
- •Beregnede/aggregerede data
Eksempler fra den virkelige verden
- •Facebook feed: Cache opslag for millioner af brugere
- •Netflix: Cache filmmetadata og thumbnails
- •Amazon: Cache produktdetaljer og priser
- •Wikipedia: Cache artikler (læses meget oftere end opdateres)
- •Nyhedssider: Cache artikler med TTL på 5 minutter