Signal Shingle: een nieuwe architectuur voor high-performance ASP+.+NET multi+-+widget sites. (Nederlands (Dutch))

Signal Shingle: een nieuwe architectuur voor high-performance ASP+.+NET multi+-+widget sites.

Friday, 24 July 2026

//

16 minute read

Hoe levert je snel antwoorden op complexe dashboards zonder gek te worden? Je stopt ze aan het weergeven op de verzoekstroom.


Het probleem: per-request fanM SK2uit

Een dashboard is een bedrieglijk dure soort pagina. Het lijkt op één URL, maar het is echt een compositiemachine met een pagina.

Een geïnstalleerde dashboard: samenvattingstellers, een tijdstaafM SK2 seriegrafiek , botlijsten , eindpunt- en landaanzichten delen allemaal één pagina terwijl ze onafhankelijke update-oppervlakken bewaren.

De operator ziet één dashboard; de server ziet traag- bewegende aggregates , live lijsten en dure vensterbeeldenM SK3

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:#cbd5e1,stroke-width:1.5px;
    classDef emphasis stroke:#38bdf8,stroke-width:2px;
    class P,H,T,B,E,C,M,S,U outline;
    class M,S,U emphasis;
    linkStyle default stroke:#94a3b8,stroke-width:1.3px;

De bekende ASP.NET-implementatie heeft elke widget zijn eigen gegevens meegenomen.

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:#cbd5e1,stroke-width:1.5px;
    classDef danger stroke:#fb7185,stroke-width:2px;
    class R,W1,W2,W3,W4,W5,V outline;
    class J danger;
    linkStyle default stroke:#94a3b8,stroke-width:1.3px;

Het ziet er snel uit met één persoon en een klein dataset : negen onafhankelijke roepen overlappen , dus de pagina duurt ongeveer zo lang als zijn langste widget in plaats van hun som

Op de Stylo.Bot dashboard, één normale paginalaad betekende ruwweg negen parallelle roepen over de website /gateway boundary. De dagvisie kon meer dan een miljoen regels scannenM SK4 Een enkele stille laad was al veelvuldig. Task.WhenAll Bijna tien dure operaties en elke bezoeker startte nog eens tien.

Parallelisme is bruikbaar. Per-vraag-fan -uitkomt het probleemM SK3 Bij vijf concurrerende kijkers*, worden negen roepen viertig,- vijf concurreren roepen,. bij vijftig kijkers zijn er vierhonderd en vijftig.

Parallele ventilator-uit maakt een enkele vraag sneller zien door de druk te vermenigvuldigen die het systeem onder druk vernietigt.

Dit is de verkeerde schaalcurve voor een dashboard. Een dashboard is een gedeelde waarnemingsoppervlak. Het zou goedkoper moeten worden als meer mensen naar hetzelfde kijken , niet duurderM SK3


De oplossing: Signal Shingle

Signal Shingle behandelt elk dashboard-widget als een 'pre'.

Zijn vingerafdruk is simpelweg widget + normalised parameters + data-surface generation. Een update van een land moet geen live-kaart invalideren -visitorscard; een veranderde filter moet niet elke andere widget koud maken . Een nieuwe generatie herhaalt alleen de sleutels van het geaffecteerde schildM SK5

Deze fragmenten leven in een begrensde LFU-cache. Warm lees houden bekeken widgets resident; één - affiltercombinaties verliezen natuurlijk

SignalR zegt dat een oppervlak veranderd is; de klant vraagt naar het geaffecteerde widget-batch; HTMX gebruikt de teruggestuurde uitdrukkingsfragmenten van de band met Idiomorphe . Het signaal draagt een smerige aanwijzing meeMSC5 nooit een kopie van de dashboarddataM SK6

In het patroon, Signalen. betekent “herstellend beschouwen”; Schilling is het onafhankelijk adressbare resultaat.

Render-zijde schillingen alleen zijn onvoldoende. Als elke fout een nieuwe database-scan uitlokt , blijft het dure werkM SK3 Signal Shingle gebruikt een twee-niveau-cache met één bewust nauwkeurige 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:#cbd5e1,stroke-width:1.5px;
    classDef emphasis stroke:#38bdf8,stroke-width:2px;
    class D,B,C,S,R,T,W,X,U outline;
    class C,S,W emphasis;
    linkStyle default stroke:#94a3b8,stroke-width:1.3px;

De twee cache-niveaus : data blijven betrouwbaar , presentatie blijft klaar

De onderscheiding is tussen een gecomposed model. en zijn weergave. Widget-verwerkingsunités. Geen enkele cache wordt een autoriteit voor opsporingsgegevens.

Laag 1 : inkrementele buckets

Het gateway bezit de data. Het houdt een begrensde, in de memorie LFU projectie van inkrementeleM SK3 raambuckets met 30- dag-sliding-opbehoeving.

