Ressourcestyring
Queuety opdeler ressourcestyring i fire grundlæggende lag med mulighed for at dimensionere worker-puljer ovenpå.
Det første lag beskriver, hvor ressourcekrævende én arbejdsenhed er. Det andet begrænser, hvor stor en fælles belastning én kø eller udbydergruppe må bære ad gangen. Det tredje fastlægger, hvor meget et enkelt workflowforløb må forbruge. Det fjerde afgør, om en worker skal starte det næste hentede job nu eller udskyde det, indtil den aktuelle proces og container igen har tilstrækkelig kapacitet.
Lagene fungerer sammen. En handler kan angive, at den tilhører en fælles pulje med højt ressourceforbrug, en kø kan reservere en begrænset mængde vægtet arbejde til én udbyder, et workflow kan sætte en øvre grænse for, hvor meget sådant arbejde det vil oprette, og workeren kan stadig afvise at starte mere af dette arbejde, hvis den aktuelle proces eller container allerede er tæt på sine grænser.
Beskriv omkostningen ved én arbejdsenhed
Jobs, workflowtrin og handlinger ved tilstandsindtræden kan alle angive de samme tre ressourcetips:
concurrency_groupconcurrency_limitcost_units
concurrency_group og concurrency_limit beskriver en fælles belastning på ét downstream-system. Hvis flere handlers rammer den samme udbyder, API-konto eller lejer, kan de bruge den samme gruppe, så workers ikke starter for mange på én gang.
cost_units beskriver den relative vægt. En cacheopdatering og et stort udbyderkald kan begge være »ét job«, men de bør ikke tælle lige meget, når et workflowbudget eller en adgangsregel for workers afgør, om det stadig er forsvarligt at starte mere arbejde.
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,
];
}
}
Samme princip gælder for jobs, der kan sendes via klasseegenskaber, og for individuelle afsendelser via PendingJob::concurrency_group() og PendingJob::cost_units().
Budgetter for delte køer og udbydergrupper
Fælles belastning handler ikke altid blot om at tælle samtidige kørsler. Nogle gange er det den samlede vægt af det, der allerede kører, som er dyrt.
Queuety understøtter dette med vægtede budgetter for køer og grupper. Købudgetter knyttes til kønavnet. Gruppebudgetter knyttes til concurrency_group, så uafhængige handlers kan indgå i den samme fælles ramme.
define( 'QUEUETY_RESOURCE_QUEUE_COST_BUDGETS', [
'providers' => 20,
'exports' => 8,
] );
define( 'QUEUETY_RESOURCE_GROUP_COST_BUDGETS', [
'openai' => 12,
'tenant:acme' => 6,
] );
Når en worker henter et job, ser den på de aktive rækker i processing, der allerede tilhører den pågældende kø eller gruppe. Hvis den aktuelle kørselsomkostning plus det hentede jobs cost_units ville overskride det konfigurerede budget, frigiver workeren jobbet og prøver igen senere.
Det giver dig en anden type styring end concurrency_limit. En udbyder kan tillade tre samtidige forespørgsler, men stadig reservere færre samlede omkostningsenheder til større forespørgsler end til mindre.
Hold ét workflow inden for en fast ramme
Workflowbudgetter er nyttige, når problemet ikke er ét tungt job, men et forløb, der bliver ved med at finde mere arbejde, end det var meningen.
Det er almindeligt i agentbaserede systemer. En planlægger kan vende tilbage til den samme ressourcekrævende gren, opdele den i for mange underopgaver eller blive ved med at starte underordnede workflows, samtidig med at den teknisk set holder sig inden for en normal genforsøgsmodel.
Queuety stiller grænser for workflows til rådighed:
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() forhindrer forløbet i at forbruge mere vægtet arbejde end tilsigtet. max_started_workflows() forhindrer et overordnet workflow i at blive til et ubegrænset træ af underordnede forløb på øverste niveau. De øvrige sikkerhedsgrænser er stadig vigtige, fordi løbske workflows ikke alle er ressourcekrævende på samme måde.
Workflowstatus viser de konfigurerede grænser og det aktuelle forbrug via den offentlige nyttedata budget, så forløbet stadig kan inspiceres, mens grænserne er aktive.
Lad workers udskyde arbejde, når processen allerede er for belastet
Selv når metadata og workflowbudgetter er korrekt konfigureret, træffes den endelige beslutning stadig af den worker-proces, der skal til at udføre jobbet.
Det er her, ressourcebevidst adgangsstyring kommer ind. Før et hentet job starter, kan Queuety undersøge:
- jobbets fælles samtidighedsgruppe
- vægtede budgetter for køer og udbydergrupper
- seneste historik over varighed og maksimalt hukommelsesforbrug for handleren
- den aktuelle workers resterende hukommelseskapacitet
- den aktuelle containers eller værts resterende hukommelseskapacitet
- den resterende tidsramme for kørsler af engangstypen
Hvis workeren allerede er for tæt på den konfigurerede grænse, frigiver Queuety jobbet i stedet for at starte arbejde, der næppe bliver fuldført korrekt.
Dette er bevidst en forsigtig tilgang. Det er ikke en fuld klyngeplanlægger, men et sikkerhedslag, der hjælper en travl worker med at undgå overbelastning af processen, den kører i, og, når der findes hukommelsesmålinger, den omgivende container eller vært.
Delen med container eller vært er valgfri. Når QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS er aktiveret, forsøger Queuety først at læse cgroup-hukommelsesdata og falder derefter tilbage til /proc/meminfo på værter med Linux. Hvis der ikke findes et pålideligt øjebliksbillede på systemniveau, fortsætter workeren med at bruge kontroller på procesniveau.
Skaler worker-puljer uden at ignorere kapaciteten
Worker-puljer med fast størrelse er nemme at forstå, men kræver også, at du vælger ét tal, som skal fungere både i stille perioder og ved spidsbelastning.
Med adaptive puljer kan du i stedet angive et minimum og et maksimum:
wp queuety work --queue=providers --min-workers=2 --max-workers=6
Den overordnede proces holder mindst det angivne minimumsantal underprocesser kørende, øger antallet op mod maksimum, når mængden af jobs, der kan hentes, vokser, og skalerer ned igen, når køen har været stille i den konfigurerede henstandsperiode.
Opskalering tager stadig højde for den tilgængelige kapacitet. Hvis systemhukommelsesovervågning er aktiveret, og den overordnede proces ikke kan se nok ledig hukommelse til endnu en worker med fuld kapacitet, beholder den puljen på dens aktuelle størrelse i stedet for at starte flere underprocesser.
Et realistisk eksempel på at kombinere lagene
Forestil dig et researchworkflow, der planlægger forespørgsler til udbydere, starter specialiserede workflows og derefter samler resultaterne.
Trinnet, der kalder udbyderen, kan angive cost_units og en fælles concurrency_group, så flere workers ikke overbelaster den samme modeludbyder. Køen kan reservere et vægtet budget til trafikken til udbyderen. Det overordnede workflow kan sætte grænser for max_cost_units() og max_started_workflows(), så en planlægger ikke kan lade forløbet vokse uendeligt. Workeren kan derefter stadig udskyde et nyt hentet udbyderkald, hvis data om det seneste maksimale hukommelsesforbrug viser, at processen eller containeren allerede er for tæt på sin grænse.
Det giver dig fire separate styringsmuligheder:
- Beskriv arbejdets vægt
- Reservér fælles kapacitet i køen eller hos udbyderen
- Sæt en grænse for, hvad ét forløb må oprette
- Forhindr en belastet worker i at starte mere arbejde end forsvarligt
Her finder du de detaljerede API'er
Denne side er en konceptuel oversigt.
Se de konkrete indstillinger her:
- Workers dækker adfærd ved adgangsstyring og konstanter for køretid
- CLI dækker kommandoer til worker-puljer med fast og adaptiv størrelse
- Workflow Guardrails dækker workflowbudgetter
- Jobs dækker metadata for jobs og handlers
- State Machines dækker ressourcemetadata for handlinger ved tilstandsskift
- API oplister de præcise metoder og returformater