Signal Shingle, en ny architecture för högpresterande ASP, ., multi-NET och - webbsidor (Svenska (Swedish))

Signal Shingle, en ny architecture för högpresterande ASP, ., multi-NET och - webbsidor

Friday, 24 July 2026

//

14 minute read

Hur levererar man snabba svar till komplexa bräder utan att bli galen?


Problemet

En dashboard är en bedrägligt dyr typ av sida.

Ett användbart dashboard: sammanfattningsmätare , en tidsram - seriediagramm M SK3 botlistat MSC4 slutpunkt och ländernämningar alla delar en sida samtidigt som de behållar oberoende uppdaterade ytor

Operatören ser ett dashboard, ;, servern ser långsamt, -, rörliga aggregationer, M SK2, live listor och dyra fönster.

flowchart TB
    P[One dashboard page] --> H[Headline counters]
    P --> T[Time-series chart]
    P --> B[Top bots]
    P --> E[Top content pages]
    P --> C[Countries / filters]
    H --> M[Shared hydrated page model]
    T --> M
    B --> M
    E --> M
    C --> M
    M --> S[Versioned widget shingles]
    S --> U[Independent HTMX OOB updates]

    classDef outline stroke:#475569,stroke-width:1.5px,color:#0f172a;
    classDef emphasis stroke:#0369a1,stroke-width:2px,color:#075985;
    class P,H,T,B,E,C,M,S,U outline;
    class M,S,U emphasis;
    linkStyle default stroke:#64748b,stroke-width:1.3px;

Den kända ASP-implementationen, ., NET, har varje widget som får sin egen data.

flowchart LR
    R[One page request] --> W1[Summary query]
    R --> W2[Time-series query]
    R --> W3[Countries query]
    R --> W4[Endpoints query]
    R --> W5[Bot query]
    W1 --> J[Task.WhenAll]
    W2 --> J
    W3 --> J
    W4 --> J
    W5 --> J
    J --> V[Render response]

    classDef outline stroke:#475569,stroke-width:1.5px,color:#0f172a;
    classDef danger stroke:#b91c1c,stroke-width:2px,color:#991b1b;
    class R,W1,W2,W3,W4,W5,V outline;
    class J danger;
    linkStyle default stroke:#64748b,stroke-width:1.3px;

Det ser snabbt ut med en person och en liten datamängd : nio oberoende inbjuder överlappar sig , så sidan tar ungefär lika lång tid som den långsammaste widgeten snarare än deras summa | . | Arithmetiskt ändras när sidan blir populär

Stylo.Bot dashboard, en normal sidamängd betydde ungefär nio parallella anslutningar över hela hemsidan / öppningsvägsgränsen, . dagens syn kunde skanna mer än en miljon rader . En enda tystnande mängd var redan flera gånger så stor. Task.WhenAll av ungefär tio dyra operationer och varje besökare började ytterligare tio

Parallelism är användbar. Per - begäranventilatorn- ut är problemetM SK3 Vid fem samtida tittareMSC4 blir nio samtalen fyrtioMST5 fem konkurrerande samtalen MST6 Vid 50 tittare är det fyrahundra och femtio M st7 Den databasseringspoolen ser en växande storm av oberoendet dyrt arbete

Parallellventilatorn gör att en enda utmaning ser snabbare ut genom att multiplicera trycket som förstör systemet under last.

Det här är den felaktiga skalningskurvan för en brädan.


Lösningen: Signal Shingle

Signal Shingle behandlar varje brädansguidet som ett föremål.

Hans fingeravtryck är helt enkelt widget + normalised parameters + data-surface generation. Ett landsaktualisering ska inte försämra en live- --- -Visitorkort. ;- -En ändrad filter ska inte göra allt annat widget kallt.

De här fragmenten lever i en begränsad LFU-cache. Warm läsning håller bevakade widgets levande ; one - avfiltrerade kombinationer förlorar sig naturligt

SignalR säger att en yta har ändrats, ;, klienten frågar efter den påverkade widgetpaketet, ;, HTMX använder den återvända utlägsningen från - och -, bandfragment med Idiomorph.

