INTEGRITY Dokumentace

Architektonický vzor řídicí a datové roviny pro Durable Objects

Úvod

Durable Objects jsou postavené na Cloudflare Workers rozprostřených napříč několika lokalitami naší globální infrastrukturní sítě. Každá instance Durable Object má vlastní trvalé úložiště zachovávané mezi jednotlivými požadavky, stav v paměti, jednovláknové provádění a lze ji umístit do konkrétního regionu.

Jedna instance Durable Object má určité možnosti výkonu a úložiště. Proto, abychom mohli aplikaci škálovat bez omezení daných limity jedné instance, potřebujeme data aplikace co nejvíce rozložit do shardů a využít Infrastruktura Cloudflare ↗ tím, že rozmisťuje instance Durable Object po celém světě a přibližuje tak data i výpočetní výkon co nejblíže uživatelům.

Tento dokument popisuje užitečný architektonický vzor pro oddělení řídicí roviny od datové roviny vaší aplikace, díky kterému dosáhnete vysokého výkonu a spolehlivosti bez omezení funkčnosti.

Vzor oddělení řídicí a datové roviny

V tomto vzoru se naše aplikace skládá minimálně z jedné instance Durable Object na každý typ zdroje, která zpracovává veškeré operace na úrovni control plane, a z tolika instancí Durable Object pro operace na úrovni data plane, kolik potřebujeme, tedy po jedné pro každou instanci zdroje vytvořenou v aplikaci.

Můžete škálovat až na miliony instancí Durable Object, jednu pro každý váš zdroj.

Hlavní výhodou tohoto architektonického vzoru je to, že operace data plane, kterých bývá obvykle více než operací control plane, zpracovávají přímo instance Durable Object obsahující data daného zdroje, aniž by procházely přes instanci control plane Durable Object. Výkon a dostupnost aplikace tak neomezuje jediná instance Durable Object, ale jsou rozloženy na tisíce až miliony instancí Durable Object.

Uveďme si příklad obecného typu prostředku XYZ, kde XYZ může být v praxi wiki, sdílený dokument, databáze pro každého uživatele nebo jakýkoli jiný typ prostředku ve vaší aplikaci.

Obrázek 1: Architektonický vzor řídicí a datové roviny pro Durable Objects
Obrázek 1: Architektonický vzor řídicí a datové roviny pro Durable Objects
  1. Uživatel v Londýně (LHR) zahájí požadavek na prostředek XYZ požadavek na vytvoření. Požadavek se směruje do nejbližšího datacentra Cloudflare a přijímá jej flotila Workers, která obsluhuje API dané aplikace.
  2. Kód Worker směruje požadavek na příslušnou instanci Durable Object řídicí roviny, která spravuje zdroje typu XYZ. Použijeme idFromName přístup k odkazování na instanci Durable Object podle názvu (control-plane-xyz). To umožňuje okamžitý přístup k instancím Durable Object řídicí roviny bez nutnosti udržovat mapování.
    • Umístění control plane Durable Object bude blízko prvnímu požadavku, který k němu přistoupí, nebo blízko explicitně zadanému regionu, který uvedeme pomocí Location Hints.
  3. Instance Durable Object řídicí roviny (control-plane-xyz) přijme požadavek a okamžitě vytvoří další instanci Durable Object (data-plane-xyz-03) poblíž místa, odkud přišel požadavek uživatele (pomocí Location Hints), takže skutečná instance Durable Object uchovávající obsah zdroje je blízko uživateli, který ho vytvořil. Označujeme vlastní init(...) na vytvořené instanci Durable Object (data-plane-xyz-03) a předá veškeré potřebné metadata, která budou potřeba k zahájení zpracování uživatelských požadavků. Instance Durable Object tyto informace uloží do svého lokálního úložiště a provede veškerou nezbytnou inicializaci. Tento krok lze přeskočit, pokud každý následující požadavek na vytvořený zdroj obsahuje všechny informace potřebné ke zpracování požadavku. Například pokud URL požadavku obsahuje všechny informace jako parametry cesty a dotazu. Používáme idFromName přístup k odkazování na Durable Object (data-plane-xyz-03) která umožňuje používat identifikátory zdrojů založené na názvu. Alternativně můžeme použít newUniqueId přístup k odkazování na Durable Object, který nám namísto identifikátoru založeného na názvu poskytne náhodný identifikátor prostředku. Tento náhodný identifikátor je pak třeba sdělit uživateli, aby jej uváděl ve svých dalších požadavcích při přístupu k danému prostředku.
  4. Instance Durable Object řídicí roviny (control-plane-xyz) uloží vygenerovaný identifikátor (data-plane-xyz-03) do svého lokálního úložiště, aby bylo možné vypsat/odstranit všechny vytvořené zdroje, a poté jej vrátí Workeru.
  5. Uživatel obdrží úspěšnou odpověď na vytvoření zdroje a příslušný identifikátor a volitelně je přesměrován přímo na daný zdroj.
  6. Uživatel odešle na API zápisový požadavek pro identifikátor zdroje vrácený v předchozím kroku, aby aktualizoval obsah daného zdroje.
  7. Kód Worker používá zadaný identifikátor zdroje k přímému odkazu na instanci Durable Object datové roviny pro daný zdroj (data-plane-xyz-03). Instance Durable Object požadavek odpovídajícím způsobem zpracuje tak, že obsah zapíše do svého lokálního trvalého úložiště, a podle toho vrátí odpověď.
  8. Jiný uživatel z Portlandu (PDX) odesílá požadavek na čtení dříve vytvořeného prostředku (data-plane-xyz-01).
  9. Kód Worker přímo odkazuje na instanci Durable Object, která uchovává data pro daný identifikátor zdroje (data-plane-xyz-01), a instance Durable Object vrátí svůj obsah přečtením z lokálního úložiště.

Pokud datový model aplikace umožňuje sharding na úrovni prostředků, můžete škálovat do šířky prakticky bez omezení, a přitom těžit z lokality dat v blízkosti uživatele, který k danému prostředku přistupuje.

Stejný vzor lze uplatnit tolikrát, kolik je potřeba k dosažení požadovaného výkonu.

V závislosti na zátěži bychom mohli náš řídicí Durable Object dále rozdělit do několika Durable Objects. Místo jediné instance Durable Object pro všechny zdroje typu XYZ, mohli bychom mít jednu instanci pro každý region. Přístup založený na názvu instance Durable Object pak usnadňuje zacílení na správnou instanci.

Závěrem, pokud najdete způsob, jak rozdělit datový model aplikace na jemně granulované a samostatné prostředky, můžete každému z nich vyhradit alespoň jednu instanci Durable Object a škálovat horizontálně.