Objektovou storage Swift už jsme na cloudsvet.cz představili, ale jak vlastně ukládá data? Proč dokáže efektivně běžet na prakticky libovolném počtu nodů a disky i nody můžete přidávat za plného provozu?
Od file systému ke skutečné škálovatelnosti
Připomeňme si, že adresa objektu je ve formátu země, město, ulice, tedy /account/container/object. Když Swift požádáte o objekt na nějaké adrese, ten musí vědět na kterém nodu a kterém disku ho najít. Klasický centralizovaný file systém by se problémem vypořádal tak, že by si držel tabulku se seznamem souborů, metadaty a informací o jeho fyzickém umístění na disku. Scale-out distribuovaná object storage by ale s takovým přístupem měla problém:
- Tabulka by s počtem objektů neustále narůstala, vyhledávání v ní by bylo čím dál tím pomalejší a aktualizace složitější
- Přístupy do této tabulky by byly extrémně časté a paralelní zapisovací operace by byly prakticky nemožné, což by vedlo na nutnost frontovat a provádět operace po jedné (tedy omezit výkon)
- Přidání nebo ubrání (či havárie) disku znamená vyřazení nefunkčních záznamů a replikaci na nová místa, tedy velký zásah do tabulky
- Samotná tabulka by musela být distribuovaný systém – v CP provedení by špatně škáloval, v AP variantě by bylo řešení konfliktů časté a relativně obtížné s dopadem na výkon
Seznam prostorů, kontejnerů a objektů existuje a Swift ho svými procesy udržuje, nicméně ten nijak nesouvisí s vlastním umísťováním objektů a jejich nalezením – jde jednoduše o seznamy, kde uživatel nejde název svých objektů a jejich URL. K nalezení objektu dojde až po zadání této URL. Jak na to?
Od URL k cílovému disku
Udržovat stavový seznam objektů a jejich umístění špatně škáluje, proto se používá HASH funkce. Jde o matematickou operaci, která z libovolného vstupu vytvoří jeho otisk o stále stejné velikosti. Používá se dnes prakticky všude – kryptografie, ukládání dat, integrita, certifikáty – typickými zástupci jsou třeba MD5 nebo SHA. Vezmete tedy URL ve formátu /account/container/object a udělate nad tímto řetězcem HASH, která vede na nějaké číslo (je docela velké). Protože počet disků bude určitě menší, než je výsledek běžné hash, mohli bychom použít modulo operaci a převést ho třeba na číslici 0-7 pro našich 8 disků a podle toho víme, kam máme zapsat (a kde najít) náš objekt. Čas vyhledávání by byl velmi rychlý a nepotřebujeme složitou stavovou tabulku. Nicméně změna počtu disků by znamenala použít modulo na jiný počet – v ten okamžik prakticky veškerá dosavadní umístění budou špatně a museli bychom celý cluster přeskládat, což je extrémně náročné. Navíc přidávání disků tímto způsobem způsobí, že jejich kompetence ve smyslu velikosti výseče budou nevyrovnané. Chce to nějaké vylepšení.
Tím je použití Consistent Hash Ring. Představte si možné výsledky HASH jako kolečko s číslicemi (HASH vrací výsledek ve stejném rozmezí bez ohledu na délku vstupu, takže kolečko bude stále stejně veliké). Zanaste vaše disky/nody na toto kolečko jako body. Disk bude “vlastnit” všechny objekty, jejichž hash je v rozmezí daném bodem disku na kružnici a vším po směru hodinových ručiček až do bodu, kde sedí další disk. V čem je to lepší, než obyčejné modulo? Když přidáte disk, ovlivníte pouze bezprostředního souseda – usurpujete si nárok na část jeho dat, protože jejich domovem jste teď vy. Všichni ostatní měnit nemusí.
Už je to lepší, ale přidání disku vytvoří stres pro jednoho souseda, což také není ideální. Swift tedy funguje ještě o něco chytřeji. Celá kružnice se rozseká na relativně velký počet výsečí, třeba 32K. Tyto se přidělí diskům, každý tedy vlastní výsečí hned několik a to napříč celým kolečkem. Nově přidaný disk si tak převezme některé výseče a rovnoměrně vycucne po kousíčkách dat z ostatních disků. Připomínám, že tato výseč (partition) je jen rozsah možných výsledků HASH.
Pojďme teď kroužků použít víc. Swift tak vytvoří jeden kroužek pro informace o záznamech o accountech (prostorech). Také jeden o kontejnerech a dále pro každou storage policy.
Přiřazení výsečí
Jak se výseče rozdělí mezi disky v rámci různých storage policy? A jak se budou držet repliky? Každý prstenec obsahuje dvě základní tabulky – tou první je seznam všech nodů a tou druhou tabulka přidělených partition k jednotlivým diskům a replikám. Představte si jednoduchou tabulku, jejíž sloupce jsou čísla partition a řádky repliky (typicky tak bude mít tabulka 3 řádky). Obsahem je mapování partition na fyzické umístění. Při rozdělování výsečí mezi fyzické disky se berou v úvahu dva faktory. Tím prvním je “váha” disku, tedy administrátorem nastavitelné preference disku (například v reflexi na jeho velikost či rychlost). Druhou je pravidlo maximální diverzity. Pakliže jedna výseč má mít tři repliky, pro jejich fyzické umístění se zvolí co nejodlišnější disk – v jiné zóně nebo alespoň v jiném serveru.
Node a disk máme, co dál?
Nic složitého. Nezapomínejme, že node je normální server. Na cílovém disku má nějaký souborový systém a používá běžné mechanismy pro nalezení souboru v rámci tohoto lokálně omezeného systému.
Více se o OpenStack Swift dozvíte také v lab guide Helion OpenStack – pokročilé v sekci Dokumenty.