StyloBot-Release-Serien – Finden und Fixieren von ungebundenem Wachstum in langen --Running-.-NET Services
Long---Running Dienste neigen dazu, langsam in Richtung ungebundenen Gedächtnisses zu driften..-Hier finde ich, wie ich diese Drift finde, ,-wie ich darüber nachdenke, es zu fixieren, ohne über ihn zu papieren. ,-und ein bearbeitetes Beispiel von StyloBot.'-Vektorgleichheitsschicht, die es von 13-GB auf der Large Object Heap zu unter 6-MB nahm
StyloBot Release Series
- Verhalten nicht IdentitätWarum StyloBot die Kunden verhaltensmäßig modelliert
- Verhalten Bewusst WERDENDie Oberfläche des Servers wurde über dieses Erkennungsergebnis gespiegelt.
- Ungebundenes Wachstum in langen --Diensten finden und behebenDie Zuverlässigkeitsdisziplin ist ein Beispiel für die Bearbeitung von :. StyloBot.).
- Verhalten--Bewusstsein TypScript UIKomponenten von , und Browsern
- Die Sidecar-ArchitekturWie der Detektions-Engine mit Nicht--.-NET-Stacks verbunden wird
- Schneller lernenDas adaptive Lernsystem (MSK) und der Urteilscache
- Testen der Sache, die Won-' sitt StillEine BDF-Datei treibt Regression an.
- StyloExtrahieren Sie einen lokalen HTML zu Markdown KonverterDie HTML-Markdown-Schicht, die sich mit dem Detektor verbindet, hat den Walker Bug lucidVIEW gefangen und die Hundefutterschleife, die es ehrlich machte.
Das bearbeitete Beispiel ist der StyloBot Vektor Layer, aber die Disziplin ist: '.StyloBot.-.specific.....Jeden langen -.Running-Dienst, der Zustand aus dem Verkehr anhäuft, wächst schließlich eine Klasse von Fehlern, die Sie in Tests oder kurzen Lastläufen fangen können...Es zeigt sich nur nach Tagen des realen Verkehrs.MSC8. Dieser Beitrag ist das Playbook, mit dem ich es finde
Das Verhaltensmodell ist in Verhalten nicht IdentitätDie Oberfläche von ASP-.-NET in Verhalten Bewusst WERDENQuelle: github-.-com./-scottgal./-stylobot.
Die Kategorie der Probleme
Jeder Cache, jeder Lernspeicher, jedes ,, jedes ", jedes ®', halten einfach die letzten N-Anfragen, jeder Puffer ist ein winziger Akkumulator, jeder sieht auf eigene Faust gut aus.,, zusammen mit einem Prozess, der für eine Woche geöffnet war.,, bilden sie eine Speicherform, die kein Test jemals reproduziert.
- arbeitet fein in dev-,-CII und der erste Tag in der Produktion
- nach und nach in Richtung OOM-, drift, dann entweder abstürzt oder beginnt zu paging
Du fängst das hier an absichtlich danach suchendAuf einem Prozess, der lange genug läuft, damit die Form entstehen kann.
Schritt -1: , Periodische Zuverlässigkeit Bewertungen -( , der Akt des Aussehens , ) ,
Das erste Stück der Disziplin ist der Kalendereintrag.
Alle paar Releases ich stoppe das Hinzufügen von Features und schaue einfach auf das laufende System unter realistischem Traffic. tut jeder dieser Blick falsch Kein spezifisches Problem ,, , kein Ziel .. , nur suchend ,. , Laufende Systeme liegen leise , ; , sie nicht laut scheitern , bis sie katastrophal fehlschlagen , . , Wenn Sie nur schauen, wenn etwas bricht ,, , Sie bereits verloren ' ,
Die neueste Überprüfung gefangen den Fehler dieser Beitrag ist über . Mostlylucid.BotDetection.Demo Prozess sitzen an einem -20 , GB Bewohner unter synthetischem Testverkehr eingestellt , dass , ' , die Art von Zahl, die nicht überleben sollte dreißig Sekunden Aufmerksamkeit ,. ,
Artikel 2 Absatz 1 Buchstabe b Setzen Sie einen wiederkehrenden Steckplatz auf den Kalender, um Ihre eigenen Metriken zu lesen..-Nicht, um irgendetwas zu beheben.
Schritt - Lassen Sie Zähler überraschen Sie
Das richtige Werkzeug für -"- ist etwas falsch -?"-auf einem -mesK2-NET-Prozess ist dotnet-countersEs ist kostenlos, es ist bereits installiert, und es sagt Ihnen die Wahrheit darüber, was Ihr Prozess jetzt tut.
Ein paar Kommandos später auf der StyloBot-Demo
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
Das ist genug, um zu wissen, was nicht stimmt, ohne irgendeinen Code zu lesen. Große Objekt-Heap war auf der 13.4, GB und wächst bei fast 100, MB, /,sec, ., etwas war die Zuteilung riesiger Objekte kontinuierlich und die Gen-2, GC konnte nicht mit ihnen Schritt halten
Ein schnelles Auffrischen auf der LOH -(, weil jeder dev trifft dieses schließlich .
Die Large Object Heap ist eine der häufigsten Überraschungen beim ersten Profilieren eines langen --Laufservices, denn fast jeder trifft es auf die harte Art und Weise.
- Die GC hat drei Generationen -- (--Gen-0,-Gen.1,-Gen, die für normale Kurzfassungen verwendet werden -- --lived objects --MSC5 -- Die meisten Zuweisungen leben und sterben in Gen.MSC6, die billig zu sammeln ist.
- Alles, was größer ist als 85. KB tut '. geht nicht in jenen Generationen Es geht geradeaus auf die Große Objekt-Heap.
- Die LOH wird nur während einer GENERALDIREKTION GCDas ist die teuerste Sammlung, das ist ..NET tut ..Gen.2. geschieht selten und die Laufzeit versucht es zu vermeiden.
- Schlimmer: Standardmäßig ist die LOH nicht verdichtet Wenn es gesammelt wird, befreit es einfach die Slots... Also auch nach einem Gen-2,. die LOH wird fragmentiert ?:. Sie haben freien Raum, aber es ist '. in den falschen -.große Löcher für die nächste Allokation - .. Neue große Objekte erweitern den Haufen anstatt ihn wiederzuverwenden
- Net effect.:, halte große Objekte mit einer konstanten Rate zuordnend und dein Prozess marschiert der Memory Footprint von ' nach oben, ob die Objekte noch referenziert werden oder nicht, es sieht wie ein Leck aus, auch wenn es eins ist.
Die größten Quellen des zufälligen LOH-Wachstums in realen .-NET-Diensten... in meiner Erfahrung...
| Quelle : | , warum es auf dem LOH endet. | |
|---|---|---|
JsonSerializer.Serialize(obj) Rückgabe einer string Ein MB-Objekt wird zu einem MB-String in einer Zuweisung. |
||
MemoryStream du lässt unbounded wachsen |
. Interner Puffer verdoppelt sich hinter 85. KB und bleibt auf der LOH. | |
byte[] buf = new byte[n] für große n Die direkte LOH-Zuweisung von ; ist sehr häufig in der Datei / network liest sich |
||
List<T> das vorbei wächst ~10-K-Referenzen --typierte Elemente |
-Backing Array Kreuze 85-KB und landet auf der LOH | - |
string.Concat / StringBuilder über den großen Text ToString() ist eine einzige riesige Zuweisung - |
- | |
XmlSerializer / DataContractSerializer von großen Graphen Die gleiche Form wie der JSON-Fall |
Wenn Sie sich nur an eine Faustregel erinnern einem Codepfad misstrauisch sein, der ein einzelnes zusammenhängendes großes Objekt auf einem Timer oder pro Anfrage erzeugt Das ist die Form, die lange Wracks - Laufende Dienste , und es ' ist genau die Form wir ' sind im Begriff, in StyloBot zu finden
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 >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
Werkzeuge, die helfen, es zu diagnostizieren
dotnet-countersfür Live-Zahlen, das LOH-Messgerät über dem ).dotnet-gcdumpunddotnet-dumpfür Snapshots, die Sie in Visual Studio oder PerfView öffnen könnenPerfView selbst für Tracing-Zuweisungen bis hinunter zu einem Stack
JetBrains CLI Profiler Was ich eigentlich für dieses Rework verwendet habe, ist jetzt als richtige globale Tools verpackt.,e so kopflos entfernte /e CI-Laufzeitprofilierung braucht keine Rider GUUI.MSC6e
JetBrains.dotMemory.GlobalToolsNehmen Sie einen Speicher-Snapshot, öffnen Sie die.dmwworkspace später zu sehen, welche erhaltenen Wurzeln halten die LOH-ZuweisungenJetBrains.dotTrace.GlobalToolsVerwenden Sie dies, wenn Sie einen Stapel anstatt eines Zählers benötigen...g.., was ist das Timer tatsächlich tut??")..
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.dtpArbeitsteilung für diese Überarbeitung
dotnet-counterssagte mir, die LOH war das Problem... die dotMemory-Snapshot erzählte mir, dass der Autosave-Timer die Ursache ist.
Es gibt Fluchtluken, wenn du sie wirklich brauchst GCSettings.LargeObjectHeapCompactionMode = CompactOnce erzwingt eine One---off LOH-Verdichtung RecyclableMemoryStream von Microsoft Pools Puffer, um die Zuteilung in erster Linie zu vermeiden .. . Beide sind Putze Die reale Fix ist fast immer zu stoppen Produktion des riesigen Objekts in den ersten Platz ?. .
Zurück zur Diagnose
Also, wann immer du ein stetiges LOH-Wachstum in einem langen - running Service siehst, ist die Frage fast immer die gleiche. Was ist ', die sehr große Objekte zuweisen? ,, auf welche Kadenz? , und warum? Die Form der Antwort (-Timer-Request-Handler-?-Serializer-?-Puffer-Pool sagt Ihnen, wo Sie im Code suchen
Auch die Ausnahmen spielten eine Rolle. 4/sec von SqliteException ist niedrig genug, um nicht in Protokollen zu zeigen, die jemand liest.,, aber hoch genug, Ihnen zu sagen, ein Code-Pfad stumm wieder versucht wird...
Artikel 2 Absatz 1 Buchstabe b wenn etwas falsch aussieht. dotnet-counters vor dem Raten-Erraten-.-Die Zahlen werden den Suchradius um eine Größenordnung von Magnitude verengen -.-
Schritt: Der falsche Geruch von -Abstraktion, Beispiel: :, HNSW für Caching, ),
Dies ist, wo die Disziplin wird interessant weil die Versuchung immer Pflaster das Symptom, anstatt die Abstraktion in Frage zu stellen
Schnell Vokabeln für die nächsten paar Abschnitte
- VektorEine feste Anordnung von Floats in der Größe von -.
float[64]Jeder Steckplatz ist eine gemessene Eigenschaft der Anforderung.( header count, , timing, IP-Familie, , usw., MSC5 Zwei Anfragen, die ähnlich sind, wie " zu erzeugen Vektoren, die einander nahe im Raum von 64- dimensional sind.float[].- Ähnlichkeit der VektorenÜblich Cosin-Ähnlichkeit Die tatsächliche Mathematik ist ein Punktprodukt, das durch zwei Normen geteilt wird.
- Ungefährer nächster Nachbar" ist dieser Vektor gegeben , Finden Sie das nächste N aus Millionen , Schnell". , Brute-- , Kraft Vergleich ist O.( , N.SK7 , pro Abfrage . , ANN-Algorithmen erhalten sub ,- , Millisekunde Ergebnisse auf Kosten des gelegentlichen Fehlens der wahr engste Übereinstimmung
- HNSWEs baut einen geschichteten Graphen, in dem die obere Schicht ein paar gut verbundene Knoten und untere Schichten im Detail ausfüllen. stabil Satz von Vektoren, die nicht für jede Anfrage entwickelt wurden, fügt ein und alte hinzu, gehen weg, "... den relevanten Punkt dieses ganzen Beitrags.
- CentroidEin Vektor, der den Cluster zusammenfasst Wenn Sie die Vektoren haben, die alle im Großen und Ganzen ähnlich aussehen, können Sie sie wegwerfen und einen Zentrioid halten.Der Zentraid ist ein verlustiger aber kompakter Ersatz... Verdichtungsstrategien verwenden diese, um eine Menge Rohgeschichte in eine kleine Zusammenfassung Geschichte zu verwandeln.
Das LOH-Wachstum führte zu drei Klassen, die strukturell identisch waren. HNSW .( Hierarchische Navigation Kleine Welt . . ) .Original Papier Malkov -&-YashuninFür die Ähnlichkeitssuche über Signature verwendet, ,.Session.,. und Intent-Vektoren, MSV3. Jeder hatte ein Feld wie :.
private readonly List<float[]> _graphVectors = new();
Jeder wurde von einem Lern-Handler gefüttert, der abonnierte LearningEventType.FullDetection, die auf Feuer jede HTTP-AnfrageJede Anfrage fügte einen Vektor hinzu.
Und alle fünf Minuten ein Autosave Timer serialisierte den gesamten Graphen zu JSON und schrieb es auf Diskette
private readonly TimeSpan AutoSaveInterval = TimeSpan.FromMinutes(5);
Im Demo-Skala signatures.vectors.json war 104, MB, ., in der Produktion intent.meta.json bei 70, MB, ,, intent.vectors.json bei 51 , MB , . , JSON-Serialisierung erzeugt eine zusammenhängende Zeichenkette im Speicher bei 100+ , . , Das String geht direkt auf die LOH ,. , Drei Indizes , alle fünf Minuten , und , , kontinuierlich wachsend .. ,
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<float[]><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
Jetzt ist der einfache Fix, um eine Kappe hinzuzufügen. MaxVectors = 10_000Es hätte geklappt ,. , Zahlen würden nach unten kommen ,, , Dashboard würde fein aussehen , . , Es wäre auch falsch gewesen .. ,
HNSW ist eine ausgezeichnete Technologie und ich benutze sie bewusst anderswo.Selbstbeleuchtete Vektordatenbanken mit Qdrant, RAG Hybrid Suche und Indexierung, Mindestlebenswerte GraphRAG). Kiefernzapfen, Schwitzen, pgvectorL 347 vom 20.12.2013, S. 671. Qdrant alle verwenden es intern, aber es ist ein Index eines corpus, nicht ein cache und was StyloBot tatsächlich brauchte, war ein Cache. Bewahren Sie für jeden aktiven Fingerabdruck ein kleines Fenster neuer Verhaltensvektoren auf, damit die Detektion die aktuelle Anforderung gegen vergangenes Verhalten von ähnlichen vergleichen kann. Bot-Fingerabdrücke wiederholen (, bleiben heiß);, menschliche Fingerabdrucke Don-', nicht (, verfehlt)., die früheren So einfach wie möglich post listet die in---Prozess HNSW Index als feature.;. Dieser Beitrag ist der follow--.up-Zulassung, wo das war die falsche fit?..
Es ist ein schneller Test für den Geruch, wenn du dir vorstellst, eine harte Kappe auf die Struktur zu ohrfeigen, ist das Ergebnis immer noch semantisch die Sache, die du wolltest.?. Ein geknapptes HNSW mit konstantem Churn ist ein Index, der ,.
Artikel 2 Absatz 1 Buchstabe b wenn du ungebundenes Wachstum siehst, ist die Frage nicht Wie können wir diese Struktur kapieren? aber Dies ist die richtige Struktur für das, was wir tun Das erste verbirgt das Symptom.Das zweite hört, was es sagt.
Schritt - wählen Sie die richtige Form - nicht nur eine Kappe
Sobald du die falsche Abstraktion genannt hast, schreibt sich der Ersatz gewöhnlich für StyloBot aus zwei Schichten.
Heiße Schicht einer Begrenzung BoundedVectorCache<TEntry>Ein dünner Wrapper um ConcurrentDictionary Der Retentions-Scorer gibt Bot---klassifizierten Einträgen ein Überlebensgewicht von 2x, so dass sich der Cache selbst um das Verkehrsmuster organisiert.
retentionScorer: (_, entry) => entry.WasBot ? 2.0 : 1.0
Persistente Schicht drei neue SQLite-Tabellensignature_centroids, session_centroids, intent_centroidsDie Lagerung der komprimierten Zentrioide aus einer Nacht VectorCompactionServiceVektoren, die als roher Float gespeichert werden MemoryMarshal.AsBytes:
internal static byte[] PackFloats(float[] v) =>
MemoryMarshal.AsBytes(v.AsSpan()).ToArray();
Kompakte binäre Serialisierung – .- Nein – MB-JSON-Strings – .-Nein – LHH-.-Nein
Speicher-Tier Anmerkung .. SQLite ist das FOSS-Single--Binary-Backend, das den richtigen Ruf für -MS K3Drop die Exe auf einem Pi und zu Fuß entfernt. pgvectorSie geben Ihnen die richtige indizierte Ähnlichkeitssuche in der Datenbank Die HNSW gehört zur horizontalen Skala von , und teilt den Zustand über eine Flotte von .. Die gleiche architektonische Regel ist ,. Verschiedenes Backend. sqlite---vss ist ein Sprungstein, wenn Sie SQLite outgrow aber wollen single-Moser bleiben wollen, ist der Cleaner Upgrade das Postgres Tier.
Ähnlichkeitssuche auf der persistenten FOSS-Schicht ist brute.-, Kraftkosinus über alle Reihen, beschleunigt mit SIMD.System.Numerics.Tensors.TensorPrimitivesIm verdichteten - Zentrioid-Skala (hunderte bis zu ein paar tausend Reihen ),, ein vollständiger Scan nimmt ~1-2. ms auf einem Pi... 4., dass ' fein ist. :, das nur im Hintergrund Handler läuft. MSC8 nie auf der Erkennung schnellen Pfad
Ein Hinweis auf VerdichtungDer Verdichtungsservice läuft nachts und reduziert die Geschichte in zwei Pässen.
- ENTWICKLUNGNehmen Sie alle rohen Vektoren, die heute geschrieben werden., group diejenigen, die sehr ähnlich sind, und ersetzen jede Gruppe mit einem Zentrioiden.
- ENTWICKLUNGNehmen Sie L.1, Zentrioide, die sich über Tage ähnlich sind, /Wochen und verschmelzen sie wieder ., Aggressive, ;, geschieht weniger häufig ;, großflächige Reduktion, andere ~10,x-)., was überlebt L. 2, ist die langfristige Form des Verkehrs, nicht das vorübergehende Rauschen.
Dies ist das gleiche Muster LSM---Tree Storage Engines -(-RocksDB-,-LevelDB-MS K3-Casandra-)-Einsatz für SSTables-:-Level hält die jüngsten Feingehalte von --geschliffenen Daten, die unteren Ebenen halten verdichtet,-Zusammengefasste Daten, weil es funktioniert, weil das Zugriffsmuster das gleiche ist :-die meisten liest Schlag aktuelle Daten, ;-ein kleiner Bruchteil der Lesegeräte benötigen den langen Schwanz .;-keine Vorteile aus halten jede rohe Reihe für immer ?.-
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
Die allgemeine Formbegrenzter Hot-Cache für den Steady-State kompakter persistenter Speicher für die Geschichte eines periodischen Verdichters zwischen ihnen' ist es wert, in Ihrem Toolkit zu halten Wenn jemand nach HNSW oder pgvector für eine Workload erreicht, die eigentlich ein Cache ist, ist dies das billigere, was sie stattdessen für . erreichen sollten
Artikel 2 Absatz 1 Buchstabe b die einfachste Datenstruktur bevorzugen, die zum LaufzeitmusterNicht derjenige, der zum Datensatz passt, sondern die Größe auf Papier.
Schritt 5:. Machen Sie den schnellen Weg tolerieren Misses
Ein subtiles, weil es sich um Zurückhaltung und nicht um Hinzufügung handelt.
Wenn der langsame --Fix-Pfad einen Datenbank-Lookup beinhaltet, ist die Versuchung, den schnellen Pfadblock auf ihm zu machen... Don...'.t.. Der schnelle Erkennungspfad in StyloBot ist synchron und die Ähnlichkeitsprüfung ist ein nicht--.blocking Wörterbuch suchen.
if (!_cache.TryGet(signatureId, out var entry))
return null; // no signal this request - other 48 detectors still run
Vermisst bedeutet keine Ähnlichkeit Signal dieser AnfrageDie anderen Detektoren laufen immer noch ,.' Ein Hintergrund-Handler fragt SQLite nach der Anfrage und erwärmt den Cache für das nächste Mal.
Dies ist, wo die meisten Caching geht falsch, die Menschen bauen einen Cache, die ,... machen den Fallback-Synchronous, für Korrektheit, und der Fehlpfad wird ein 50.ms p.99.s Spike, die .. Der Cache war gemeint, um die Dinge schneller zu machen, sondern es machte den schlimmsten Fall schlechter.
Artikel 2 Absatz 1 Buchstabe b Wenn du ein Miss-, nicht tolerieren kannst, hast du einen Cache - . - Du hast eine ausgefallene Warteschlange.
Schritt zur Prüfung jedes Akkumulator - nicht nur die laute
Sobald Sie gefunden haben, eine unbounded Struktur, nehmen Sie an, es gibt andere, die laute ist nur derjenige, der zuerst brach
Das Audit ist mechanisch, für jedes lange Wörterbuch, für jede Liste oder für jeden Satz von : was seine Größe begrenzt, wer entscheidet, wann die Einträge verlassen und was der schlimmste Fall unter feindlichem Verkehr ist. Wenn du alle drei in einem Satz beantworten kannst, dann ist es ein Leck. Vergängliche Signale model-:-alles, das sich ansammelt, muss zerfallen,-ausheben,-oder kompakt.)-
Für StyloBot-,- die meisten Akkumulatoren waren bereits gut ---bounded
EphemeralPatternReputationCacheDie Hartkappe bei Einträgen mit Hintergrundzerfall und LRU-EviktionNeutral→Suspect→ConfirmedBadZustand Maschine und die asymmetrische Hysterese leben in Schneller lernen)BehavioralPatternAnalyzerImemoryCache mit Per---Identitätsgrenzwerten (50-Wege ,, Timings ,, 15- und TTL-)DriftDetectionHandlerMuster von ×, Proben von ,, TTL, -, beschnittenSessionEscalationServiceTTL mit Timer, -, angetriebene Räumung
Man brauchte mehr Aufmerksamkeit über die HNSW-Klassen hinaus. MarkovTracker._cohortBaselinesDie Markov-Kette Tracker hält per---Cohort Ausgangsübergang Matrizen -(-Separat von per-MSC2-Signaturketten, die bereits LRU-Eviktion bei MaxTrackedSignaturesDie Kohorten-Grundlagen der Kohorte, wie z.B. "Datenzentrum, -new" oder "Residential-Returning"), hatten keine Räumung, wenn das Wörterbuch die kältesten Kohor ten übertrifft. SelfMaintenanceOptions.MarkovCohortSize.
Artikel 2 Absatz 1 Buchstabe b jede singleton Sammlung beantwortet drei Fragen oder es ' ist ein bug.:, was sie begrenzt ,, was vermeidet es MSKS3, was -' ist seine schlechteste - Gehäuseform
Schritt 7: . Machen Sie jeden gebundenen konfigurierbar
Der nächste Fehler-Modus nach dem " ist ", dass ' falsch für diese Hardware ist. "., Hard... MaxEntries = 10_000 ist in Ordnung, bis jemand Ihren Service auf einem Pi-4, oder in einem Container mit MSA1.
Für StyloBot.,, jedes Limit landete unter einer einzigen SelfMaintenanceOptions Blockieren appsettings.jsonDie Standardwerte arbeiten für einen Standardserver. LowMemory statische Voreinstellung
public static SelfMaintenanceOptions LowMemory => new()
{
SignatureCacheSize = 1_000,
SessionCacheSize = 500,
IntentCacheSize = 300,
MarkovCohortSize = 2_000,
CacheSlidingExpiration = TimeSpan.FromHours(1),
};
builder.Services.AddBotDetection(opts =>
{
opts.SelfMaintenance = SelfMaintenanceOptions.LowMemory;
});
Oder über appsettings.json für die Umgebung----spezifisches Tuning -:-
{
"BotDetection": {
"SelfMaintenance": {
"SignatureCacheSize": 1000,
"SessionCacheSize": 500,
"IntentCacheSize": 300,
"CentroidRetentionDays": 14
}
}
}
Der tiefere Punkt, der an einem Ort gesetzt wird, ist etwas, das Operatoren über die Grenze von . urteilen können. const int Deklarationen ist etwas, das niemand über die Zentralisierung der Drehknöpfe begründen kann, ist die Hälfte des Seins selbst.
Artikel 2 Absatz 1 Buchstabe b jede Bindung, die der Bediener für sein Hardwareleben in einem Konfigurationsblock ändern möchte... nicht über die Codebase verstreut.
Wie "-Fixed" aussieht
Für StyloBot speziell für (-FOSS bauen,- LowMemory voreingestellt
Komponenten vor der Verwendung nach der Verwendung von | |---|---|---| Unterschrift HNSW Index Unbounded LOH Hot-Cache Sitzungs-HNSW-Index Unbounded LOH - Hotcache KB Intent-HNSW-Index: Ungebundener LOH: Hotcache für | |, JSON-Autosave-Puffer |, 100-500, MB LOH alle 5, min. |, MKS5, MSC6, Ausgangswerte der Markov-Kohorten Gesamt-Vektorschicht ,13+ , GB LOH | <6, MB |
Das Detektionsmodell ist unverändert. wo Ähnlichkeitsnachweise leben und wenn es erlaubt ist, den schnellen Pfad zu beeinflussenDie Centroids überleben die Neustarts in SQLite.(.FOSS-). oder Postgres+.pgvector, (.paid.MSC5. Nachtverdichtung produziert immer noch keines davon erfordert ungebundenes Gedächtnis.
Der FOSS build sitzt auf einem Pi-M4 mit dem LowMemory preset.,.Der FOSS build befindet sich nach der Aufwärmung unter 500. MB RSS auf unbestimmte Zeit..... Bezahlte Postgres...-.backed deployments erben die gleiche heiße -.Cache-Disziplin...;.Die persistente Schicht skaliert einfach horizontal, anstatt neben dem Prozess zu leben.....
Die allgemeine Lektion
Die falsche Abstraktion bleibt falsch Das Symptom wird einfach leiser Die nächste Person, um das System zu berühren erbt eine Struktur, die fast funktioniert, Das ist schlimmer als eine, die offensichtlich tut .
Das Muster, das in langen Lernsystemen reproduziert wird
- Besiege den heißen Pfad:-umgeschränkt,-in-Memory-,-designed, um Misses zu tolerieren,-Eviktionspolitik ausgerichtet auf die Arbeitsbelastung
- Komprimieren Sie die GeschichteKompakter binärer persistenter Speicher, regelmäßig verdichtet, vom Anforderungsgewinde aus zugegriffen
- Prüfen Sie alles andereJeder Akkumulator antwortet, was es begrenzt, ,, was vermeidet es ,, was das Schlimmste Fall
- Zentralisieren Sie die KnöpfeEin Konfigurationsblock, nicht fünfzehn
consts - Planen Sie die SucheDer Fehler existiert nur im laufenden System
Befestigen Sie die Form nicht das Symptom
Literaturhinweise
StyloBot Release-Serie
- Verhalten nicht IdentitätDas Verhaltensmodell und das Leiden-Clustering dieser Ebene ist der Speicher für
- Verhalten Bewusst WERDENDie Oberfläche, die Erkennungsurteile in Razor verbraucht
- Schneller lernenDas vierstufige Lernsystem und das Urteil-Cache, dass diese Speicherdisziplin begrenzt bleibt
- Bot Detection Part Signature Pipeline und StyloBot ArchitectureDie Original-Erkennung der Triebwerksarchitektur post
- Bot Detection Teil so einfach wie möglichDer zwei- oder mehrzeilige Tropfen von -in der (, bei dem der HNSW Index erstmals eingeführt wurde
HNSW und Vektorsuche in diesem Blog
- Selbstbeleuchtete Vektordatenbanken mit QdrantHNSW-Tieftauchgang :, Graphenschichten
M,ef_constructAbstimmung - RAG Hybrid Suche und IndexierungHNSW als dichte Hälfte einer hybriden Retrieval-Pipeline
- Mindestlebenswerte GraphRAG- DuckDB VSS HNSW gotcha
array_cosine_distancevs.array_cosine_similarity) - Semantische Suche mit ONNX und QdrantKonfiguration der HNSW-Konfiguration über den Qdrant-Client
- GraphRAG-:® Warum Vektorsuche auf der Corpus-Ebene nach unten brichtWarum reines ANN ausreichend im Maßstab ist
Externe Verweise
- HNSW-Wikipedia-)
- Malkow & Yashunin , Effiziente und robuste Näherungssuche mit Hierarchical Navigable Small World GraphenDas Original Papier
- Pinecone, MSK, Faiss, HNSW-Erklärer
- Qdrant-Indizierungskonzepte
- Große Objekt-Heap docs
dotnet-countersBezugDas Werkzeug, das die LOH in den ersten Platz tauchte- JetBrains dotMemory-Befehl„-"-ProfilerDer CLI-Speicherprofiler für diese Nachbearbeitung
- JetBrains dotTrace-Befehl„-"-ProfilerDie gleiche Form für die Leistung des Zeitlinienprofils
- sqlite---vssWenn und wenn die persistente Schicht Brute Kraft auswächst
Quelle für die Implementierung github-.-com./-scottgal./-stylobotLive-Engine, Dashboard und kommerzielle Steuerungen am Stylobot-.-net.