Gebruik 'fine buckets' voor zes-uur en 24-uurdiagrammenM SK2urenlange rollups voor lange vensters . Het punt is dat een aangevraagd venster bukets combineert in plaats van opnieuw te lezen.

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

Nieuwe observaties updaten de nieuwste bucket. De historische deel is niet opnieuw gescand- omdat een pagina werd gelaaid . Het gateway blijft de enige schrijver en de enige plek die beslist wat een detectie betekentM SK3

Cacheniveau 1 : het gehydrateerde inhoudscache.

Upstream, de website cachet gehydrade dashboardmodellen , gehackt door een genormaliseerde widgetset, vensterM SK3 filters en genereringMSC4 Het overbruggt autoritatieve data en renderingMST5

Het opslaan van een model in plaats van een volledig HTML houdt CSRF-waarden vast, authenticatie chrom, eigenschapsvlaggen en nonces op de versoek - afgeleverde schakel waar ze thuishoren

Op een koude sleutel, terugkeren we een duidelijke opwarmingsstaat in plaats van synchronisch herberekening. Alleen de tick materialiseerder verdient een nieuw paginaresultaatM SK2 Latere leesdiensten dienen de laatste succesvolle generatie

Cacheniveau 2 : de schinglerende cache.

Het dashboard is bewust verdeeld : het gateway bezit de data ; de website bezit Razor en de browserrelatie . Niveau M SK3 levert kleine updates lokaal zonder dat het een concurrerende data-opslagplaats wordt

Zodra een paginamodel bestaat, kan een widget als OOB-element weergegeven worden en in de begrensde LFU-schindelcache gehouden met een veiligheids-TTL. Een warme schindel omloopt zowel de compositie als het Razor-refererenM SK2 een misleest het alreeds -warme pagina-uitkomst waar het mogelijk is. hx-swap-oob="morph", en bewaart het resultaat onder zijn vingerafdruk.

De batch-endpointpartities splitsen widgets in warme vingerafdrukken en misses, componeert de ondersteunde misses één keer, dan geeft OOB HTML terug . Een samenvatting of landen veranderen reM SK3 sleutels alleen op die oppervlakte

Dit is niet redundant caching. Niveau M SK1 antwoorden “ wat is het coherent dashboardmodel?” Niveau


Cache grens: waarom dit geen reactie-caching is

Reactie-caching is direct te vergelijken. Een normale reactie-cache bewaart een ondoorzichtig HTTP-antwoord; Onafhankelijk gecacheerde widgets ontwikkelen onafhankelijke uitloop- en uitvalmodusmodiM SK2 De pagina kan snel laden terwijl ze niet langer één coherente staat beschrijft.

De bekende cachingpatronen zijn allemaal nuttig. Ze beschermen simpelweg verschillende grenzen:

Patroon Wat het opbehoudt ♫ Het beste pasmaat ♫ Waarom het hier alleen niet voldoende is ♫
HTTP-responscache Een HTTP-reactie, normaal gehackt door URL en verzoekM SK3verwante regels ♫ Publieke GET-endpoints en CDN ♫
ASP. Net-uitgangcache Gegenereerde serveruitgangM SK3 met expliciet variëren en ontsnappingsbeleid | Slechte pagina's met een kleine \ , stabiele versoek - sleutelspaar Het kan de pagina snel cachen МSK8 maar het is nog steeds een ondoorzichtig pagina resultaat in plaats van een gecoördineerde live projectie
Donut-boor / fragmentencache Een cachede schijf met dynamische gaten , of onafhankelijk gecached fragmenten ♫ pagina's waarvan het chrom stabiel is en waarvan de kleine dynamisch gebieden echt onafhankelijk zijn | Het maakt elk gat zijn eigen cache-levenscyclus ♫
Signal Shingle Een gehydrateerde, generatieM SK3 een gestempeld paginamodel plus geversioneerde widget-verwerkingsfragmenten Een dashboard waarvan de onderdelen onafhankelijk moeten worden opgedateerd en continue om één staat te beschrijven De cache-grens is de gecomposede projectie ; er komen schingen van af, geen concurrerende winkelsM SK3

Niveau-2 shingles zijn. een uitgangscache, bewust klein en fragmentarisch -vormig. Het verschil is dat fragmenten niet onafhankelijk beslissen over de datarealiteit.

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:#cbd5e1,stroke-width:1.5px;
    classDef emphasis stroke:#38bdf8,stroke-width:2px;
    class D,G,M,H,T,B,C,P outline;
    class G,M,P emphasis;
    linkStyle default stroke:#94a3b8,stroke-width:1.3px;

Wanneer data verandert, de geaffekteerde samenstelling krijgt een nieuwe generatie. Een browser kan de vorige kort zien terwijl een update in de vlucht isM SK2 maar dat leeftijdsniveau is expliciet en begrensd . Het is nooit een verzameling van aparte cache's owned aan - die tegenstrijdige beweringen maken over MSC5nu\”.

