CDN Cache 2.0

Jsou to již 3 roky, co jsme publikovali článek o tom, jak cachujeme soubory v CDN. Od té doby došlo k několika změnám.

Popis infrastruktury

CDN používáme k servírování různých souborů, přičemž majoritu dělají video soubory. Všechny soubory uchováváme v cephu.

Z cephu jsou soubory servírované pomocí nginxu, ve kterém máme v LUA implementovanou logiku pro práci s odkazy. Navíc v nginxu děláme i takové věci, jako je omezení množství přenesených dat z jednoho souboru. To se hodí např. u nesegmentovaných mp4 video souborů, kde jsou dostupné seekovatelné ukázky, ale celý soubor již uživateli nepřenese.

Cephů máme v současné době několik a to z několika důvodů.

Rozložení rizik

Ceph je software jako každý jiný, prochází vývojem, vydávají se nové verze. Vyjma testovacích cephů máme také jeden malý (nyní 0,5PB velký) produkční, kam dáváme málo stahované soubory a který je první produkční cluster, na kterém zkoušíme změny konfigurací a nové verze. Pokud je na něm vše v pořádku a stabilní, tak teprve nasazujeme na další.

Hardware

Jednotlivé clustery se snažíme držet vždy konzistentní z pohledu konfigurace hardware. V případě, že některá z komponent umře, tak přesně víme, kterou komponentou to máme nahradit, a zjednodušuje nám to správu. Příklad: do jednotlivých osd nodů sice můžeme dávat disky různé kapacity, pro správné vyvážení je ale potřeba, aby váha hosta byla napříč celým clusterem velmi podobná. Kdybychom míchali disky různých velikostí, tak by nám to komplikovalo upgrady 6TB a 8TB disků za 18TB diky, které nyní děláme, protože bychom museli počítat váhu na jednotlivých serverech.

Popis provozu

Jako v každé CDN nemáme predikci toho, který soubor bude stahovaný. Máme ale výhodu v celkovém výkonu cephů. Celkem jsou všechny cephy schopny odservírovat dohromady až téměř 100Gbps provozu. To nám dává volnost v cachování, kdy nemusíme nutně cachovat soubory při prvním přístupu, ale stačí jen počkat, až soubor bude trochu víc sledovaný.

Provozní změny od první verze

Velikost storage

V původní verzi jsme pracovali stovkami TB, nyní už jsme řádově ve vyšších petabajtech aktivních dat.

Velikost souborů

Začínali jsme v situaci, kdy běžná velikost souboru byla 200MB až 1GB. Nyní servírujeme soubory od několika kb až po 250GB archívy.

Distribuce provozu

Dříve nám stačilo soubory servírovat pouze z jedné lokality. Někteří operátoři a jejich agresivní cenová politika nás však donutila zajistit distribuci i z jiných lokalit a distribuci optimalizovat.

Množství provozu

Vzrostly i požadavky na datové přenosy, kvůli čemuž jsme upgradovali síť na 100Gbps, a zároveň jsme optimalizovali hardware. O tom se však rozepíšeme příště.

Změny v cachování

Původní cachování fungovalo skvěle do momentu, něž k nám první uživatel nahrál 250GB soubor, který si následně stáhl. A množství těchto uživatelů postupně rostlo.

V původním návrhu jsme ke všem souborům přistupovali stejně a zajímal nás jen objem přenesených dat. To mělo za důsledek, že se nám do cache uložil jednou stažený 250GB soubor, který měl přednost před 200x staženým 1GB souborem a ke kterému už následně nikdo nepřistoupil.

Museli jsme tedy úplně přepsat rozhodovací logiku pro výběr souborů ke cachování. Nově se rozhodujeme na základě poměru množství přenesených dat k velikosti přenášeného souboru.

Toto řešení nám přineslo jednu milou vlastnost - přesně víme, kolik cachovací kapacity potřebujeme.

Příklad

