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

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

Twitter

Timeline cache: Redis
- User timeline (hot data)
- TTL: 30 seconds
- Cache hit rate: 99%+

Facebook

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:

Strategiyalar:

Eviction:

Redis:

Keyingi dars: Cache invalidation strategiyalari va consistency.