System Design
Caching asoslari
Cache — tez-tez ishlatiladigan ma’lumotlarni tez joyda (memory) saqlash.
Nega Cache kerak?
Database sekin
Database query: 50-100ms
Memory read: 1ms
100x tezroq!
Scaling qimmat
Database vertical scaling:
2x capacity = 3-4x narx
Cache horizontal scaling:
2x capacity = 2x narx
Cache Hit vs Miss
User request → Cache
├─ Hit → Return from cache (1ms)
└─ Miss → Database query (50ms)
→ Store in cache
→ Return to user
Cache hit rate: Qancha request cache’dan?
80% hit rate → 80% requests 1ms
20% miss → 20% requests 50ms
Average: 0.8×1 + 0.2×50 = 10.8ms
vs No cache: 50ms
4.6x tezroq!
Cache qayerda?
1. Browser Cache
Cache-Control: max-age=3600
Browser 1 soat local saqlaydi → Server request yo’q.
2. CDN Cache
User → CDN (cache hit) → 5ms
User → Origin server → 150ms
3. Application Cache
const cache = new Map();
async function getUser(id) {
if (cache.has(id)) {
return cache.get(id); // Hit
}
const user = await db.query('SELECT * FROM users WHERE id = ?', [id]);
cache.set(id, user);
return user;
}
4. Database Cache
-- PostgreSQL shared_buffers
-- MySQL query cache
Database o’zi cache qiladi.
5. Distributed Cache
Redis, Memcached
Multiple servers share cache
Cache Invalidation
Hardest problem in computer science:
“There are only two hard things in Computer Science: cache invalidation and naming things.” — Phil Karlton
Muammo: Stale data
Time 0: Cache → user.name = "Ali"
Time 1: DB UPDATE user.name = "Vali"
Time 2: Cache → user.name = "Ali" (eski!)
1. Time-to-Live (TTL)
cache.set('user:123', user, { ttl: 300 }); // 5 minut
5 minutdan keyin avtomatik o’chiriladi.
Oddiy
Stale data (TTL tugaguncha)
2. Write-through
async function updateUser(id, data) {
await db.update(id, data);
cache.set(id, data); // Cache'ni yangilash
}
Cache har doim yangi
Har write’da cache update (overhead)
3. Write-behind (Write-back)
async function updateUser(id, data) {
cache.set(id, data); // Avval cache
queue.push({ type: 'update', id, data }); // Background DB update
}
Juda tez (faqat cache write)
Cache crash = data loss
4. Cache-aside (Lazy loading)
async function getUser(id) {
let user = cache.get(id);
if (!user) {
user = await db.find(id);
cache.set(id, user);
}
return user;
}
async function updateUser(id, data) {
await db.update(id, data);
cache.del(id); // Cache'ni o'chirish
}
Faqat kerakli data cache’langan
First request sekin (cold cache)
Cache Eviction Policies
Cache to’ldi, nimani o’chirish?
1. LRU (Least Recently Used)
Eng uzoq vaqt ishlatilmagan o'chiriladi
Cache: [A(10s ago), B(5s ago), C(1s ago)]
→ A o'chiriladi
Ko’p qo’llaniladi: Redis default
2. LFU (Least Frequently Used)
Eng kam ishlatiladigan o'chiriladi
Cache: [A(100 times), B(10 times), C(5 times)]
→ C o'chiriladi
3. FIFO (First In First Out)
Eng birinchi kirgan o'chiriladi
Queue kabi
4. Random
Tasodifiy o'chirish
Oddiy, lekin samarasiz
Redis - Popular Cache
Basic operations
const redis = require('redis');
const client = redis.createClient();
// Set with TTL
await client.set('user:123', JSON.stringify(user), { EX: 300 });
// Get
const cached = await client.get('user:123');
const user = JSON.parse(cached);
// Delete
await client.del('user:123');
Data structures
// String
await client.set('count', 42);
// Hash
await client.hSet('user:123', { name: 'Ali', age: 25 });
// List
await client.lPush('queue', 'task1');
// Set
await client.sAdd('tags', 'redis', 'cache');
// Sorted Set
await client.zAdd('leaderboard', { score: 100, value: 'user123' });
Cache Patterns
1. Read-through Cache
App → Cache → (miss) → DB
↓
Populate cache
↓
Return to app
Cache o’zi DB’dan oladi.
2. Write-through Cache
App → Write → Cache → DB
Har doim sync.
3. Write-behind Cache
App → Write → Cache
↓ (async)
DB
Background’da yozish.
Real-world Examples
Timeline cache: Redis
- User timeline (hot data)
- TTL: 30 seconds
- Cache hit rate: 99%+
Memcached:
- Thousands of servers
- Terabytes of RAM
- Billions of requests/sec
Stack Overflow
Redis:
- Questions, tags
- User profiles
- TTL: 5-10 minutes
Best Practices
1. Cache tez-tez ishlatiladigan ma’lumotlar
// Good: Popular product
cache('product:bestseller-123');
// Bad: Rare data
cache('user:inactive-for-5-years');
2. Appropriate TTL
// Hot data
cache.set('trending', data, { ttl: 60 }); // 1 min
// Warm data
cache.set('product', data, { ttl: 3600 }); // 1 hour
// Cold data
cache.set('archive', data, { ttl: 86400 }); // 1 day
3. Monitor hit rate
const hits = cache.hits();
const total = cache.total();
const hitRate = hits / total;
if (hitRate < 0.8) {
console.warn('Low hit rate!');
}
4. Namespace keys
// Good
cache.set('user:123:profile', data);
cache.set('user:123:posts', data);
// Bad
cache.set('123', data); // Qaysi 123?
5. Handle cache failures gracefully
async function getUser(id) {
try {
const cached = await cache.get(`user:${id}`);
if (cached) return cached;
} catch (err) {
console.error('Cache error:', err);
// Continue without cache
}
return await db.findUser(id);
}
Xulosa
Cache:
- 10-100x tezroq
- Database yukini kamaytiradi
- Scalability uchun shart
Strategiyalar:
- Cache-aside (lazy loading) - eng ko’p
- Write-through - strong consistency
- Write-behind - high performance
Eviction:
- LRU - default choice
- TTL - har doim qo’ying
Redis:
- Eng mashhur distributed cache
- Rich data structures
- High performance
Keyingi dars: Cache invalidation strategiyalari va consistency.