Správa prostředků
Queuety rozděluje řízení prostředků do čtyř hlavních vrstev a navíc umožňuje volitelné nastavení velikosti poolu.
První vrstva popisuje náročnost jedné jednotky práce. Druhá omezuje, jakou společnou zátěž smí v daném okamžiku nést jedna fronta nebo skupina poskytovatelů. Třetí určuje, kolik smí spotřebovat jeden běh workflow. Čtvrtá rozhoduje, zda má worker ihned spustit další převzatou úlohu, nebo ji odložit, dokud v aktuálním procesu a kontejneru nebude dostatečná rezerva.
Tyto vrstvy spolupracují. Handler může deklarovat, že patří do náročného sdíleného poolu, fronta může vyhradit jen určité množství vážené práce pro jednoho poskytovatele, workflow může omezit, kolik takové práce vytvoří, a worker může stále odmítnout spustit další práci, když se aktuální proces nebo kontejner již blíží svým limitům.
Popis náročnosti jedné jednotky práce
Úlohy, kroky workflow a akce při vstupu do stavu mohou všechny zveřejnit stejné tři informace o prostředcích:
concurrency_groupconcurrency_limitcost_units
concurrency_group a concurrency_limit popisují společnou zátěž jednoho navazujícího systému. Pokud několik handlerů zasahuje stejného poskytovatele, účet API nebo tenanta, mohou použít stejnou skupinu, aby workeři nespouštěli příliš mnoho úloh najednou.
cost_units popisuje relativní váhu. Obnovení mezipaměti a rozsáhlé volání poskytovatele mohou být obě „jednou úlohou“, ale při rozhodování, zda je bezpečné spustit další práci, by neměly mít stejný vliv na rozpočet workflow nebo pravidlo přijímání úloh workerem.
final class CallProviderStep implements \Queuety\Step
{
public function handle( array $state ): array
{
// ...
}
public function config(): array
{
return [
'concurrency_group' => 'providers',
'concurrency_limit' => 3,
'cost_units' => 5,
];
}
}
Stejný princip platí pro odesílatelné úlohy prostřednictvím vlastností tříd a pro jednotlivá odeslání prostřednictvím PendingJob::concurrency_group() a PendingJob::cost_units().
Rozpočty pro sdílené fronty a skupiny poskytovatelů
Společná zátěž se ne vždy měří prostým počtem souběžných úloh. Někdy záleží na celkové váze právě běžících úloh.
Queuety to umožňuje pomocí vážených rozpočtů pro fronty a skupiny. Rozpočty front se určují podle názvu fronty. Rozpočty skupin se určují podle concurrency_group, takže nesouvisející handlery mohou sdílet stejný limit.
define( 'QUEUETY_RESOURCE_QUEUE_COST_BUDGETS', [
'providers' => 20,
'exports' => 8,
] );
define( 'QUEUETY_RESOURCE_GROUP_COST_BUDGETS', [
'openai' => 12,
'tenant:acme' => 6,
] );
Když worker převezme úlohu, zkontroluje aktivní záznamy processing, které již patří do dané fronty nebo skupiny. Pokud by součet aktuálně běžící zátěže a cost_units převzaté úlohy překročil nastavený rozpočet, worker úlohu uvolní a zkusí to znovu později.
To vám dává jinou možnost řízení než concurrency_limit. Poskytovatel může povolit tři souběžné požadavky, a přesto vyhradit méně celkových jednotek nákladů pro větší požadavky než pro menší.
Udržte jedno workflow v rámci limitu
Rozpočty workflow se hodí, když problémem není jedna náročná úloha, ale běh, který neustále objevuje více práce, než se očekává.
To je v agentních systémech běžné. Plánovač může znovu procházet stejnou náročnou větev, rozdělit ji na příliš mnoho dílčích úloh nebo dál spouštět podřízená workflow, a přitom technicky zůstávat v rámci běžného modelu opakovaných pokusů.
Queuety pro tyto případy nabízí limity na úrovni workflow:
Queuety::workflow( 'research_run' )
->max_transitions( 20 )
->max_for_each_items( 12 )
->max_state_bytes( 32768 )
->max_cost_units( 40 )
->max_started_workflows( 8 )
->then( PlanResearchStep::class )
->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
->dispatch();
max_cost_units() zabrání běhu spotřebovat více vážené práce, než se zamýšlelo. max_started_workflows() zabrání nadřazenému běhu vytvořit neomezený strom hlavních podřízených běhů. Ostatní ochranné mechanismy jsou stále důležité, protože ne každé nekontrolované workflow je náročné stejným způsobem.
Stav workflow zpřístupňuje nastavené limity a aktuální využití prostřednictvím veřejných dat budget, takže běh lze kontrolovat i během platnosti těchto limitů.
Umožněte workerům odložit práci, když je proces už příliš vytížený
I když jsou metadata a rozpočty workflow nastavené správně, konečné rozhodnutí stále náleží procesu workeru, který se chystá úlohu spustit.
Právě zde přichází ke slovu přijímání úloh s ohledem na prostředky. Před spuštěním převzaté úlohy může Queuety zkontrolovat:
- sdílenou skupinu souběžnosti úlohy
- vážené rozpočty front a skupin poskytovatelů
- nedávnou dobu trvání a historii maximální spotřeby paměti handleru
- zbývající paměťovou rezervu aktuálního workeru
- zbývající paměťovou rezervu aktuálního kontejneru nebo hostitele
- zbývající časový limit pro jednorázové běhy
Pokud se worker již příliš blíží nastavenému limitu, Queuety úlohu uvolní místo toho, aby spustil práci, která pravděpodobně neskončí bez problémů.
Tento přístup je záměrně konzervativní. Nejde o plnohodnotný plánovač clusteru, ale o ochrannou vrstvu, která vytíženému workeru pomáhá nepřetěžovat proces, v němž běží, a pokud jsou k dispozici údaje o paměti, také okolní kontejner nebo hostitele.
Kontrola kontejneru nebo hostitele je volitelná. Když je povoleno QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS, Queuety se nejprve pokusí načíst údaje o paměti z cgroup a na hostitelích Linux v případě potřeby použije /proc/meminfo. Pokud není k dispozici spolehlivý systémový snímek, worker dál používá kontroly omezené na vlastní proces.
Škálování poolů workerů s ohledem na kapacitu
Pevné pooly workerů se snadno spravují, ale nutí vás zvolit jedno číslo pro klidná období i nárazové špičky.
Adaptivní pooly umožňují místo toho nastavit minimum a maximum:
wp queuety work --queue=providers --min-workers=2 --max-workers=6
Nadřazený proces udržuje alespoň minimální počet aktivních podřízených procesů, při růstu počtu dostupných úloh se rozšiřuje až k maximu a po dobu nastavené prodlevy bez aktivity pool opět zmenší.
Škálování nahoru stále respektuje dostupnou kapacitu. Pokud je zapnuto sledování systémové paměti a nadřazený proces nevidí dostatek volné paměti pro dalšího workera s plnou rezervou, ponechá pool v aktuální velikosti místo spouštění dalších podřízených procesů.
Praktický příklad kombinace vrstev
Představte si výzkumné workflow, které plánuje volání poskytovatelů, spouští specializovaná workflow a nakonec sloučí výsledky.
Krok komunikující s poskytovatelem může zveřejnit cost_units a sdílené concurrency_group, aby několik workerů nezahltílo stejného poskytovatele modelu. Fronta může pro provoz tohoto poskytovatele vyhradit vážený rozpočet. Nadřazené workflow může omezit max_cost_units() a max_started_workflows(), aby plánovač nemohl běh neustále rozšiřovat. Worker pak může stále odložit nově převzaté volání poskytovatele, pokud nedávné údaje o maximální spotřebě paměti ukazují, že se proces nebo kontejner již příliš blíží svému limitu.
Tím získáte čtyři samostatné možnosti řízení:
- popsat váhu práce
- vyhradit sdílenou kapacitu fronty nebo poskytovatele
- omezit, kolik může jeden běh vytvořit
- zabránit vytíženému workeru spouštět příliš mnoho úloh
Kde najdete podrobné API
Tato stránka nabízí koncepční přehled.
Konkrétní nastavení najdete zde:
- Workeři popisuje přijímání úloh a konstanty běhového prostředí
- CLI popisuje příkazy pro pevné a adaptivní pooly workerů
- Ochranné limity workflow popisují rozpočty workflow
- Úlohy popisují metadata úloh a handlerů
- Stavové automaty popisují metadata prostředků akcí stavů
- API uvádí přesné metody a tvary návratových hodnot