Серія релізів StyloBot: Винайти та виправити безмежний ріст у довгостроковій сферіM SK1Running .NET Services (Українська (Ukrainian))

Серія релізів StyloBot: Винайти та виправити безмежний ріст у довгостроковій сферіM SK1Running .NET Services

Monday, 01 June 2026

//

19 minute read

Довгий-сервіси, які працюють, повільно рухаються у напрямку необмеженої пам 'яті . ось як я знаходжу цей рух МSK3 як я думаю про те, щоб його виправити без паперування над ним M SK4 і працюючий приклад з StyloBot ' векторного шару схожості, який переніс його від MSC6 GB на Великому Об' єктному Пагорбі до під МSK7 MB.

StyloBot

Серія випуску StyloBot

  1. Подібність, Не ідентичність: чому StyloBot моделює клієнтів поведінково
  2. Подібність-Усвідомлення ASP.NET UI: сервер - віддав поверхню над результатом виявлення
  3. Винайти та виправити безмежний ріст у довгостроковій-Running M SK1NET Services: дисципліна надійності
  4. Подібність-Усвідомлення інтерфейсу TypScript: Express , Fastify, і компоненти браузера
  5. Архітектура Sidecar: як реагуючий двигун підключається до не МSK1NET стеків
  6. Навчитися швидше: адаптивна система навчання , чотири МSK2 пам 'ять на рівні M SK3 і кэш вердикта
  7. Випробовуємо те, що не зупиняє нас: контрольна дисципліна : один БДФ файл керує регресією МSK2 завантаженням МСК3 та калібрацією
  8. StyloExtract - локальний інтерфейс навчання HTML для конвертера Markdown: HTML → Марка-даун, який поєднується з детектором МSK2 walker bug lucidVIEW caught МSK3 and the dogfood loop that made it honest

Вироблений приклад - векторний шар StyloBot,, але дисципліна - це 't Stylo Bot-спеціальнийM SK3 Будь-яка довга МSK4гортання МSK5NET-сервіс, який накопичує стан з потоку, врешті-решт, зростає до класу błędów, які ви можете зафіксувати в тестах чи в коротких завантаженняхMSC7 Він з 'являється лише після днів реального потокуMスク8 Цей пост є підручником, який я використовую для його віднаймки

Модель поведінки Подібність, Не ідентичність; поверхня ASPM SK1NET в Подібність-Усвідомлення ASP.NET UI; джерело на github.comM SK1scottgal/stylobot.


Клас проблеми

Довгий-сервіси, що працюють, накопичуютьсяM SK1 Кожна кэша , кожний магазин навчання МSK3 кожне " ми M SK5 ми просто будемо зберігати останні N-запити М SK6 буфер - маленький накопичувач . кожен з них виглядає добре сам по собі MSC8 Разом МSK9 в процесі, який МSK10 працював тиждень-на-всьогоден МСК11 вони формують форму пам 'яті, яку жодний тест ніколи не повторює М СК12

  • працює добре в dev, CIM SK1 і перший день виробництва
  • поступово рухається у напрямку OOM, потім або скасується, або починає набирати повідомлення

Ви спіймаєте це навмисно шукаючи його, про процес, який МSK1 тривав досить довго, щоб форма з 'явилась

Шаг 1: Periodic reliability reviews МSK1the act of lookingM SK2

Перша частина цієї дисципліни - це: МСК0 , Не технічна . ".". Це МСК2 , календарний запис.

Кожні кілька випусків, Я припиняю додавати додатки і просто дивлюся на працюючу систему під реальним рухомM SK1 запитуючи чи щось із цього виглядає неправильно? Ніяких конкретних помилок, немає метиM SK1 Просто дивлячись. Работі системи мовчазно лежать ; вони не втрачають звуку МSK4 не втручаються аж до того, як вони катастрофічно втрачатимуть звуку

Найновіша перевірка виявила błąd, що ця стаття про: Mostlylucid.BotDetection.Demo процес, який сидить на 20 жителі Великобританії, встановленному під синтетичною тестовою траєкторією . Таке число МSK2 не повинно пережити тридцять секунд уваги