Eén autoriteit, één gecombineerde generatie, veel herbruikbare toeleveringsfragmenten .


SSR eerste, progressieve verbetering tweede

Signal Shingle is geen JSON API met een client-zijds dashboard geschilderd bovenaan. De StyloM SK2Bot-dashboard is de eerste Razor SSR : betekenisvolle tellers

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:#cbd5e1,stroke-width:1.5px;
    classDef emphasis stroke:#38bdf8,stroke-width:2px;
    class R,S,V,H,A,G,D,O,W,M,I outline;
    class S,W,M emphasis;
    linkStyle default stroke:#94a3b8,stroke-width:1.3px;

HTMX vraagt naar HTML en wisselt de teruggestuurde eilanden.. SignalR levert een klein vuile signaal in plaats van JSON-modellen.


Verfrissen is een gescheduleerd werk, geen toeval bij het verkeer.

Vervristing gebeurt buiten de paginarequest. Dit is een harde grens : een koude lees geeft terug een verwarmingsresultaat , terwijl alleen de tick materializer samenwerktMSC3 De paginarequête is een lees van een coherente projectieM SK4 nooit een excuus om dure datawerk te beginnen

De coördinatierijen zijn vastgeprikkeld en recent gezet-les envelops lezen, warmt ze dan in gegrensde golven met een pagina -telling en murenM SK3horlogebudgetMSC4 Binnen een golf zet het kompatible werk in een slagMST5 een gemeten kostenbudget kan latere golven volledig stoppenMSP6 Dit is niet Task.WhenAll Met een nieuwe naam.

De gelijktijdigheidslimiet is deel van juistheid : de verfris-lus krijgt een bekend capaciteitsbudget, nooit een onbegrensde reeks verbindingen . Een volledig warme update maakt geen compositie of Razor-rendering op de een of andere manier

Orchesterd, geen storm. Dat is de operationele regel.

Voorwarming is de omslag, geen wenselijke caching

Een cache kan de eerste verzoek niet beschermen als het alleen warm wordt. Na Die vraag komt aan. Dus de materialiseerder heeft twee banen. Gekoppelde verstek Hou de echte vensteropties warm. Demand-gegated envelops Omhulselfilters die mensen daadwerkelijk gebruiken, gerangschikt door toegangsgetal en recintie. Slechts een echte verzoek houdt er één levend voor.

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:#cbd5e1,stroke-width:1.5px;
    classDef emphasis stroke:#38bdf8,stroke-width:2px;
    class P,L,Q,G,W,N,H,Z outline;
    class Q,W,H emphasis;
    linkStyle default stroke:#94a3b8,stroke-width:1.3px;

Voorwarming moet overeenkomen met de echte productoppervlakte. Als de interface vier normale vensters biedt en de warmer er één kent , driekwart van de verwachte eerste-klikpaad nog steeds koud is


LFU is niet alleen uitroeiing : het is de vraagsignaal.

LFU is meer dan ontsnapping hier. Toegang is het vraagsignaal : het bepaalt wat nog steeds woont , waarnaar het werk de eerste verfrising geeft , en wat veilig kan verdwijnen M SK4 Dat maakt onbegrensde filterruimte bestuurbaar MSC5 Een landfilter die de hele dag bekeken wordt blijft warm MST6 een filter dat geprobeerd wordt als hij ouder wordt M ST7 Geen aparte M stk8 populaire dashboard M Stk9 tafel is nodig Mstk10


Aanpasbaar naar statisch

Traditionele live-dashboards reageren op meer verkeer door meer werk te doen, dan worden ze minder bruikbaar bij de plekbedieners die ze het meest nodig hebben . Signal Shingle omdraait dat verband. De verfrisingscontroleerder meet verfrisingkosten in vergelijking met een budget

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

Dit is een gesloten loop op de beschermde hulpbron, geen gok van ruwe RPS. Onder lading beweegt het systeem naar een statisch snapshot in plaats van meer databasewerk te creëren om een onmogelijke belofte van levendheid te behouden.

Laad maakt dat het dashboard minder werkt, niet meer. Daarom neemt het patroon af in plaats van te dalen

“Statisch” is niet een mislukking . Het is de laatste bekende coherente projectieM SK3 omringd door een frisseheidsbeleid en eerlijk gelabeld

Een statisch/dynamische hybride, volgens het ontwerp

De statische helft is het reactiecontract : een snelle , coherente snapshot van de cacheniveaus. De dynamische helft is een afzonderlijk gebudgeteerd proces |: schakelaar | - gedreven nauwkeurige controles ♫, optioneel SignalR versnelling voor live widgets |

Het systeem kan dus continu tussen twee nuttige modes glijzen:

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