I mönstret, signal betyder “se till att göra det klartM SK1 shingle är det oberoende adresserbara resultatet.

Rendera-Seitenshinglar är helt enkelt otillräckliga . Om varje miss löser en ny databass scanning, så finns det dyrt arbete kvarM SK3 Signalshinglen använder två levels-cache med en avsiktligt smal hand,

flowchart LR
    D[Gateway<br/>authoritative events] --> B[Incremental window buckets<br/>data stays single-source]
    B --> C[Level 1 : content cache<br/>hydrated page result]
    C --> S[Level 2 : shingle cache<br/>versioned OOB widget HTML]
    S --> R[Request path<br/>read + Razor shell]

    T[Schedule tick/poll + LFU demand] --> W[Bounded prewarm waves]
    W --> B
    W --> C
    X[Coalesced SignalR dirty beacon] --> U[HTMX batch update]
    U --> S

    classDef outline stroke:#475569,stroke-width:1.5px,color:#0f172a;
    classDef emphasis stroke:#0369a1,stroke-width:2px,color:#075985;
    class D,B,C,S,R,T,W,X,U outline;
    class C,S,W emphasis;
    linkStyle default stroke:#64748b,stroke-width:1.3px;

De två kasnivåerna : data förblir autentiska , presentation förblir redo

Skillnaden är mellan modell och dess utformat Widgets levererade enheter. Inget av de båda kaserna blir en auktoritet för att upptäcka data

Ytter 1 : inkrementella buketter

Gatewayn äger datan.

Använd finbuckets för sex timmar

last 24 hours  → merge 288 five-minute buckets
last 30 days   → merge 720 hourly buckets

not

last 30 days   → scan and aggregate 1,000,000+ event rows again

Nya observationer uppdaterar den nyaste burken. Den historiska delen är inte scannerad eftersom en sida laddats upp. . Gatewayt är fortfarande den enda skrivaren och den enda plats som bestämmer vad detektorn betyder.

Cachenivå 1 : den hydrata innehållsキャッシュen

Uppströms – , – kastar webbsidan upp hydratiserade datapanelmodeller, , – låst av en normaliserad widget-uppsättning,, – fönster, , – filter och generering, M SK4 – Den överbrygger autentiska data och rendering.

Att kassera en modell istället för full HTML håller CSRF-värdena, autentiseringsklom , drag flager och nonser på applikationen- skickade skala där de hör till

På ett kallat nyckel , återfå en klar uppvärmnings tillstånd snarare än att göra om det i synkrona ordning. Bara tickmaterialisatorn får ett nytt resultat på sidorna . Senare svar serverar den senaste framgångsrika generationen M SK3 även när en nyre är på flyget MSC4

Cachenivå 2 : skal render cache

Dashboarden är medvetet splittrad : grindverket äger data ; hemsidan äger Razor och webblägrensrelationen M SK2 nivå 2 serverar små uppdaterade saker lokalt utan att bli en konkurrenskraftig databutik MSC4 den innehåller bara versionerade HTML som är avlägsna från grindverket

När en sidamodell existerar, kan en widget presenteras som ett OOB-element och hållas i den begränsade LFU-shinglens kass med en säkerhets TTL hx-swap-oob="morph", och lagrar resultatet under fingeravtrycket

Partitionens slutpunkt delar prylar till varma fingeravtryck och missar.

Det här är inte överdrivande kakning. Pozition 1 svar | “ vad är den konsekventa datapanelmodellen |?” | Pozitionen | МSK4 | svar ♫ “ | vad DOM-inseln kan denna webblader få |?” | Den första gör sammansättningen gemensamt | ; | den andra gör partiella uppdaterade nästan gratis


Cachegränsen: varför det här inte är reaktionscaching

Response caching är värt att jämföra direkt. En normal response cache lagrar en otydlig HTTP-anslutning ; oberoende cachede widgets utvecklar oberonde utgångs- och avbrytningsmodi . sidan kan laddas snabbt, medan den inte längre beskriver ett konsekventt tillstånd.

