# StyloBot-julkaisusarja: Pitkällä aikavälillä tapahtuvan rajattoman kasvun löytäminen ja korjaaminenM SK1Työttäminen .Nettipalvelut

*Pitkät -toiminnalliset palvelut suuntautuvat hitaasti rajattomaan muistiin, .Tämä on se, miten minä havaitsen tämän virtauksen, ,, miten ajattelen sen korjaamista ilman paperointia siitä.*

[<img src="/articleimages/stylobot-logo.svg" alt="StyloBot" width="120" />](https://www.stylobot.net)

> **StyloBot -sarja**
> 
> 1. [**Käytänne, Ei identiteettiä**](/blog/stylobot-fingerprint): miksi StyloBot mallistaa asiakkaita käytännöllisesti
> 2. [**Behaviour-Aware ASP.NET UI**](/blog/behaviour-aware-ux): palvelijaM SK1 luovutti pintansa kyseisen havaitsemistuloksen yli
> 3. **Pitkällä aikavälillä tapahtuvan -käynnissä olevan .NET-palvelujen rajaton kasvun löytäminen ja korjaaminen**: luotettavuuden kurinalaisuus
> 4. [**Behaviour-Aware TypeScript UI**](/blog/typescript-sdk): ExpressM SK1 Fastify, ja hakukonekomponentit
> 5. [**Sidecar-arkkitehtuuri**](/blog/sidecar-architecture): miten havaitsemismoottori liitetään muihin kuin -.NET-palkkiin
> 6. [**Oppiminen nopeuttamaan**](/blog/stylobot-release-learning): mukautuva oppimisjärjestelmä, , neljä,- tasotasoinen muisti ja , tuomiovarasto
> 7. [**Todistuksen testaaminen, joka ei jää rauhaan**](/blog/stylobot-release-nondeterministic-testing): tarkastusta koskevat säännökset : yksi BDF-tietokanta hallinnoi regressiaa M SK2 lastausta, , ja kalibrointia
> 8. [**StyloExtract - paikallisen oppimisen HTML:n Markdown-muuttaja**](/blog/stylobot-release-styloextract): HTMLM SK1Markdown-laaja, joka on päällekkäinen tunnistajan kanssa , walkinger bug lucidVIEW caught, ja dogfood loop, joka teki siitä rehellisen

<!--category-- ASP.NET, StyloBot, Bot Detection, Performance, Architecture -->
<datetime class="hidden">2026-06-01T10:30</datetime>

Työskennelty esimerkki on StyloBotin vektoritaso,, mutta ala on't StylobotM SK2specifinen . Mikä tahansa pitkittyvä~-käynnissä oleva \.Net-palvelu, joka kerää tilanteen liikenteestä, kasvaa lopulta eräänlaiseen ryhmään virheitä, joita voitte havaita.

Käytännön malli on [Käytänne, Ei identiteettiä](/blog/stylobot-fingerprint); ASP:n  .NET-pinta-ala [Behaviour-Aware ASP.NET UI](/blog/behaviour-aware-ux); lähde osoitteessa [github.com/scottgalM SK2stylobot](https://github.com/scottgal/stylobot).

[TOC]

---


## Ongelman luokka

Pitkät~-~käynnissä olevat palvelut keräävät~M SK1~Kaikki cache~,~Kaikilla oppimispisteillä~MSC3~kaikki ♪"~me~MST5~olemme vain pitämään viimeiset N-pyynnöt\"~pufferi on pieni kerääjä~ .~Yhdessä kukin näyttää hienolta omalla tavallaan~ MST8~Yhdenmukaisesti~MIST9~prosessissa, joka on jatkunut jo viikko ajan~ MIST11~he muodostavat muistimuodon, jota mikään testi ei koskaan toistaa~MTS12~

- toimisi hyvin dev, CIM SK1 ja ensimmäisenä tuotantopäivänä
- vähitellen etenee kohti OOM, ja sitten joko kaatuu tai alkaa soittaa

Saatte tämän *harkitsemalla sitä*, prosessista, jonka prosessi on ollut riittävän pitkä, jotta muoto olisi syntynyt

## Askel 1:Perioilliset luotettavuutta koskevat tarkistukset

Ensinnäkin: "' ei ole tekninen, . on aikataulullinen"

Joka muutamassa versiossa, lopetan ominaisuuksien lisäämisen ja katson vain käynnissä olevaa järjestelmää realistisen liikenteen alla, kysyn *vaikuttaako tämä väärin?* Ei erityistä virhettä, ei tavoitettaM SK1 vain katsotaan. Käytössä olevat järjestelmät piilevät hiljaa ; ne eivät toimiMSC4 epäonnistu voimakkaasti, kunnes ne epäonnistuvat katastrofaalisesti

Äskettäin julkaistussa tarkistuksessa havaittiin bug, joka koskee `Mostlylucid.BotDetection.Demo` prosessi, joka on 20 Englannin kansalaisessa, joka asetetaan synteettiseen testausliikenteeseen

**Säännöt:** put a recurring slot on the calendar to read your own metrics

## Askel 2: Antakaa laskentareiden hämmästyttää teitä

Asianmukainen väline " on jotain väärää ?" NET-prosessissa on [`dotnet-counters`](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters). Se, ', on ilmaisia, ,, se, M SK3, on jo otettu käyttöön,,, ja se kertoo teille totuuden siitä, mitä prosessinne tekee tällä hetkellä

Muutamat ohjeet StyloBotin demossa:

```
dotnet.gc.last_collection.heap.size[loh]   13,393,217,096 bytes (13.4 GB)
dotnet.gc.heap.total_allocated              97 MB/sec
dotnet.exceptions[SqliteException]          4/sec
```

Se' riittää siihen, että tiedämme, mikä on vääris ilman, että lukee mitään koodia. [Suurobject-heap](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap) oli 13.4 Englannin puntaa ja kasvanut lähes 100 MB/secM SK3 Joku oli jakamassa valtavia esineitä jatkuvastiMSC4 ja sukupolviMST5 GC ei pystynytMSV6 pysymään niiden tasalla

### Lyhyt refresher LOH:lle (, koska kaikki .NET-devat törmäävät siihen viime kädessä

Large Object Heap on yksi yleisimmistä yllätyksistä, kun ensimmäistä kertaa profiiliin otetaan pitkä -käynnissä oleva .NET-palvelu. SeM SK3 kannattaa tarkistaa, koska lähes kaikki kohtaavat sen vaikealla tavalla

- GC:ssä on kolme sukupolvea.
- **Mikään suurempi kuin 85 KB ei mene näissä sukupolveissa '** Se kulkee suoraan **Suurobject-heap**.
- LOH kerätään vain **Gen2 GC**,, joka on kaikkein kalliin keräys .NET tekee. GenM SK3 tapahtuu harvoinMSC4 ja runtime yrittää kovasti välttää sen
- Pahinta, on standardin mukaan LOH **ei compactoitu** kun se on kerätty; se vain vapauttaa lähtökohdatM SK1 Näin ollen jopa Genin jälkeen~2,~ LOH on hajanainen~: sallitte vapaan tilan~ , mutta se' on väärässä~MSC6~kokoiset aukot seuraavalle kohdentamiselle ~. Uudet suuret esineet laajentavat rypäleä sen sijaan, että käyttäisivät sitä uudelleen~M SK8
- Nettovaikutus: pitää jakaa suuria esineitä vakaalla vauhdilla , ja prosessinne' muistinjälki liikkuu ylöspäin riippumatta siitä, onko esineitä vielä viitattu vai ei

Suurimmät sattumanvaraisen LOH-kasvun lähteet todellisissa .NET-palveluissa

|lähde | Miksi se päätyy LOH:hen
|---|---|
| `JsonSerializer.Serialize(obj)` palauttaa `string` | Yhdestä 100 MB:n kohdasta tulee SSK2 MB UTF-string
| `MemoryStream` sallitte rajattoman kasvun | Sisäinen bufferi kaksinkertaistuu 85 KB: n jälkeen ja pysyy LOH:ssa |
| `byte[] buf = new byte[n]` suurille `n` | Direktiivi LOH:n kohdentaminen; hyvin yleinen asiakirjassaM SK2verkon lukeminen |
| `List<T>` grows past ~10 K referenceM SK1typed items | Tausta-arran ristit 85 KB ja laskee LOH:n m|
| `string.Concat` / `StringBuilder` yli suuren tekstin | Lopullinen `ToString()` |
| `XmlSerializer` / `DataContractSerializer` suurten graafioiden | Sama muoto kuin JSONin tapaus |

Jos muistatte vain yhden sormensäännön: **on epäluuloinen mistä tahansa kooditiedosta, joka tuottaa yhden rinnakkaisen suuren kohdan timerissa tai pyynnöstä.** Se, että ' on muoto, joka tuhoaa pitkät rautatiepalvelut, - -muoto, ,-muoto ja "M SK3" -muodo on juuri se muoto, jonka "StyloBot" -koneella "MST4" -rakennamme.

```mermaid
flowchart LR
    classDef input fill:none,stroke:#3b82f6,stroke-width:2px
    classDef store fill:none,stroke:#f59e0b,stroke-width:2px
    classDef async fill:none,stroke:#a855f7,stroke-width:2px
    classDef problem fill:none,stroke:#ef4444,stroke-width:2px

    A["Per-request handler<br/>Add to collection"]:::input --> B["Long-lived List / Dict / Buffer"]:::store
    C["Timer / autosave<br/>every N min"]:::async --> D["JsonSerializer / MemoryStream<br/>single &gt;85 KB allocation"]:::problem
    B --> D
    D --> E["Large Object Heap"]:::problem
    E --> F["Gen2 GC<br/>infrequent, expensive"]:::async
    F --> G["LOH not compacted by default<br/>fragments build up"]:::problem
    G --> H["Process RSS marches upward"]:::problem
```

Apuvälineet sen diagnoosimiseksi:

- [`dotnet-counters`](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters) elävien lukujen osalta (LOH-rajan ylittävät toimenpiteet

- [`dotnet-gcdump`](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-gcdump) ja [`dotnet-dump`](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dump) snapshotteja, jotka voidaan avata Visual Studiossa tai PerfViewissa.

- [PerfView](https://github.com/microsoft/perfview) itse siirtojen jäljittämiseksi pisteeseen.

- **JetBrainsin CLI-profiilit** (miltä itse asiassa olen käyttänyt tätä uudelleenkäsittelyä varten). Nyt paketoitu asianmukaiseksi .NET maailmanlaajuiset työkalutM SK3 niin päätöntä / kaukoisilta M/ CI runtime profilointia ei tarvita Rider GUI:tä
  
  - [`JetBrains.dotMemory.GlobalTools`](https://www.jetbrains.com/help/dotmemory/Command-Line_Profiler.html): liittääM SK1 ottaa muistinapshotin, avata `.dmw` työtilaa myöhemmin nähdäkseen, mitkä säilyneet juuret pitävät LOH-jakoa.
  - [`JetBrains.dotTrace.GlobalTools`](https://www.jetbrains.com/help/profiler/Performance_Profiling__Profiling_Using_the_Command_Line.html): samanlainen malli näytteenottoa varten / jäljittäminen \/ aikarajan tiedot
  
  ```bash
  dotnet tool install -g JetBrains.dotMemory.GlobalTools
  dotnet tool install -g JetBrains.dotTrace.GlobalTools
  
  dotMemory get-snapshot <pid> --save-to-dir=./snapshots
  dotTrace attach <pid> --profiling-type=Sampling --timeout=60s --save-to=./trace.dtp
  ```
  
  Työn jakaminen uudelleenkäsittelyyn: `dotnet-counters` sanoin, että ongelmana oli LOH; DotMemory-napshot kertoi minulle, että syynä oli autosave timer.

On olemassa ulospääsypuitteita, jos niitä todella tarvitaan. `GCSettings.LargeObjectHeapCompactionMode = CompactOnce` 1-off LOH:n compaction [`RecyclableMemoryStream`](https://github.com/microsoft/Microsoft.IO.RecyclableMemoryStream) Microsoft pools-pufferit, jotta vältettäisiin kohdentaminen ensi sijassa. Molemmat ovat plastejaM SK1 Todellinen ratkaisu on lähes aina lopettaa jättiläisen esineen tuotanto ensi sijasta.

### Palaan diagnoosiin

Näin ollen aina kun näette LOH:n vakaata kasvua pitkässä toiminnassa, kysymys on lähes aina sama. *mikä'jako hyvin suuria esineitä kohdennetaan?* Vastauksen muoto (timer?pyynnön käsittelijäM SK2 serializer ? puskuripooliMSC4 kertoo, mihin kohdassa katsoa

Poikkeukset olivat myös tärkeitä. `4/sec` vuodesta `SqliteException` on riittävän alhainen, ettei se näy pöytäkirjoissa kukaan lukee, mutta riittävän korkea, jotta kerrotaan teille, että kooditie yrittää hiljaisesti uudelleen

**Säännöt:** kun jokin näyttää väärältä, vahvistaa `dotnet-counters` ennen arvausta. Luvut pienentävät etsintäradiaalin suuruusjärjestyksessä

## Menettely 3: vääränlainen

Tämä on se, missä järjestelmä tulee kiinnostavaksi, koska kiusaus on aina *korjaus* oireet sen sijaan, että kyseenalaistetaan abstractio

> ### Nopea vocab ( seuraaville osilleM SK1
> 
> - **Vektori**: kiinteätM SK1laajuiset floattien joukot - e.gMSC4 `float[64]`Each slot is a measured property of the request (header count , timingM SK3 IP family, etcMSC5 Kaksi pyyntöä, jotka ovat samankaltaisiaMRK7, tuottavat toisiinsa läheisiä vektoreita |64-dimensional space | `float[]`.
> - **Vektoritehokkuus**: yleensä [Kosiinin samankaltaisuus](https://en.wikipedia.org/wiki/Cosine_similarity) - kahden vektorin välisen askeleen kosine
> - **Lähes lähimmäinen naapuri (ANNM SK1**Tämän vektorin perusteella : " löytää läheisimmät N miljoonistaM SK3 nopeasti". Brutto-- voiman vertailu on OMSC6NSSK7 kutakin kysymystä kohdenMST8 ANN:n algoritmit saavat sub-millisekundisia tuloksia ottamalla huomioon, että joskus puuttuu *totta* läheisin ottelu.
> - **HNSW**: yksi näistä ANN-algoritmiista . Se rakentaa kerrostetun grafiikan, jossa korkeimmalle tasolle on joitakin pisteitäM SK2yhtetyt nodot ja alhaiset tasot täyttävät yksityiskohtaisesti. Menette ytimeen ja zoomoitte itseltäänMSC4 Erinomainen suuren indeksoinnin kannalta *vakaa* joukko vektoreita. ei ole suunniteltu "kaikki pyyntö lisää yhden ja vanhat menevät poisM SK2 - koko tämän kohdan asiaankuuluva kohta
> - **Centroidit**: ryhmän vektoreiden keskimääräinen suhde - yksi vektori, joka kokoaa ryhmittymän yhteenM SK2 Jos teillä on SSK3 vektorit, jotka kaikki näyttävät laajasti samanlaisilta, voitte heittää ne pois ja säilyttää yhden centroidinMSC5 centroidi on häviävä mutta kompaktinen korvaajaMST6 Kompaktointistrategiat käyttävät tätä monien raakahistorian muuttamiseen pieneksi yhteenvetohistoriaksi

StyloBotin osalta LOH-kasvu johti kolmeen ryhmään, jotka olivat rakenteellisesti identiaaleja [HNSW](https://en.wikipedia.org/wiki/Hierarchical_navigable_small_world_graphs) (Hierarkiallinen navigointikelpoinen pieni maailma[alkuperäinen Malkov & Yashunin paper](https://arxiv.org/abs/1603.09320)), jota käytetään samankaltaisuuksien hakuun allekirjoituksestaM SK1 istunnossa , ja tarkoituksen vektorit. kullakin oli ala, kuten

```csharp
private readonly List<float[]> _graphVectors = new();
```

Jokaista syötti oppija, joka on allekirjoittanut `LearningEventType.FullDetection`,, joka palaa **kaikki HTTP-pyynnöt**. Jokaiseen pyyntöön lisättiin vektori

Ja joka viiden minuutin välein – , – autosave-aikataulu siirtää koko grafiikan JSONiin ja kirjoittaa sen diskille.

```csharp
private readonly TimeSpan AutoSaveInterval = TimeSpan.FromMinutes(5);
```

Demossa, `signatures.vectors.json` oli 104 MB `intent.meta.json` 70 MB, `intent.vectors.json` 51 MBM SK1 JSON- serialisointi luo toisiinsa liittyvän stringin muistissa | 100+ | MB |. | Tämä string kulkee suoraan LOH:hen |

```mermaid
flowchart LR
    classDef input fill:none,stroke:#3b82f6,stroke-width:2px
    classDef async fill:none,stroke:#a855f7,stroke-width:2px
    classDef problem fill:none,stroke:#ef4444,stroke-width:2px

    R["HTTP request"]:::input --> H["LearningHandler<br/>FullDetection event"]:::async
    H --> L["List&lt;float[]&gt;<br/>graph vectors<br/>(no eviction)"]:::problem
    L -.5 min timer.-> J["JsonSerializer.Serialize<br/>~100 MB string"]:::problem
    J --> LOH["Large Object Heap"]:::problem
    L -->|grows every request| L
    LOH -.fragmentation.-> RSS["Process RSS climbs"]:::problem
```

Nyt: helppo korjaus on lisätä katto `MaxVectors = 10_000`, LRU:n karkottaminenM SK1 purjehtiminen. Se olisi toiminut . Luvut olisivat laskeneet,, Tappiot näyttäisivät hyvältä,. Sekin olisi ollut väärääMSC6

HNSW on erinomainen teknologia, ja käytän sitä tarkoituksellisesti muualla.[Self-Hosted Vector Databases with Qdrant](/blog/self-hosted-vector-databases-qdrant), [RAG-hybridinen haku ja indeksointi](/blog/rag-hybrid-search-and-indexing), [Vähimmäiskäytännöllinen GraphRAG](/blog/graphrag-minimum-viable-implementation)). [Pineconi](https://www.pinecone.io/learn/series/faiss/hnsw/), [Vaurioituminen](https://weaviate.io/developers/weaviate/concepts/vector-index#hnsw-index), [pgvector](https://github.com/pgvector/pgvector#hnsw), ja [Qdranti](https://qdrant.tech/documentation/concepts/indexing/#vector-index) kaikki käyttävät sitä sisäisesti. mutta se' on indeksi komissiostaM SK2 ei cachea , ja StyloBot tarvitsi itse asiassa cachea *"kaikkien aktiivisten sormenjälkien osalta , säilyttää pieni ikkuna viimeaikaisista käyttäytymisvektoreista, jotta havaitseminen voi verrata nykyisen pyynnön aikaisempaa käyttäytymistä vastaaviin* Botin sormenjälkiä toistetaan ( jää kuumaksi ); ihmisen sormenjäljet eivät ole 't [Niin yksinkertaista kuin mahdollista](/blog/botdetection-part3-as-simple-as-possible) prosessin HNSW-indeksi on lueteltu osana ominaisuuksia.

On olemassa ”'” – pikatesti hajusta“:” – jos kuvittelette, että rakennukseen on tehty kova päällys”,” – lopputulos on semanttisesti edelleen se, mitä halusitte” ?” – HNSW:tä, joka on sidottu jatkuvaan pisteeseen ei ole “'” – indeksi, eikä se ole ”,” – se on ”M SK6” – huono ”Cash”, jossa on indeksi”, ja "'” – aseita.

**Säännöt:** kun näette rajattoman kasvun, kysymys ei ole *"millä tavoin saamme tämän rakenteen päätökseen?* mutta *Tämä on oikea rakenne sille, mitä teemme* Ensimmäinen peittää oireet. Toinen kuulee, mitä se teille sanoo.

## Askel 4: Ottakaa oikea muoto, ei vain katto

Kun olette nimittänyt väärän abstraktin, korvaus kirjoitetaan yleensä itse. StyloBotissa oli kaksi kerrosta.

**Heißlaaja:** a rajattu `BoundedVectorCache<TEntry>`, hiukka wrapper ympärille [`ConcurrentDictionary`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2) pääsyn kanssa-taajuus ensisijainen poistaminenM SK1 säilyttämisäänistö antaa botille-luokkaan kuuluville merkinnöille MSC3x eloonjäämisen painoaMST4 niin että kasvi on itse \-\organisoitu liikennemuodon ympärille \ :\

```csharp
retentionScorer: (_, entry) => entry.WasBot ? 2.0 : 1.0
```

**Pysyvä taso (FOSS):** kolme uutta SQLite-taulukkoa (`signature_centroids`, `session_centroids`, `intent_centroids`) painettujen centroidien varastointi yöaikaisesta `VectorCompactionService`. Vektorit varastoidaan raaka-aluksena, [`MemoryMarshal.AsBytes`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.memorymarshal.asbytes):

```csharp
internal static byte[] PackFloats(float[] v) =>
    MemoryMarshal.AsBytes(v.AsSpan()).ToArray();
```

Kompaktinen binaarinen serialisointi. Ei 100+ MB JSON-stringitM SK2 Ei LOH.

> **Storage-tier note.** SQLite on FOSS-järjestelmä / yksittäinen - kaksoispuitteettoman backendin - oikea puheenvuoro \" pudottaa exe piin ja kävellä pois \ ." kaupallinen StyloBot käyttää PostgreSQL:tä [pgvector](https://github.com/pgvector/pgvector), antaa asianmukaisen indeksoidun samankaltaisuuksia koskevan hakutuloksen *tietokannan sisällä* - vakaalla komissiolla, , jossa HNSW kuuluu, M SK2 horisontaalisella mittakaavalla,, ja yhteisessä valtiossa koko laivaston alueella, . Yhteinen arkkiteettinen sääntö,M SK5 erilainen tausta,. [sqlite-vss](https://github.com/asg017/sqlite-vss) on askeleenpylväs, jos haluatte laajentaa SQLite-järjestelmää mutta pysyä yhtenäisenä.

FOSS:n pysyvällä tasolla tehtävät samankaltaisuustutkimukset ovat brute-force cosine over all rows[`System.Numerics.Tensors.TensorPrimitives`](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.tensors.tensorprimitives)). Kompaktoidussa -, keskikokoisessa (, satojen tai muutaman tuhannen rivin mittakaavassa, ),, koko skannaus kestää Pi:ssä ~1-2 ms.

Huomautus **L1/LM SK1 compaction**, sen jälkeen, kun "compaction" tekee todellista työtä tässä osassaM SK3 compaction-palvelu toimii yöaikaisesti ja vähentää historiaa kahdesti

- **L1**: otetaan kaikki tänään kirjoitetut raaka-arvotM SK1ryhmä, ne, jotka ovat hyvin samankaltaisia , ja korvataan kukin ryhmä yhdellä centroidilla ( keskimääräinen). edullinenMSC5 tapahtuu usein
- **L2**: otetaan LM SK1 keskikeskukset, jotka ovat samankaltaisia päivien ja viikkojen välisenä aikana /viikkoina, ja yhdistämme ne uudelleen. agressiivinenMST4 tapahtuu vähemmän useinMSV5 suuren kokon vähentäminen MST6muunlainen mST7xMST8 Se, mikä selviytyy L\MST9\ on liikenteen pitkän aikavälin muotoMSTO11\ ei väliaikaista melua\MSTO12\

Tämä on sama malli LSM-puuvarausjärjestelmien moottorit (RocksDBM SK2 LevelDB , Cassandra\) käyttäminen SSTableihinMSC5 taso |0 pitää hiljattain korjattua luokkaa | - hillittyjä tietoja ♫ ; alhaiset tasot pitävät compactoituja ♫, yhteenvetottuja tietoja \ . lainaaminen toimii, koska pääsymalli on samanlainen ♫

```mermaid
flowchart LR
    classDef input fill:none,stroke:#3b82f6,stroke-width:2px
    classDef store fill:none,stroke:#f59e0b,stroke-width:2px
    classDef async fill:none,stroke:#a855f7,stroke-width:2px
    classDef good fill:none,stroke:#22c55e,stroke-width:2px

    R["HTTP request"]:::input --> FP["Fast path<br/>BoundedVectorCache.TryGet"]:::good
    FP -->|hit| S["Use similarity signal"]:::good
    FP -->|miss| N["null<br/>other detectors still run"]:::good
    R -.post-response.-> BG["Background learning handler"]:::async
    BG --> DB["SQLite (FOSS)<br/>or Postgres+pgvector (paid)"]:::store
    BG --> WARM["Warm cache for next time"]:::async
    WARM --> FP
    NC["Nightly VectorCompactionService<br/>L1 then L2"]:::async --> DB
    DB --> NC
```

Yleismuoto (**rajattu kuumaキャッシュ vakaalle tilalle + compact persistent store historialle + periodic compactor between them**) ilmenee yhä useammin pitkässä -käynnissä olevissa oppimisjärjestelmissä, . se on arvokasta säilyttää työkaluissanne,. kun joku hakee HNSW:tä tai pgvectoria työtaakkaa varten, jonka ' on itse asiassa varattu,, tämä on halvempi,MSC7 yksinkertaisempi asia, johon olisi pitänyt päästä sen sijaan,M SK8

**Säännöt:** mieluummin yksinkertaisinta tietorakennetta, joka sopii *runtime-malli*, ei se, joka sopii tietokokonaisuuteen

## Menettely 5: Tehdään nopeutettu tie sallimaan virheet

Täsmällinen: ,, koska se koskee pikemminkin hillitsemistä kuin lisäystä

Jos hitaan-parannustie sisältää tietokannan etsinnän, houkutus on tehdä siitä nopean tien vyöhykkeeksiMSC2 DonM SK3t . StyloBotin havaitsemisnopeustie on synkronistinenMST5 ja samankaltaisuuksien tarkastaminen ei ole ‐-blokoivia dictionary lookup-tarkastuksiaMSSK7

```csharp
if (!_cache.TryGet(signatureId, out var entry))
    return null; // no signal this request - other 48 detectors still run
```

Miss tarkoittaa *ei vastaavuussignaali tätä pyyntöä*. Muut havaintolaitteet toimivat edelleen. taustakäsittelijä hakee SQLitea sen jälkeen, kun pyyntö on saatu päätökseen ja Cache on lämpenetty seuraavaksi kerralla ; nopea tie ei koskaan pysäytä tietokannan hakua

Tämä on se, missä suurin osa tallennetusta tilasta menee pieleen: ihmiset rakentavat tallennetun tilan, tekevät palautumisen synkronistiseksi M SK2tarkoituksenmukaisuuden vuoksi ", ja virhetasosta tulee 50ms p~99 huijausMSC6 tallennetus oli tarkoitettu tekemään asiat nopeammiksiMST7 sen sijaan se teki pahimman tilanteen huonommaksiMSV8

**Säännöt:** jos pystytte't suvaitsevat virhettä, ette ' ei cacheaM SK3 teillä on fancy queue

## Askel 6: Tarkastus *joka kerta* akku, ei vain kova

Kun olette löytäneet yhden rajattoman rakenteen, olettakaa, että on muitakin.

Tilintarkastus on mekaaninen. jokaiselle pitkälle käännökselle - eläväksi käännetyksi käännnöksiM SK2 luetteloon, tai luetteloonsa *mitkä rajoittavat sen kokoa,, kuka päättää, milloin tulot poistuvatM SK1 ja mikä ' on pahin tapaus vihamielisessä liikenteessä?* Jos pystytte vastaamaan kaikkiin kolmeen kysymykseen yhdessä lauseessa, [Lyhyt signaalit](/blog/ephemeral-signals) malli: kaiken, mikä kerääntyy, on kumottava

StyloBotin osalta: Most accumulators were already well-bounded

- `EphemeralPatternReputationCache`: jäykkä päällys 10,000 merkintöihin, joiden taustalla on hajoaminen ja LRU:n poistaminen `Neutral` → `Suspect` → `ConfirmedBad` valtiokone, ja epäsymmetrinen hystereesi elävät [Oppiminen nopeuttamaan](/blog/stylobot-release-learning))
- `BehavioralPatternAnalyzer`: IMemoryCache per-identiteettirajojen kanssa.
- `DriftDetectionHandler`:  10,000 mallit
- `SessionEscalationService`: 35-minuuttinen TTL timerin kanssa

HNSW-luokkien lisäksi tarvitaan huomiota `MarkovTracker._cohortBaselines`. [Markov-ketju](https://en.wikipedia.org/wiki/Markov_chain) jäljittäjä ylläpitää per-kohortin lähtökohtaisia siirtymämatriittia, jotka ovat erillään per - allekirjoitusketjuistaM SK3 ja joista LRU oli jo karkotettu `MaxTrackedSignatures`). Kohorttien peruslinjat ( yksi liikennekohortin kohden, kuten |"datacenter | - | uusi | | 4 | tai | 5 | asuinpaikka | 6 | paluu | 7 | ei ollut lainkaan karkottamista | 8 | määräys | 9 | karkottaa kylmäimmät kohortit | 10 | vähimmäistaso kokonaismuutoksissa | 11 | silloin kun sanasto ylittää `SelfMaintenanceOptions.MarkovCohortSize`.

**Säännöt:** kukin yksitoninen keräys vastaa kolmeen kysymykseen tai se

## Askel 7: Tehkää kaikki rajat konfiguroitavissa

Seuraava epäonnistumismuodon jälkeen "ei rajoitetta" on "joukko, jokaM SK3on vääränlainen tälle laitteelle `MaxEntries = 10_000` on hyvä, kunnes joku hallinnoi palvelua Pi'llä tai kontissa, jossa on 256 MBM SK2

StyloBotin , osalta kaikki raja-arvot laskeutuivat yhdestä `SelfMaintenanceOptions` suljetaan `appsettings.json`. Tasa-arvot toimivat tavanomaisen verkon osalta . Rajoitettuja laitteita varten `LowMemory` static preset:

```csharp
public static SelfMaintenanceOptions LowMemory => new()
{
    SignatureCacheSize  = 1_000,
    SessionCacheSize    = 500,
    IntentCacheSize     = 300,
    MarkovCohortSize    = 2_000,
    CacheSlidingExpiration = TimeSpan.FromHours(1),
};
```

```csharp
builder.Services.AddBotDetection(opts =>
{
    opts.SelfMaintenance = SelfMaintenanceOptions.LowMemory;
});
```

Vai sen kautta `appsettings.json` ympäristölle-erityinen tuningM SK1

```json
{
  "BotDetection": {
    "SelfMaintenance": {
      "SignatureCacheSize": 1000,
      "SessionCacheSize": 500,
      "IntentCacheSize": 300,
      "CentroidRetentionDays": 14
    }
  }
}
```

Syvempi kohta, :, raja, jonka ' on asetettu yhteen paikkaan, on se, mitä operaattorit voivat perustella. `const int` julistukset ovat asia, jota kukaan ei voi perustella.

**Säännöt:** jokaista rajaa operaattori voi haluta muuttaa omien laitteistojensa osalta yhden config-kierroksen avulla., ei ole hajautettu koko codebasen läpi.

## Miten "fixedM SK1 näyttää

StyloBotin osalta erityisesti (FOSS-rakentaminen,LowMemory presetM SK2

|komponentti SSK1 Ennen | Sen jälkeen S|
|---|---|---|
| allekirjoitus HNSW-indeksi
| Istunnon HNSW-indeksi | | | Unbounded LOH |
| Suunnitelma HNSW-indeksi
| JSON autosave-pufferit SSK1 100-500 MB LOH joka S5 min
| Markov-kohortin lähtökohdat
| Vektoritaso kokonaisuudessaan **13+ GB LOH** | **<6 MB** |

Tunnusmalli ei ole muuttunut. Mitkä muutokset ovat *jossa on olemassa todisteita samankaltaisuudesta* ja *kun se' sallii vaikuttaa nopeaan tietä*. Centroidit säilyvät SQLitessa uudelleenkäynnissä (FOSS) tai PostgresM SK3pgvector (paidMSC5 yökompaktointi tuottaa edelleen LMST6LMSV7 yksikään niistä ei edellytä rajatonta muistiaMSSK8

Pi:ssä 4 LowMemory-asetuksen mukainen ennallaan , FOSS-rakenne on sijoittautunut ±500 MB RSS:n mukaiseksi warmupin jälkeen, loputtoman ajanjaksollaMSC4 maksullinen postgresiM SK5 tukitut käyttöönotot ovat samaa kuumaa ± - talletusjärjestelmiä koskeva sääntöjä noudattava layer ±; pysyvä taso vain mittaa horisontaalisesti sen sijaan, että se elää prosessin läheisyydessä ±SSK8 joka tapauksessa ±: ennustettavissa oleva vakaa ±

## Yleistä opetusta

Kapsin lisääminen rajoittaa muistia muuttamatta rakennetta. väärä abstrakti pysyy vääränä; oire vain vaikeneeM SK2 seuraava henkilö, joka koskettaa järjestelmää, perii rakenteen, joka toimii lähestulkoon , mikä on huonompaa kuin se, joka ei selvästikään toimi

Muodot, jotka toistuvat pitkässä-käynnissä olevissa oppimisjärjestelmissä

- **Cap the hot path**: rajoittuu, , sisältyy, M SK2 muistiin,, on suunniteltu ohjusten sallimiseen, , karkotuspolitiikka yhdenmukaistettu työmäärän kanssa
- **Kompressoida historia**: compact binary persistent store , periodically compacted
- **Tarkastellaan kaikkea muuta**: kukin akkumulaattori vastaa siihen, mikä sen rajoittaa , mitä se karkottaa M SK2 mikä ' pahin tapaus
- **Keskeistetään polttimet**: yksi config-blokti , ei viisitoista `const`s
- **Luettelo tarkastelusta**: virhe on vain käynnissä olevassa järjestelmässä

Fix the shape, not the symptomM SK1

---


## Lisä lukeminen

**StyloBot -sarja**

- [Käytänne, Ei identiteettiä](/blog/stylobot-fingerprint): käyttäytymismalli ja Leidenin klusterointi tämä taso on muisti
- [Behaviour-Aware ASP.NET UI](/blog/behaviour-aware-ux): pinta, joka kuluttaa havaitsemispäätöksiä Razorissa
- [Oppiminen nopeuttamaan](/blog/stylobot-release-learning): neljään luokkaan kuuluva oppijärjestelmä ja tuomiovarasto, jota tämä muistiin liittyvä kurinpito rajoittaa
- [Bot-detection part 2: Signature Pipeline and StyloBot Architecture](/blog/botdetection-part2-signature-pipeline-and-stylobot-architecture): alkuperäinen havaitseminen -engine-arkkitehtuuri
- [Bot-detection part 3: mahdollisimman yksinkertainen](/blog/botdetection-part3-as-simple-as-possible): kaksinkertainen -line dropM SK2in (, jossa otettiin ensimmäisen kerran käyttöön HNSW-indeksi prosessissa

**HNSW ja vektorinen haku tässä blogissa**

- [Self-Hosted Vector Databases with Qdrant](/blog/self-hosted-vector-databases-qdrant): HNSW syvänpyynti `M`, `ef_construct`, mukauttaminen
- [RAG-hybridinen haku ja indeksointi](/blog/rag-hybrid-search-and-indexing): HNSW hybridiperätysputken tiheänä puoletna
- [Vähimmäiskäytännöllinen GraphRAG](/blog/graphrag-minimum-viable-implementation): DuckDB VSS HNSW gotcha`array_cosine_distance` vs `array_cosine_similarity`)
- [Semanttinen haku ONNXin ja Qdrantin kanssa](/blog/semantic-search-with-onnx-and-qdrant): HNSW:n konfigurointi Qdrant-clientin kautta
- [GraphRAG: Miksi vektoritutkimus katkeaa Corpus-tasolla](/blog/graphrag-knowledge-graphs-for-rag): miksi puhdas ANN ei ole

**Ulkoiset viittaukset**

- [HNSW (WikipediaM SK1](https://en.wikipedia.org/wiki/Hierarchical_navigable_small_world_graphs)
- [Malkov & YashuninM SK1 *Tehokas ja vahva läheisimpien naapurien lähentämistutkimus hierarkisten navigointikelpoisten pienmaailman grafiikkojen avulla*](https://arxiv.org/abs/1603.09320): alkuperäinen paperi
- [Pinecone: Faiss M SK1 HNSW selvittäjä](https://www.pinecone.io/learn/series/faiss/hnsw/)
- [Kranttiindeksointi käsitteet](https://qdrant.tech/documentation/concepts/indexing/#vector-index)
- [.NET Large Object Heap -asiakirjat](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap)
- [`dotnet-counters` viittaus](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters): alun perin LOH:n pintaan tuoma työkalu
- [JetBrains dotMemory - komenti-liiniprofiili](https://www.jetbrains.com/help/dotmemory/Command-Line_Profiler.html): tämän uudelleenkäsittelyn yhteydessä käytettävä CLI-tietoprofiili
- [JetBrains dotTrace-command-liiniprofiili](https://www.jetbrains.com/help/profiler/Performance_Profiling__Profiling_Using_the_Command_Line.html): sama muoto suorituskykyyn / aikatauluprofiili
- [sqlite-vss](https://github.com/asg017/sqlite-vss): SQLite + Faiss, jos ja kun pysyvä taso ylittää brute force -voiman

Lähde täytäntöönpanosta: [github.com/scottgalM SK2stylobot](https://github.com/scottgal/stylobot). Elävä moottoriM SK1 Dashboard , ja kaupalliset valvontalaitteet [stylobot.net](https://www.stylobot.net).