Dat is adaptieve schaalvorming ingebouwd in de architectuur, geen paniekschalter bijgevoegd na het falen van de pool.


Frisheid behoort tot de widget: één non-noverhandelbare invariant

Niet elk widget verdient dezelfde frisseheid. Een trendgrafiek of eindpuntrangorde kan een paar minuten of een uur achter staan; een lijst van recente bezoekers of huidige scores heeft een dichter tempo nodigM SK2 De tempo leeft met het widgetMSC3 de frisseklasseMske4

Klas Typische widgets Basiskadentie Waarom SMK4
Aggregaat samenvatting, trendsM SK3 landenMSC4 eindpunten minuten tot een uur Het signaal verandert langzaam genoeg dat stabiliteit waardevoller is dan draaien
Live recente bezoekers , sessies МSK3 namen , cijfers , , bedreigingen ongeveer een minuut De operator zoekt naar de huidige beweging

Twee zichtbaar identieke widgets kunnen vragen naar verschillende cadenties. Het inzetten van cadentie in de cache-leutel dupliceert data ; Het accepteren van de eerste cadantie kan een latere consument achterlaten.

De invariant is eenvoudig:

Een gedeelde cache-invoer moet nooit dienen aan een staler dan één van de active consumenten die aangevraagd is.

Formaal:

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

Cadence is een per-consumer. De vloer., geen deel van de handtekening. Als één consument vraagt om 60 seconden en een ander vijf minuten langM SK3 een gedeelde inskrywing verfrisst elke ♫ 60 seconde.\ Wanneer de snelle consument weggaat,\ herbereken het minimum\MST7\ wanneer er geen consumenten meer zijn\M ST8\ stoppen met het schedulen en laten LFU het terugfordern\Mst9\


Honest chrom en consistentieregels

Een adaptief systeem zou eerlijk moeten zijn over zijn aanpassing. Widget chrom toont de huidige effectieve cadentie : “ elke 60sM SK4 \“ elke

Er zijn een paar regels nodig om een projectie eerlijk te houden.

  • Generatiestempels. Elk stuk /neemt de datageneratie van het schakelwerk waaruit het is gemaakt . Een smerige bel en een reactie kunnen worden vergeleken
  • Gekoppelde signalen. Een drukke detector kan veel gebeurtenissen per seconde produceren. De signalenpaad zet ze in één vuile bel en een verfrisde beslissing, in plaats van de browser of de verfrissloop te laten branden.
  • Hersync op herverbinding. Een herverbinding wordt niet behandeld als bewijs dat er niets gebeurde.. Een beurtenis-check sluit de mislukte-check af.
  • Gegrensde TTL terugval. Een behouden stuk mag niet onsterfelijk worden. Zodra het de klas overschreeft - het specifiek uitputt en niet kan worden opgefrisd, wordt het koudM SK3 warmer dan altijd stil te liggenMSC4
  • Geen inhoudsvervuiling. Live shingles kunnen namen bevatten, vingerafdrukken of scores. Hun inhoud blijft in de geheugen , is niet gelogdM SK3 en elke diagnostische bewerking bewerkt ze per verstek.

Het doel is niet onmiddellijke consistentie. Het is een projectie waarvan leeftijd en generatie gegrenseerd zijn, waarneembaar en nooit toevalligM SK2


Problem en oplossing

Hier is de hele handel in één tabel.

Per-request fanM SK3out Signal Shingle tweevoudige laag
paginarequest Begint N-gegevens te halen en te wachten.
Datawerk Herhaal per bezoeker Gedeeld
Widget-update Elk widget kan onafhankelijk afhaald worden Warme shingles dienen rechtstreeks; misses componeren als een lot M
Concurrency Task.WhenAll Vergroot met verkeer Gegrensde verfrissende golven met een gemeten kostenbudget
Gefilterde aansigten ongecached of onbegrensd Warme combinaties blijven levendM SK3 koude LFU-evict
Load response Meer verkeer creëert meer werk Meer kosten verlengen de cadentie naar statische ≥
Frisheid Implesiet en vaak inconsistent Onduidelijk per widget , min
Mislukkingsmodus Langzame verzoeken, pooluitputtingM SK3 ineenstorten Oudere, maar gelabelde projectieMSC5 begrensde werk MSC6

Signal Shingle componeert bekende ASP's.NET-stukken : een LFUMSC2 SignalRMsc3 geballeerde compositieMSc4 RazorM sc5 HTMX en een scheduler met een echt gelijktijdig budget Msc6 De poort blijft autoritiefMc7 de website levert een projectie opMcc8 de browser ontvangt kleine versie fragmentenMcs9

Bewegen van het weergeven van de verzoekpaad. Laat ladingsthrottle refresher werken in plaats van de reactie.

Finding related posts...
logo

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