De kända kakande mönsterna är alla användbara. De skyddar helt enkelt olika gränser

Pattern ♫ ♫ ♫ Vad den förvarar ♫
HTTP-reagment-cache En HTTP-respons ♫ , ♫ som vanligtvis låses med URL och begäran ♫- ♫ varierande regler ♫ МSK4 ♫ offentliga GET-finpunkter och CDN ♫
ASP
Donut- hål / fragment Cache En kaskad skala med dynamiska hål ♫ , eller oberoendet kaskad fragment ♫ sidor vars krom är stabil och vars små dynamska områden är verkligt oberonde ♫
Signal-Singler En hydratad generation , - en markerad sidamodell plus versionerade widget-tillförselfragment ett dashboard vars delar måste uppdateras självständigt och fortsätta att beskriva ett tillstånd Cachegränsen är den sammanbyggda prognosen ; skalor är avlägsna från den , inte konkurrenskraftiga affärer

Niveau-2 shingles är en utgångsキャッシュ, medvetet liten och fragmenterad -formad. Skillnaden är att fragment inte bestämmer data verkligheten oberoende av varandraM SK3 innehållsmodellen är uppbyggd förstMSC4 under en generation

flowchart LR
    D[One authoritative<br/>gateway dataset] --> G[Generation 184]
    G --> M[One hydrated<br/>page model]
    M --> H[Headline shingle<br/>generation 184]
    M --> T[Chart shingle<br/>generation 184]
    M --> B[Bot-list shingle<br/>generation 184]
    M --> C[Country shingle<br/>generation 184]
    H --> P[One coherent page]
    T --> P
    B --> P
    C --> P

    classDef outline stroke:#475569,stroke-width:1.5px,color:#0f172a;
    classDef emphasis stroke:#0369a1,stroke-width:2px,color:#075985;
    class D,G,M,H,T,B,C,P outline;
    class G,M,P emphasis;
    linkStyle default stroke:#64748b,stroke-width:1.3px;

När data förändras, så får den påverkade kompositionen en ny generation... En webblader kan kortfattat se den tidigare när en redigering är på flyg, men den åldern är uppenbar och begränsad... Det är aldrig en uppsättning separata, -, ägida kasper som gör motsägelsefulla antaganden om,

En auktorite , en komponerad generation, många återanvändbara leveransfragmenter.


SSR första, ,, progressiv förbättring andra

Signal Shingle är inte en JSON API med en klient- sida-dashboard målad över toppen. StyloM SK2 Bot-dashbordet är Razor SSR-first | : | meningsfulla mätare , | tabeller |, | bord | МSK6 | länkar och navigering innan JavaScript körs ♫ . | HTMX | , | SignalR och Alpine förbättrar den sidan istället för att ersätta den ♫

flowchart LR
    R[GET dashboard] --> S[Razor SSR<br/>complete useful HTML]
    S --> V[Operator can read<br/>and navigate now]
    S --> H[HTMX enhancement]
    S --> A[Alpine enhancement]
    S --> G[SignalR enhancement]
    G --> D[Dirty beacon<br/>not dashboard JSON]
    D --> H
    H --> O[GET OOB widget batch]
    O --> W[Versioned HTML shingles]
    W --> M[HTMX / Idiomorph morph]
    A --> I[Local UI state<br/>menus, filters, affordances]

    classDef outline stroke:#475569,stroke-width:1.5px,color:#0f172a;
    classDef emphasis stroke:#0369a1,stroke-width:2px,color:#075985;
    class R,S,V,H,A,G,D,O,W,M,I outline;
    class S,W,M emphasis;
    linkStyle default stroke:#64748b,stroke-width:1.3px;

HTMX frågar efter HTML och byter tillbaka den återvända ön. SignalR levererar ett litet smutsigt signal snarare än JSON-modeller . Alpine äger den lokala gränssnittstaten | : | Menuer |, | blinkar och pris som inte förtjänar en runda färd |


Refresh är en avmattlig jobb, inte ett oavsiktligt biverkningar av trafiken

