Umut ABALI
← Projelere dön

Mini-CDN

Üç edge cache node'u, round-robin yönlendirme, TTL/LRU önbellekleme ve Prometheus/Grafana izleme içeren bir CDN simülasyonu.

Problem

Bir CDN'in gerçekte nasıl davrandığını anlamak için uçtan uca küçük bir CDN kurdum: miss olduğunda, bir kaydın süresi dolduğunda, cache dolduğunda, origin veya bir edge çöktüğünde ne oluyor? Her mekanizma, okunabilen ve test edilebilen birkaç yüz satır Go kodu.

Mimari

Mini-CDN mimari diyagramımissClientRouter :8080round-robin · /healthz every 2 sedge-1disk cache · TTL · LRUedge-2disk cache · TTL · LRUedge-3disk cache · TTL · LRUPrometheusscrapes /metricsOrigin :9000read-only filesGrafanaprovisioned dashboard
router/, edge/, origin/, internal/ ve docker-compose.yml dosyalarından çıkarıldı. Prometheus beş servisin hepsini tarıyor, sadelik için tek ok çizildi.
  • Router her isteği sıradaki sağlıklı edge'e reverse-proxy ile iletiyor (round-robin). Her edge'in /healthz'ini 2 saniyede bir yokluyor ve proxy hatasında edge'i sağlıksız işaretliyor.
  • Her edge'in bellekte bir indeksi (boyut, cachedAt, lastAccess) olan disk cache'i var. CACHE_TTL'den (compose dosyasında 5 dk) eski kayıtlar origin'den yeniden çekiliyor.
  • Purge tüm edge'lere dağıtılıyor: POST /purge her edge'i temizliyor, DELETE /cache/<yol> tek bir dosyayı her yerden siliyor.
  • Her servis, küçük ve elle yazılmış bir registry ile Prometheus formatında /metrics sunuyor. Grafana hazır bir dashboard ile geliyor.

Tasarım kararları

Cache'e yazarken istemciye de stream etmek

Miss durumunda origin yanıtı aynı anda hem cevaba hem geçici bir dosyaya kopyalanıyor (io.MultiWriter). Sonra geçici dosya yerine taşınıyor (rename).

Ödünleşim: İlk istemci için ek gecikme yok ve yarım kalan indirme asla cache kaydı olmuyor. Ama başlıklar kopyalama bitmeden gönderildiği için akış ortasındaki bir hata temiz bir hata yanıtına dönüşemiyor.

Origin çöktüğünde bayat içerik sunmak

Origin isteği başarısız olursa ve süresi dolmuş bir kopya varsa, edge 502 yerine onu X-Cache: STALE ile sunuyor.

Ödünleşim: Erişilebilirlik artıyor, karşılığında içerik güncel olmayabiliyor.

Byte ile sınırlı LRU, yeni dosya korumalı

CACHE_MAX_BYTES (varsayılan 500 MB) her edge'i sınırlıyor. Toplam sığana kadar en uzun süredir erişilmeyen kayıtlar siliniyor, ama az önce yazılan dosya asla silinmiyor.

Ödünleşim: Basit ve doğru, ama silinecek kaydı bulmak tüm kayıtlar üzerinde doğrusal bir tarama.

Önce yol güvenliği

CleanRequestPath '..' segmentlerini reddediyor, SafeJoin her disk yolunu cache kökünün içinde tutuyor. İkisinin de birim testi var.

Ödünleşim: Az miktarda ek kodla hem origin'de hem edge'lerde path traversal açıkları kapanıyor.

Tüm edge'ler arasında round-robin

İstekler yoldan bağımsız olarak sağlıklı edge'ler arasında dönüyor.

Ödünleşim: Yük dengeli ve demo kolay, ama aynı dosya üç edge'de de cache'leniyor (dosya başına üç miss).

Teknolojiler

Gonet/httphttputil.ReverseProxyDocker ComposePrometheusGrafana

Sırada ne var

  • Aynı anahtar için eşzamanlı miss'leri single-flight ile birleştirmek, böylece soğuk bir dosya edge başına origin'e bir kez gitsin.
  • Yola göre consistent hashing, böylece her dosya tek bir edge'de dursun.
  • Doğrusal tarama yerine O(1) LRU (map + çift yönlü bağlı liste).
  • Hit oranını ve gecikmeyi raporlayan, tekrarlanabilir bir yük testi.

Sonuçlar

round-robin router arkasında edge cache node'u
3
Cache hit oranıBenchmark yakında
Gecikme: HIT ve MISS, p50 / p95Benchmark yakında
Origin yükünün azalmasıBenchmark yakında