Правило: ставить повторюваний відлік на календарі, щоб читати власні метрики. Нічого не виправитиM SK1 Просто подивитися

Шаг 2: Дозвольте, що شمارники вас здивують

Правильний інструмент для " є дещо неправильним ?" на МSK2NET-процесі dotnet-counters. Це МSK1 це безкоштовне МSK2 це ' це вже вбудовано СМСК4 і це говорить вам правду про те, що ваш процес робить зараз

Кілька команд пізніше на demo StyloBot:

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

Це достатньо, щоб знати, що не так, не читаючи коду. Величезний об 'єкт був на 13.4 ГБ, і зростав майже МSK1 МБ МSK2 секунда . Щось постійно розподіляло величезні об 'єкти мSK4, а ген M2 GC МСК6 не міг піднятися з ними ммSK7

Швидкіше поновлення на LOH ( тому що кожен . NET dev досягає цього врешті-решт

Великий кусок об 'єктів - це одна з найпоширеніших несподіванок, коли ви вперше застосовуєте довгу-програму M SK1NET-сервіс. ЦеMSC3 варте переробки, бо майже кожен зустрічається з ним по-важкому :

  • GC має три покоління: (ГенМSK1 ГенM SK2 Гн МSK3 для нормального короткого циклу - для живих об 'єктів . Більшість розподілів живе і помирає в гені0,, який дешевий для збору
  • Будь-що більше за 85 КБ не йде в ті покоління Він йде прямо на Величезний об 'єкт.
  • ВАК збирається лише під час Ген2 GC,, яка є найдорожчою колекцією
  • Найгірше, по замовчуванню LOH - не стиснена коли він збирається; він просто звільняє прогалиниM SK1 Таким чином, навіть після гену2, LOH стає фрагментованимMSC3 у вас є вільний простірМSK4 але цеMСК5 є неправильнимМСК6 розміром діри для наступного розподілуМ СК7 Нові великі об 'єкти розширюють купу, а не повторюють їїM СК8
  • Цифровий ефект: продовжувати розподіляти великі об 'єкти з постійною швидкістюМSK1 і ваш процесM SK2 пам' ять рухається вгору, незважаючи на те, чи об' єкти все ще відносяться до них чи ні МSK3 Це виглядає як витік, навіть якщо він не є

Найбільші причини випадкового росту LOH у реальних послугах .NETM SK1 з мого досвіду:

Źródło Чому він опинився на ЛOH МSK2
JsonSerializer.Serialize(obj) повертаючи string Об 'єкт МSK1 МБ стає МSK2 Мб UTF string -16 string , все в одній долиці
MemoryStream ви дозволяєте рости безмежно Внутрішній буфер подвоюється за МSK1 КБ і залишається на LOH
byte[] buf = new byte[n] для великих n пряме виділення LOH ; дуже поширено в файлі
List<T> що росте за минулим ~10 K відмітка МSK1 надруковані речі МSK2 Крести опорної массиви 85 КБ і приземлиться на ЛОХ
string.Concat / StringBuilder над великим текстом Финал ToString() є одним величезним розподілом
XmlSerializer / DataContractSerializer великих графів Те ж саме, що і в випадку з JSON

Якщо ви пам 'ятаєте лише одне правило: бути підозрюваними до будь-якого кодового шляху, який виробляє єдиний супутний великий об 'єкт на таймері або за запит. Те, що "'" - це форма, яка руйнує довгі services , а МSK2 і MSК3 є точною формою, яку ми МСК4 збираємося знайти в StyloBot .

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

інструменти, які допомагають його діагностувати:

  • dotnet-counters для живих чисел (показчик LOH вище МSK1

  • dotnet-gcdump і dotnet-dump для зйомок, які можна відкрити в Visual Studio або PerfView.

  • PerfView для відстеження розподілу до стопки.

  • Профильери JetBrains CLI ( те, що я насправді використовував для цієї переробки ). Зараз упакований як правильний МSK2 NET глобальні інструменти МSK3 так безголовний МСК4 віддалений MСК5 CI розробка пробігу часу не потребує вказівного інтерфейсу gui

    • JetBrains.dotMemory.GlobalTools: під 'єднати , зробити знімок з пам' яті МSK2 відкрити .dmw робочий простір пізніше, щоб побачити, які залишені коріння тримають LOH розподіли.
    • JetBrains.dotTrace.GlobalTools: одна і та сама форма для зразку МSK1 відображання МSK2 дані про часову лінію . Використовуйте це, коли вам потрібна стопка, а не шкала
    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
    

    Розділ праці на цю переробку: dotnet-counters сказав мені, що проблема в тому, що LOH

Є шлюпки для порятунку, якщо вам їх дійсно потрібно. GCSettings.LargeObjectHeapCompactionMode = CompactOnce змушує потиснути LOH на один - RecyclableMemoryStream від буферів Microsoft для того, щоб уникнути розподілу в першу чергу. Обидві штуковиниM SK1 Справжнє рішення - майже завжди припинити виробляти гігантський об 'єкт в першу очередь.

Повернімося до діагностування

Отже, коли ви бачите постійний ріст LOH у довгостроковій-працевлаштуванніM SK1, питання майже завжди таке ж що' це розподіляє дуже великі об 'єкти , на яку каденцію Форма відповіді (timerM SK1 обладнатель запитів? сеrializerMSC3 буферний фондМSK4 вказує вам, куди подивитися в коді

Винятки також мали значення. 4/sec від SqliteException low enough to not show in logs anyone reads, but high enough to tell you a code path is silently retrying

Правило: коли щось виглядає не так, підтвердити з dotnet-counters перед припущенням. Числа зменшать радіус пошуку за порядок величиниM SK1

Шаг 3: Неправильний МSK1 запах абстракції

Ось де стає цікавою дисципліну: МСК0 , тому що спокуса ",", always , зламка симптом, а не питання абстракції.

Гнучкий vocab ( для наступних секційM SK1

  • Вектор: фіксованийM SK1масштабний ряд плавників - eMSC3g. float[64]each slot is a measured property of the request ( header count , timing МSK3 IP family float[].
  • Схожість вектора: зазвичай Схожість косину - косину куту між двома векторами . Близьше МSK2 МSK3 більш схожеM SK4 Фактична математика - це дотиковий продукт, поділений двома нормами; один метод під назвоюMSC6
  • Приблизний найближчий сусід (ANNM SK1МSK0 " беручи до уваги цей вектор МSK2 знаходити найближче N з мільйонів , швидкіше M SK4 Brute - порівнює силу OMSC6NM SK7 за запитом MSC8 алгоритми АNN отримують результат на менше ніж МСК9 мілісекунд за рахунок того, що іноді не вистачає правда найближчий матч.
  • HNSW: один із тих алгоритмів ANN . Він створює шаровий графік, де верхній шар має декілька зразків МSK2 з 'єднані вузли та нижні шари заповнюють деталями M SK3 Ви вводите вгору і збільшуєте зображення MSC4 Чудово для індексування великого , стабільний набір векторів. Не розроблений для M SK1 кожна просьба додає один, а старі зникають " МSK3 відповідний момент цілого поста
  • Центроїди: середній показник групи векторів - один вектор, який підсумовує кластер МSK2 Якщо у вас є МSK3 вектори, які всі виглядають майже однаково \ , ви можете відкинути їх і залишити один центроід \ МSK5 центроид є поганим, але компактним замінником . \ Сокремлення використовують це, щоб перетворити велику кількість сирої історії на маленьку історію підсумку \

Для StyloBot, ріст LOH спричинив три класи, які були структурно ідентичними : в процесіM SK2 HNSW (Hierarchічний навігаційний маленький світM SK1 графи МSK2оригінальний Мальков & Яшунин), що використовується для пошуку схожості над підписом

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

Кожна з них була нагоджена вчителем, який підписувався LearningEventType.FullDetection,, що реагує на кожен HTTP запит. Кожна просьба додала вектору . Кожня просьма МSK2 Ніхто не виїхав

І кожні п 'ять хвилин - МСК0 - автоматичний таймер відтворює весь графік на JSON і записує його на диск - МSK1

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

На рівні демонстрації, signatures.vectors.json був 104 MBM SK1 В produkcji: intent.meta.json на 70 MBM SK1 intent.vectors.json на 51 MBM SK1 Серіалізація JSON створює континуальну струну в пам 'яті на ♫ 100+ ♫ MB ♫ МSK3 ♫ Ця струна йде прямо до LOH ♫. ♫ Три індекси ♫МSK5 ♫ кожні п' ять хвилин ♫

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

Тепер : легким рішенням є додавати капулу . MaxVectors = 10_000, Виселення з ЛРУ МSK1 корабель це . Це було б спрацювало МСК3 Номери були б нижче MСК4 панель обкладинки виглядала б непогано М СК5 Це також було б неправильним M СК6

HNSW - це чудова технологія, і я використовую її навмисно в інших місцях.Self-Схований векторні бази з Qdrant, Гібридні пошуки та індексування RAG, Найменше життєздатний граф РАГ). Pinecone, Вов 'язати, pgvector, і Кдрант всі користуються нею всередині. МСК0, але це - индекс корпусу. МSK2, а не кэш. ,, і те, чого насправді потребував StyloBot - кэш " для кожного активного відбитка пальців , тримайте маленьке вікно недавніх векторів поведінки, щоб детекція могла порівняти теперішній запит з минулим наслідком схожих Ті ж самі відбитки пальців Bot повторюються. (тримати гаряче ); людські відбити пальця не мають Так просто, як це можливо пост, який вміщував в ” - ” процес Індекс HNSW як функцію “ ; ” цей пост є наступним ” МSK2 ”, визнаючи, де це неправильне ”

МSK0 - це швидкий тест на запах. МSK1 - якщо уявити, що ви кладете тверду кришку на конструкцію. , - це результат, який, семантично, є тим, що вам хотілося.

Правило: коли ви бачите безмежний ріст, " Яким чином ми покриємо цю структуру ?" але "" МСК0 - це правильна структура для того, що ми робимо "". Перший приховує симптоми. Другий слухає, що він вам говорить.

Шаг 4: Виберіть правильну форму , не просто шапку

Як тільки ви написали неправильну абстракцію, ,, замінник зазвичай пише сам себе. Для StyloBot це були два шари.

Горячий шар: а обмежена BoundedVectorCache<TEntry>, тонкий рюкзак навколо ConcurrentDictionary з доступом- виведення частоти priorytetуM SK1 Шордер затримки дає Botу - класифікованим записам MSC3x вагу виживання , так що self-キャッシュ МSK5 організовується навколо шаблону руху M SK6

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

Утримований шар (FOSS): три нові таблиці SQLite (signature_centroids, session_centroids, intent_centroids) зберігання стислених центродів з нічного VectorCompactionService. Вектори зберігаються як сирові плавники МSK1 бульбашки, використовуючи MemoryMarshal.AsBytes:

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

Компактна бінарна сеrialізація. Ні 100+ МБ струни JSONM SK2 Ні LOH.

Запис на рівні зберігання. SQLite - це FOSS / один - бінарний заголовок МSK2 правильний дзвінок для МSK3 кидати exe на Pi і йти геть \ ." Коммерційний StyloBot використовує PostgreSQL з pgvector, дасть вам правильний індексований пошук схожості всередині бази даних - на стабільному корпусі , там, де належить HNSW МSK2 горизонтальна скала M SK3 і спільний стан по всьому флоту sqlite-vss є кроком вперед, якщо ви переростаєте SQLite, але хочете залишатися одним.

Поиск схожості на первісному шарі FOSS - brute-force cosine over all rows, accelerated with SIMD M SK2System.Numerics.Tensors.TensorPrimitives). На стисненому МSK1центрoidному масштабі МSK2 з сотнями до декількох тисяч рядків ), повний скан займає \ ~1-2 \ ms на Пі \ МSK5 , що ' \ є хорошим \ : \ , це працює лише в фонових обладначів

Запис на L1/LM SK1 компактація, з того часу, як МSK1комплікація МSK2 робить реальну роботу в цій секції . Комплікаційна служба працює щоночі і зменшує історію в два проходи

  • L1: візьмемо всі ті сирові вектори, що написали сьогодні , група тих, які дуже подібні МSK2 і замінимо кожну групу одним центроідом. МSK3 середній МСК4 дешевий MСК5 часто трапляється М СК6 скромне зниження розміру M СК7 e М סК8 g М S К9 М הסК10x М Ш К11
  • L2: візьмемо LM SK1 центроїди, які самі по собі схожі на ці дні /тижневі, і знову об 'єднаємо їх MSC3 агресивні ; стають менш рідкісними МSK5 скорочення розміру M SK6 інші

Це одна і та сама модель LSM-Tree Storage Engines M SK1RocksDB, LevelDB , CassandraMSC4 Use for SSTablesMska5 level Мska6 holds recent fineMSKA7grained dataM Ska8 lower levels hold compactedMска9 summarised data Mska10 borrowing it works because the access pattern is the sameMске11 most reads hit recent dataМSK12 a small fraction of readings need the long tailMske13 nothing benefits from keeping every raw row foreverMsek14

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

Ogólnа форма (закритий гарячий кэш для стабільного стану + компактний постійний склад для історії + періодичний компактор між ними) з 'являється знову і знову в довгих - функціональних системах навчання МSK2 Це МSK3 варте того, щоб ви зберігали його у вашому наборі інструментів M SK4 Коли хтось звертається до HNSW або pgvector для навантаження на роботу, що – МSK5 – це насправді кэш , це дешевша MSC7 простіша річ, яку він мав би досягнути замість цього MST8

Правило: віддають перевагу найпростішій структурі даних, яка підходить модель часу бігу, не той, що підходить до набору даних ' розмір на папері

Шаг 5: Робіть швидкий шлях толерантним до пропущень

Чудовий: МСК0 , тому що "'" має на меті стриманість, а не додавання .

Якщо повільний-фіксний шлях включає в себе пошук бази даних ,, то є спокуса зробити його блоком швидкого шляхуMSC2 DonM SK3t. Швидкий шлях виявлення у StyloBot синхроннийМSK5 і перевірка подібності не є пошуком словника, що блокує МSK6

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

Помилка означає не схожість сигнал цього запиту. інші детектори все ще запускаються . Працівник, що керує базами даних, запитує SQLite після закінчення запиту і нагріває кэш на наступний раз

Це те місце, де більшість Caching іде не так. : люди будують Cache , роблять зворотній спір синхронний МSK2 для правильності M SK3 і шлях пропущення стає МSK4 ms p мSK5 піком \ . Cache мав на меті зробити речі швидшими \ МSK7 замість цього він робив найгірший випадок гіршим .

Правило: якщо ви можете' не терпіти пропущення , ви не маєте

Шаг 6: Аудит кожного дня акумулятор, не тільки гучний

Як тільки ви знаходите одну безмежну структуру, уявіть, що є інші.

Аудит є механічним. що визначає його розмір - МСК0, хто вирішує, колиဝင်ки залишаться - МSK1, а що - ' - найгірший випадок під ворожим рухом? Якщо ви не можете відповісти на всі три запитання в одному реченні, Ефемеральні сигнали модель: будь-що, що накопичується, має зруйнуватися

Для StyloBot, більшість акумуляторів вже були добрими

  • EphemeralPatternReputationCache: жорстка капелька на МSK1 записах з розпадом фону і виведенням LRU МSK2механіка розпаду , NeutralSuspectConfirmedBad станова машина, і асимметрична істеріза живуть в Навчитися швидше)
  • BehavioralPatternAnalyzer: IMemoryCache з перM SK1limiдами ідентичності
  • DriftDetectionHandlerМSK0 10,000 зразки
  • SessionEscalationServiceМСК0 35- Minuтний ТТЛ з таймеромМSK2виведення за кермом

Потрібно було звернути увагу на інші класи HNSW: MarkovTracker._cohortBaselines. Марковський ланцюг відслідковувач зберігає базові матриці переходу в коhorті per-, separate from per -signature chainsM SK3 which already had LRU eviction at MaxTrackedSignatures). Початкові показники коhorти МSK1 один на коhorту руху, як МSK2 дата-центр - новий МиSK4 або миSK5 житловий МіSK6 повернення МСК7 взагалі не було виселення СМСК8 фиксація ЯМСК9 виселити найхолодніший коhorт ІМСК10 найменший об 'єм переходів УМСК11 коли словник перевершує SelfMaintenanceOptions.MarkovCohortSize.

Правило: Кожна колекція на один тон відповідає на три запитання, або: МСК0 - це баг , : - це те, що його об 'єднує ,

Шаг 7: Робіть кожен прив 'язок конфігурованим

Наступний режим непрацездатності після "без прив 'язкуM SK1 - "зав' язаний, що МSK3 неправильний для цієї аппаратурії MaxEntries = 10_000 все гаразд, доки хтось не запустить вашу службу на Пі4, або в контейнері з M SK1 MB.

Для StyloBot, кожне обмеження приземлилося під одним SelfMaintenanceOptions заблокувати appsettings.json. Погані варіанти працюють для стандартного сервера . Для обмеженого обладнання там LowMemory Статичний пресет:

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;
});