Uppvärmning sker utanför sidan begäran. Detta är en hård gräns | : | ett kallt svar ger ett uppvärmningsresultat |, | medan bara tick materialiseraren komponerar |

Koordinatorernas köer ställdes upp och nyligen- läste omloppsedeln , så värmer de upp i begränsade vågor med en sida Task.WhenAll som bär ett nytt namn.

Komparensgränsen är en del av korrektheten. : Refresh-loopet får ett redan känt kapacitetbudget.

Orchesterat, inte en storm. Det är den operationella regeln.

Framvärmning är täckning , inte villlig kakning

En kas kan inte skydda den första begäran om den bara värms efter som begäran kommer fram. Så materialisatorn har två jobb Pinned defaults behålla den riktiga 6hM SK1 24h+, ♫ ♫ 7d och ♫ 30 d-fenstervalen varma Efterfrågan-bestämda omlopp skyddsfilter som folk faktiskt använder

flowchart TB
    P[Pinned default windows<br/>6h · 24h · 7d · 30d] --> Q[Warm queue]
    L[Recently read filtered views<br/>LFU hotness order] --> Q
    Q --> G{Tick budget<br/>still available?}
    G -->|yes| W[Bounded warm wave<br/>compose once, store model]
    G -->|no| N[Defer to next tick<br/>serve prior generation]
    W --> H[Level 1 content cache]
    H --> Z[Level 2 shingle cache<br/>rendered on demand]

    classDef outline stroke:#475569,stroke-width:1.5px,color:#0f172a;
    classDef emphasis stroke:#0369a1,stroke-width:2px,color:#075985;
    class P,L,Q,G,W,N,H,Z outline;
    class Q,W,H emphasis;
    linkStyle default stroke:#64748b,stroke-width:1.3px;

Framvärmning måste matcha den verkliga produktens yta. Om gränssnittet erbjuder fyra normala fönster och kylaren känner till ett , tre fjärdedelar av den förväntade första -klickvägen är fortfarande kallt


LFU är inte bara utfånganing : det är efterfråganssignal

LFU är mer än utfånganing här . tillgången är efterfråganssignalen : den bestämmer vad som kvarstår som bosättare , vilket avlägsna arbete uppfrischar först M SK3 och vad som kan utan tvekan försvinna MSC4 Det gör obegränsade filterytader tillägnade för att sköta ut Mska5 Ett landsfilter som observerar hela dagen stannar varmt M Ska6 ett filter som prövats när det åldras, M Ska7 Det finns ingen separat ♫ M Ska8 ♫ populärt bordspanel | M Ska9 ♫ bord är nödvändigt ♫


Adaptiv mot statisk

Traditionella live-dashboarder reagerar på mer trafik genom att göra mer arbete, så blir de minst användbara vid de punktoperatörer som behöver dem mest . SignalShingel omverkar förhållandet. Frequensreglerna mäter frigörelsekostnaden mot ett budgetMSC3 dyra cyklar sträcker ut effektiva intervallM SK4 billiga kontrakterar mot den efterfrågade inställningen

refresh cost <= budget  → preserve requested cadence
refresh cost >  budget  → lengthen effective cadence
cost settles            → cautiously shorten it again

Detta är ett slutet kretslopp på den skyddade resursen.

Lade gör att brädan fungerar mindre, inte mer. Det är därför mönstret bryts ned istället för att kollapsa

“Statisk” är inte ett misslyckande . Det är den sista kända konsekventa prognosen

Ett statiskt hybrid med design

Den statiska halvan är reaktionskontraktet | : | en snabb |, | ett coherentt ögonblicksbild från kasetnivåerna | МSK2 | Den dynamiska halvan består av en separat budgeterad process | : | programmerare ♫ - | körda due checker | , | optionell SignalR-acceleration för live-widget | , | och en återuppkopplad synkronisering |. | Reaktionen är fortfarande snabb även när ögonblicksbilderna blir äldre

Så systemet kan skifta kontinuerligt mellan två användbara moder:

quiet / cheap refreshes       → dynamic dashboard, short effective cadences
busy / expensive refreshes    → static-like snapshot, longer declared cadences