Máme jeden menší cachovací server, přes který uživatelé přistoupili k souborům o celkové velikosti 65,75TB. Pojďme se podívat, kolik kapacity potřebujeme pro cachování při různých poměrech přenesených dat vůči k velikosti souboru.

  • Při poměru 0 potřebujeme 65,75 TB cache (tzn. cachujeme všechny soubory)
  • Při poměru 1 potřebujeme 46.55 TB (tzn. soubory, které byly alespoň 1 stažené celé)
  • Při poměru 2 potřebujeme 22.00 TB
  • Při poměru 3 potřebujeme 13.41 TB (poměr

Zároveň máme přehled o cachovací kapacitě a můžeme ji náležitě plánovat. Komentovaný příklad:

{
    "Size": { # Statistika z pohledu velikosti souborů
        "Total": "65.75 TB",           # Celková velikost přenesených zdrojových souborů
        "CacheRequired": "13.41 TB",   # Požadovaná velikost cache
        "CorrectlyCached": "8.79 TB",  # Velikost správně cachovaných souborů
        "SurplusInCache": "247.06 GB", # Velikost souborů, které mohou uvolnit místo
        "ToBeCached": "4.62 TB"        # Velikost souborů, které v cache nejsou, ale měly by být
    },
    "Files": { # Statistika z pohledu množství souborů
        "Total": 91430,           # Celkový počet souborů, ke kterým se přistoupilo
        "CorrectlyCached": 13851, # Počet správně cachovaných souborů
        "SurplusInCache": 332,    # Počet souborů, které v cache mohou uvolnit místo
        "ToBeCached": 6696        # Počet souborů, který by bylo dobré cachovat
    },
    "Traffic": { # Statistika z pohledu přenosu dat
        "Total": "171.96 TB",  # Celkový přenos dat za měřené období
        "Cached": "123.54 TB", # Množství dat servírovaný z cache
        "Direct": "48.42 TB"   # Množství dat servírovaný z backendu
    }
}

Ve statistice výše přehledně vidíme, že by tento cachovací server bylo dobré rozšířit o dalších 4,62TB, resp. trochu víc, protože soubory odmazáváme záměrně velmi pomalu.

I při této kapacitě však z cache odbavíme 72% datového provozu, což pro odlehčení zátěže ze storage v současné době bohatě stačí. Ke zvednutí tohoto poměru stačí jen dokopit disky.

Cachování a invalidace cache

Tady se toho moc od předchozí verze nezměnilo. Dobře nám funguje to, že servery fungují autonomně, takže si nedrží žádné informace o dalších serverech a samy se rozhodují, co budou dělat. Dokážeme tedy velmi snadno nasadit do sítě jeden cachovací server, stejně tak jako celý rack.

Soubory, ke kterým přistupuje víc uživatelů cachujeme přednostně. Soubory, které mají spíše pozvolnější přístupy cachuje v rámci volných kapacit. Stejně tak invalidace cache je spíše v režimu až když je opravdu potřeba.

Přistupujeme k tomu tak, že zápisy do cache jsou drahé a to ať už kvůli výkonu SSD, tak kvůli jejich životnosti. Spoléháme přitom však na výkon samotných storage, které jsou samy o sobě schopny odservírovat slušnou porci provozu.

Nasazení cachovací serverů

Rozhodovali jsme se, jestli nasadit jednu velkou cachovací vrstvu nebo pro každý ceph vlastní cache. Nakonec jsme se zvolili separátní cache pro každý ceph.

Snažíme se dělat věci maximálně jednoduše, takže v kódu nepotřebujeme vědět nic o výkonu storage serverů. Pro každý ceph tak jednoduše jen pomocí kapacity cache můžeme určit i její orientační výkon. Kdybychom měli jednu vrstvu, tak by se jednoduše bez další logiky mohlo stát, že by byly cachované soubory z jednoho cephu, ale na ostatní by se už nedostalo.

Routing

Směrování uživatelů stále děláme pomocí L7 balanceru, kdy požadavek pomocí http přesměrování posíláme na správný backend server. Balancování jsme rozšířili o váhy (hash buckets) jednotlivých serverů, což nám pomáhá při přidávání a odebírání jednotlivých serverů.

Distribuci požadavků jsme hodně rozšířili, protože někteří operátoři začali omezovat provoz, který od nás dostávají.

Stejně tak uživatelé od operátorů, kteří mají nepřijatelné platební podmínky, posíláme přes náhradní cesty.

Vrstvení cache

Většinu cachovacích serverů nyní máme jednoúrovňovou - buď je soubor cache nebo se servíruje ze storage.

Pro některé sítě však máme přidanou předřazenou vrstvu tak, aby se maximálně ušetřila šířka pásma a co nejvíc provozu se obsluhovalo v rámci dané sítě. V takovém případě se soubor cachuje několikrát.

Závěr

Určitě se máme kam se posouvat, hlavně co se týče rychlosti cachování, která je nyní (záměrně) velmi volná. Současné řešení však s ohledem na druh našeho provozu s přehledem zvládá uspokojit všechny uživatele a stojí naprostý zlomek toho, co bychom potřebovali pro plnohodnotnou cache mířící na 99% a více cache hit ratio.

Příště představíme hardware, který na cachování používáme.