Або через appsettings.json для середовища-спеціальне налаштуванняM SK1

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

Глубоша точка – МСК0 – це межа, яка встановлена в одному місці, і її оператори можуть пояснити. const int заяви - це те, про що ніхто не може подумати.

Правило: кожен кордон оператора міг би хотіти змінити для свого обладнання життя в одному блокі конфігурації, не розсіяний через кодову базуM SK1

Як виглядає "fixed"

Для StyloBot особливо (FOSS build, LowMemory presetM SK2

Komponenт МSK1 Перед МSK2 Після
Індекс HNSW для підпису МSK1 Необмежений LOH МSK2 ~256 КБ гарячий кэш мSK4
Індекс сеансу HNSW МSK1 Необмежений LOH МSK2 ~258 КБ гарячий кэш M
Індекс інтенції HNSW
Бюфери автозаощадження JSON
Марковські базові лінії Коhorти МSK1 Необмежений МSK2 ~1 MB
Вкупний векторний шар МSK1 13+ ГБЛО <6 MB

Модель виявлення незмінна. Що змінилося? де існують докази схожості і коли ' дозволяє впливати на швидкий шлях. Centroids survive restarts in SQLite (FOSS) or PostgresM SK3pgvector

На Пі4 з пресетом LowMemoryM SK1 будування FOSS сидить під 500 МБ RSS після нагрівання , неодмінно M SK4 платна постгресса МSK5 закріплені депозиції успадковуються так само гаряче MSC6 касетна дисципліна ; постійний шар просто масштабується горизонтально, замість того, щоб жити поруч з процесом

Об 'єктивний урок

Доdanie капсуни обмежує пам 'ять, не змінюючи архітектуру. МСК0. Неправильна абстракція залишається неправильним. МSK1. Симптом просто затихає. .. Наступна людина, яка торкається системи, успадкує структуру, яка майже працює. ММК3. Вона гірша за ту, що очевидно не працює.

Модель, яка повторюється у довготривалих системах навчання

  • Закрити гарячий шлях: замкнутийM SK1 в- пам 'ятіMSC3 здатний терпіти пропущені пропущення , політика виведення з ладу з навантаженням
  • Стиснути історію: компактний бінарний постійний склад , періодично сконцентрований МSK2 доступний за межами потоку запиту
  • Аудитувати все іншеevery accumulator answers what bounds it , What evicts it МSK2 What is the worst case
  • Центрізувати кнопки: один блок конфігурації , не п 'ятнадцять consts
  • Заплануйте перегляд: баг існує лише в запущеній системі

Управляйте формою, не симптомомM SK1


Дальне читання

Серія випуску StyloBot

HNSW і векторний пошук у цьому блогі

Внешні показники

Источник implementу: github.comM SK1scottgal/stylobot. Живий двигун , панель управления МSK2 та коммерціальні прилади stylobot.net.

Finding related posts...
logo

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