Det är adaptiv skalning som är inbyggd i arkitekturen.


Frihet tillhör widgetet: en ickeM SK1 omnegocierad invariant

Alla prylar förtjänar inte samma nyhet. En trendgraf eller slutpunktklassning kan vara minuter eller en timme efter dem ; en lista av nyliga besökare eller aktuella poäng behöver en hårdare kadens

klass Typiska widgets grundkadensen МSK3 Varför
Aggregerad sammanfattning , trender МSK3 länder , slutpunkter ♫ minuter till en timme Signalen förändras tillräckligt långsamt för att det är mer värt att vara stabil än att knuffa
Live nya besöker , sessioner ♫ , namn ♫ , poäng ♫ МSK5 hot ♫

Två synligt identiska widgets kan be om olika kadenser. Att sätta in kadensen i dataminnet gör datan kopierad ; Att acceptera den första kan låta en senare konsument bli obekväm

Invarianten är enkel:

Ett gemensamt kassier måste aldrig servera en staler än någon av dess aktiva konsumenter som begärts..

Formellt:

effective cadence(entry) = MIN(requested cadence of every active consumer)

Cadence är en per-consumer golv, inte del av undertecknetet . Om en konsument frågar efter 60 sekunder och en annan i fem minuter , gör en gemensam insats uppfriskande varenda ♫ 60 sekunder M SK5 När snabbkonsumensen lämnar ♫ , räkna tillbaka det minimala ♫ МSK7 när inga konsumenter kvarstår ♫, sluta planera och låta LFU återta det ♫


Honest krom och konsekventa regler

Ett anpassningsbart system bör vara ärligt om dess anpassning. Widget-chrom visar den nuvarande effektiva kadensen : “uppdatering av varje \60sM SK4 | |

Det finns några regler som behövs för att hålla en prognos ärlig.

  • Generationsmärken. Varje chunk, /, registrerar datagenereringen som den skapades från.
  • Koplicerade signaler. En upptagna upptäckare kan generera många händelser per sekund. Signalbanan byter dem till ett smutsigt signal och en refresh lösning snarare än att skjuta upp webbläsaren eller refresh-loopen
  • Resync på att koppla igen. Ett återkoppel behandlas inte som bevis på att inget har hänt.
  • Begränsad TTL fallback. En bevarad del är inte tillåten att bli oömtlig . När den överträffar klassen- är begränsad till specifik förruttnad och kan inte återuppvärmas , blir den kallad M SK3 värmende istället för att tystna för alltid
  • Inget innehållsdjukan. Liv shinglar kan innehålla namn, fingeravtryck eller poängen. Deras innehåll stannar i minnet , är inte registrerade

Målet är inte omedelbart konsistens.


Problemet och lösningen

Här är hela handeln i en tabell

Per-skrävventilatornM SK3av ♫ ♫ Signal-Singler-dubbellag ♫
Page request Startar att få fram och väntar på N data läser en färdig modell / hamnar och visar skalan
Dataarbete upprepade gånger per invånare
Widget-uppdatening ♫ ♫ Varje widget kan hämtas oberoende av andra ♫
Konkurensens Task.WhenAll expanderar med trafik Begränsade frifriskande vågor med ett mätt kostnadsbudget
Filterade synpunkter Oavstängd eller oavstämpt Heißa kombinationer stannar kvar
Laderespons Mer trafik skapar mer arbete Fler kostnader sträcker ut kadensen mot statisk
Frihet Otydligt och ofta inkonsistent ♫ ♫ Otydlig per widget ♫, ♫ min ♫
Missbruksmodit långsamma begäran, vattensamlingstömningM SK3 kollaps Gamre men markerade projiktionerMST5 begränsad arbete MMST6

Signal Shingle komponerar välkända ASP, ., NET-skivor, :, en LFU,,, SignalR, M SK3, sammanlagd komposition ,, Razor och HTMX, och en programmerare med ett riktigt samtida budget.

Flytta ut Rendering från begäranstigen. Låt throttle-uppfriskande fungera istället för responsen

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.