From a0ed986ce77bee2fc961d1f91a444bfbd0795e81 Mon Sep 17 00:00:00 2001 From: lachtan Date: Mon, 14 Sep 2026 07:29:02 +0200 Subject: [PATCH] nanobot: 2026-09-14 07:29:02 --- .../2026-09-13_ollama-nvidia-full-report.md | 498 ++++++++++++++++++ projects/devops/memory.md | 18 + projects/devops/state.md | 4 +- 3 files changed, 518 insertions(+), 2 deletions(-) create mode 100644 projects/devops/artifacts/2026-09-13_ollama-nvidia-full-report.md diff --git a/projects/devops/artifacts/2026-09-13_ollama-nvidia-full-report.md b/projects/devops/artifacts/2026-09-13_ollama-nvidia-full-report.md new file mode 100644 index 0000000..63dc1a3 --- /dev/null +++ b/projects/devops/artifacts/2026-09-13_ollama-nvidia-full-report.md @@ -0,0 +1,498 @@ +# Ollama na nvidia.hell — ucelený report + +**Stav k:** 2026-09-13 21:30 (poslední ověřený záznam) +**Pro:** agenta, který na problému bude pokračovat +**Zdroje:** `history.md` (záznamy 2026-09-12 21:10 až 2026-09-13 21:30), +`knowledge.md`, `todo.md`, `done.md`, `explore/negativni-zjisteni.md` + +--- + +## 1. Shrnutí v pěti větách + +Ollama na `nvidia.hell` opakovaně shodila celý stroj (load 81 na 4 jádrech, +SSH neprošlo ani banner exchange, 45 minut nedostupnosti). Příčina není jeden +bug, ale **řetěz tří nezávislých mechanismů**: (1) ollama vypíná `mmap` podle +vzorce, který na tomhle stroji **nemůže být nikdy splněn**, takže model teče +do anonymní paměti místo zahoditelné page cache; (2) architektura PLE u +`gemma4` drží 5,9 GiB vah v RAM hostitele bez ohledu na volnou VRAM; +(3) každé přerušení loadu (kill i vlastní timeout scheduleru) **natrvalo +leakne napinovanou host paměť** v nvidia driveru — uvolní ji jen reboot. +Nasazená pojistka je cgroup strop na `ollama.service`; ověřeně drží dostupnost +stroje (240/240 heartbeatů), ale **retest v konečné podobě ještě neproběhl**. + +--- + +## 2. Prostředí + +| Položka | Hodnota | +|---|---| +| Stroj | `nvidia.hell` — VM pod Proxmox (`pve.hell`, 192.168.4.47) | +| RAM | původně 11,4 GiB, uživatel **snížil na 9,5 GiB** (viz §5.3) | +| Swap | 32 GB, `vm.swappiness=60` | +| CPU | 4 jádra | +| GPU | NVIDIA RTX 4060 Ti 16 GB (16380 MiB) | +| Ollama | 0.33.2 nativně (ne v kontejneru), unit `/etc/systemd/system/ollama.service` | +| Nejnovější upstream | v0.34.0 (5. 9. 2026) — release notes neřeší scheduler ani mmap | +| Frontendy | OpenWebUI (podman, `:8080`), LibreChat (192.168.4.45), **nanobot.hell (192.168.4.64)** | +| Další služby | `traefik`, `jupyterhub`, `docker`, `nvidia-persistenced`, `zabbix-agent` | + +**Klienti jsou důležití:** `nanobot.hell` je skutečný zdroj zátěže — posílá +dávky desítek `POST /api/chat` a `/v1/chat/completions` přes ~10 různých modelů +během minut a drží `qwen3-embedding:0.6b` periodickými `POST /api/embed`. +LibreChat byl v obou incidentech jen **zesilovač** (po 15min timeoutu load +okamžitě zopakoval). + +--- + +## 3. Kauzální řetěz — jak se stroj položí + +``` +nanobot.hell pošle dávku requestů přes ~10 modelů + │ + ▼ +[1] ollama rozhoduje "fits alongside existing models" podle VRAM, + ne podle volné RAM → pustí další model i při system_free = 115 MiB + │ + ▼ +[2] týmž dechem "disabling mmap due to host memory pressure" + (podmínka nemůže být na 9,5GiB stroji nikdy nesplněna) + → model jde do ANONYMNÍ paměti místo page cache + │ + ▼ +[3] u gemma4 navíc PLE drží 5901 MiB vah v host bufferu + (do VRAM jde jen 2966 MiB z 16076 volných) + │ + ▼ +[4] RAM dojde → swap thrashing (pswpin 4512/s), %system 90 %, load 81 + → stroj nedostupný, SSH neprojde + │ + ▼ +[5] load je přerušen (kill zvenčí NEBO vlastní timeout scheduleru) + → llama-server umírá uprostřed CUDA init + → napinovaná host paměť se NEUVOLNÍ → trvalý leak + │ + └──► leak ubere RAM → další load se vejde ještě hůř → smyčka +``` + +**Klíčové:** body [1] a [2] jdou proti sobě — jedno rozhodnutí říká „vejde se", +druhé v téže vteřině říká „je málo paměti". Bod [5] je ta část, která z jednoho +incidentu udělá degradaci trvající do rebootu. + +--- + +## 4. Ověřená fakta (co platí a čím je to doloženo) + +### 4.1 Vypínání mmapu + +`sched.go`, `disableMmapForHostPressure`: + +``` +FreeMemory < modelSize + max(8 GB, TotalMemory/10) → vypni mmap +``` + +Headroom je **konstanta 7,45 GiB** až do 80 GB RAM. Pro `gemma4` +(`model_size="8.9 GiB"`) je potřeba **16,4 GiB volné RAM**. Stroj má 9,5 GiB +celkem → podmínka je splněná **nepodmíněně, bez ohledu na klienta i na to, +kolik je zrovna volno**. + +Důkaz z journalu — tři loady při zcela různé volné paměti, všechny tři +`disabling mmap ... headroom="7.5 GiB"`: + +| čas | `system_free` | +|---|---| +| 12:09:20 | 8,4 GiB | +| 12:44:50 | 3,4 GiB | +| 13:00:03 | 115,1 MiB | + +**Kontraintuitivní důsledek:** čím prázdnější je karta, tím spíš se mmap vypne — +při těsné VRAM zůstává zapnutý (`sched.go` ř. 1235). + +### 4.2 gemma4 / PLE + +`gemma4:e4b` (8,95 GiB, `gemma4:latest` je alias téhož blobu) hlásí +`offloaded 43/43 layers to GPU`, ale reálně: + +``` +| - CUDA0 (RTX 4060 Ti) | 16076 = 15951 + (2966 = 2829 + 29 + 107) + -2842 | +| - Host | 5938 = 5901 + 0 + 37 | +``` + +Per-Layer Embeddings drží embeddingy na CPU **záměrně** +([HuggingFace blog](https://huggingface.co/blog/gemma3n): „PLE reduces +accelerator memory usage by offloading embeddings to the CPU"). Ollama si +ten CPU buffer započítá do předpovědi `predicted="9.4 GiB"`, jako by šel celý +do VRAM. Na 9,5GiB stroji je 5,9 GiB host bufferu neufinancovatelné — +**gemma4 se sem nevejde a nikdy nevejde**, ať je karta jakkoli prázdná. + +### 4.3 Leak napinované paměti (nejzávažnější zjištění) + +Každé přerušení loadu llama-serveru uprostřed CUDA inicializace natrvalo ztratí +host paměť napinovanou přes GUP (get_user_pages). + +**Nezáleží na tom, kdo proces ukončil.** Doloženo pro obě varianty: +- externí `SIGTERM` od earlyoomu (~15 killů = 9,27 GiB), +- zrušení samotným ollama schedulerem (`Load failed: timed out waiting for + llama-server to start: context canceled` po odpadnutí klienta) = **5,19 GiB + z jednoho zrušení**. + +**Diagnostika** (jediné, co leak ukáže): +```bash +# počet napinovaných stránek +awk '/nr_foll_pin_acquired/{a=$2} /nr_foll_pin_released/{r=$2} END{print a-r, "stránek =", (a-r)*4096/1073741824, "GiB"}' /proc/vmstat + +# druhý příznak: Active(anon)+Inactive(anon) >> AnonPages +grep -E 'AnonPages|Active\(anon\)|Inactive\(anon\)|MemAvailable' /proc/meminfo +``` + +**Co leak NEUKÁŽE:** `ps -eo rss` (~250 MB přes všechny procesy), +`nvidia-smi` (2 MiB / 16380 MiB, „No running processes found"), +`systemd-cgtop` (žádná služba nic nedrží), `sar` (nemá pro to sloupec — +proto ve vzorcích z 13:40 nesedělo 9,4 GB do žádné kategorie). + +**Co leak neuvolní:** +- `systemctl restart ollama` — `foll_pin` delta identická, navíc paměť + **uteče z cgroup do rodiče** (`memory.current` ollamy spadne na 18 MB, + `system.slice` si 5,9 GiB nese dál) → kontejnerování platí jen do prvního restartu. +- `rmmod nvidia_uvm nvidia_drm nvidia_modeset nvidia` — proběhl čistě + (`lsmod` prázdný), delta **bit za bit stejná** (2 307 318 stránek). + Ověřeno 2026-09-13 20:20. Tím padl dřívější předpoklad, že teardown pomůže. + +**Co leak uvolní:** **jen reboot.** Ověřeno 2026-09-13 20:26 — +`MemAvailable` 89 MB → 7,6 GiB, `Inactive(anon)` 5,9 GiB → 0. + +Poznámka: nenulová `foll_pin` delta při běžícím modelu je normál +(po rebootu 252 949 stránek = 0,96 GiB pro načtený `qwen3-embedding:0.6b`). +Leak se pozná podle toho, že delta zůstane, když neběží žádný llama-server. + +### 4.4 Cgroup pojistka — co funguje + +Nasazeno v `/etc/systemd/system/ollama.service.d/override.conf` +(záloha `override.conf.bak-20260913`): + +```ini +MemoryMax=6G +MemorySwapMax=0 # nejdůležitější řádek +CPUQuota=200% +CPUWeight=20 +# MemoryHigh záměrně NENASTAVENO — viz §5.1 +``` + +Plus `/etc/systemd/system/ssh.service.d/10-oom-protect.conf`: +`OOMScoreAdjust=-900`, `MemoryMin=32M` (ověřeno, že `ssh.socket` má +`Accept=no`, takže listener žije v `ssh.service`). + +**Zátěžový test 2026-09-13 16:55–17:05** (heartbeat à 2 s, každý úder nové SSH +spojení; spouštěč `curl /api/generate` na `gemma4:latest`): + +| Kritérium | Výsledek | +|---|---| +| Dostupnost SSH | **240/240 úderů, 0 výpadků** | +| `MemAvailable` minimum | 3204 MiB (kritérium bylo 2 GiB) | +| `loadavg` max | **3,41** (při incidentu 81) | +| OOM killer v `dmesg` | žádný | + +`MemorySwapMax=0` je z toho nejdůležitější — **nedostupnost dělal swap thrash, +ne OOM**. `MemoryMax=` sám o sobě mapuje na `memory.max`, což je strop jen pro +RAM; po jeho dosažení kernel proces nezabije, ale začne ho swapovat. + +### 4.5 Rozlišení, proč ollama spadla + +```bash +dmesg | grep -i 'oom\|constraint' +``` +- `constraint=CONSTRAINT_NONE ... global_oom` → **globální OOM killer**, + pojistka nezasáhla (stroj byl sežraný leakem, ollama se ke svému 6G stropu + vůbec nedostala) +- `constraint=CONSTRAINT_MEMCG` → **cgroup limit**, pojistka zafungovala + +Smyčku `Start request repeated too quickly` dělá `Restart=always` + +`RestartSec=30` + `StartLimitBurst=3/300s` z drop-inu — **to je záměr**, ne chyba. + +--- + +## 5. Slepé uličky — co nezkoušet znovu + +### 5.1 `MemoryHigh` je past + +Nastaveno `MemoryHigh=5G` + `MemoryMax=6G`. gemma4 potřebuje host buffer +5901 MiB → padlo **přesně doprostřed pásma**: + +``` +memory.events: high 84358 max 0 oom 0 oom_kill 0 +memory.peak: 5,46 GiB +``` + +Cgroup 84 tisíckrát reclaimovala, proces se plazil, tvrdý strop nezasáhl ani +jednou a load **visel 600 s bez jediné chybové odpovědi** — ani neselhal, +ani neproběhl. Pro chování „rychle selhat" se `MemoryHigh` **nesmí nastavit**. +Odstraněno. + +### 5.2 earlyoom — zavržen, odinstalován + +Nasazen 14:20, do večera pryč. Tři samostatné problémy: + +1. **Ve výchozí konfiguraci by nezasáhl nikdy.** Podmínky `-m` a `-s` platí + **současně**. Ze swapu bylo obsazeno 1,4 z 32 GB (~95 % volných), takže + `swap <= 10 %` nemohlo nastat. Man page: „You can use `-s 100` to have + earlyoom effectively ignore swap usage." +2. **SIGKILL práh je polovina zadané.** `-s 100` dá kill až při `swap <= 50 %` + → nutné psát `-s 100,100`. +3. **Je to zesilovač, ne pojistka.** Killy llama-serveru uprostřed CUDA init + leakují (§4.3). Po ~15 killech chybělo 9,27 GiB, práh `-m 10` se trvale + posunul pod klidovou spotřebu a ollama už nenačetla vůbec nic — každý nový + llama-server umíral už při 300 MiB RSS. **Kladná zpětná vazba.** + +**Poučení: proti procesu, který drží GPU kontext, je externí zabíječ horší než +nic.** Totéž se dá čekat od `systemd-oomd` (PSI varianta téhož principu) — +nenasazováno, odvozeno, neověřeno měřením. Balík earlyoom je ve stavu `rc`, +zbývá `apt purge`. + +### 5.3 Navýšení RAM neřeší nic + +Headroom je konstanta 7,45 GiB do 80 GB RAM → pro gemma4 by mmap zůstal zapnutý +až u ~20GiB VM. Uživatel proto paměť naopak **ubral** z 11,4 na 9,5 GiB. + +### 5.4 Konfigurace ollamy nemá páku + +- **`OLLAMA_NO_MMAP` neexistuje.** [Issue #4895](https://github.com/ollama/ollama/issues/4895), + [PR #6854](https://github.com/ollama/ollama/pull/6854) nikdy nesloučen + („upstream changes broke this patch"). V `ollama serve --help` volba pro mmap + není. Jediné, co existuje, je `PARAMETER use_mmap` v Modelfile — a **není + doloženo**, že `true` přebije automatické vypnutí kvůli host memory pressure. +- **Ollama nemá admission control.** Ověřeno z `--help` (v0.33.2): neexistuje + proměnná „odmítni load, když se nevejde do VRAM". K dispozici je jen + `OLLAMA_MAX_LOADED_MODELS`, `OLLAMA_MAX_QUEUE`, `OLLAMA_NUM_PARALLEL`, + `OLLAMA_GPU_OVERHEAD`, `OLLAMA_CONTEXT_LENGTH`, `LLAMA_ARG_FIT_TARGET`, + `OLLAMA_LOAD_TIMEOUT`. Ollama je navržená tak, že do CPU přeteče vždycky. +- **Omezování počtu modelů završeno.** `OLLAMA_MAX_LOADED_MODELS=1` + + `NUM_PARALLEL=1` + `MAX_QUEUE=8` byly v plánu a uživatel je vyhodil oprávněně: + stroj shodila **hostitelská RAM, ne VRAM** (karta má 16 GB volných) a 49 + requestů z nanobotu nepoložilo stroj frontou, ale **sekvencí loadů**, na což + `MAX_QUEUE` nesahá. +- **Zvedat `OLLAMA_LOAD_TIMEOUT` zavrženo** (online se doporučuje jako „turns + a hard failure into a slow success") — u nás by jen prodloužilo thrashing + z 5 na 15 minut. +- **Upgrade ollamy neřeší nic** — v0.34.0 release notes: ChatGPT Desktop, + structured output na Apple Silicon, OpenAI tool search. Nic o scheduleru + ani mmapu. + +### 5.5 Proxmox ballooning je pro LLM stroje nevhodný + +`pvestatd` (`auto_ballooning`) počítá cíl z **volné paměti hostitele**, ne +z tlaku v guestu — ten určuje jen prioritu ve frontě. `maxchange` je 100 MB +na cyklus à 10 s (~10 MB/s): navýšení o 8 GB trvá ~14 minut, zatímco načtení +modelu 17 s. Během incidentu zůstalo `total` na 7,4 GiB, přestože guest padl +na 136 MB volných. **Řešení: `balloon: 0` a pevná paměť.** + +--- + +## 6. Chybné závěry, které byly cestou opraveny + +| Původní závěr | Oprava | +|---|---| +| „Viníkem je LibreChat" | Uživatel reprodukoval zatuhnutí i z `ollama` CLI. LibreChat byl jen zesilovač; spouštěčem je samotný model. | +| „Embedding drží LibreChat" | Drží ho **nanobot.hell (192.168.4.64)**, ne LibreChat (192.168.4.45). | +| „Regresi 0.32.10 způsobil Vulkan" | [Rozbor na dev.to](https://dev.to/milkyway008/ollama-model-loads-time-out-after-the-03210-upgrade-the-load-mode-change-and-the-fix-25m) ji připisuje Vulkanu na iGPU — na nás nesedí (CUDA, diskrétní karta). Náš log uvádí jiný spouštěč (`host memory pressure`), ale ústí do téhož `--load-mode none`. Potvrzuje #18373. | +| „Leakuje jen externí kill" | Leakuje i zrušení vlastním schedulerem — jedno stálo 5,19 GiB. | +| „Leak uvolní teardown nvidia driveru" | `rmmod` neuvolnil ani stránku. **Jen reboot.** | +| „`failed (Result: oom-kill)` = zafungoval cgroup strop" | `constraint=CONSTRAINT_NONE` → globální OOM. Pojistka nezasáhla. | +| „~9,4 GB v `sar` nesedí do žádné kategorie" | Byla to právě ta napinovaná paměť; `sar` pro ni nemá sloupec. | + +--- + +## 7. Upstream — nahlášené a neopravené + +| Issue | Co říká | Stav | +|---|---|---| +| [#18373](https://github.com/ollama/ollama/issues/18373) | Regrese načítání: 0.33.3 load 2m34s vs. 0.23.4 28s, SSD 600 MB/s místo 3 GB/s. Explicitně „all models", hlášeno i na NVIDII. | otevřené, bez reakce maintainerů | +| [#10104](https://github.com/ollama/ollama/issues/10104) | 200 GB RAM, 80 GB VRAM, ollama sama nasadí `--no-mmap` a load selže. | zavřené bez řešení | +| [#10341](https://github.com/ollama/ollama/issues/10341) | gemma plní RAM navzdory volné VRAM, **na RTX 4060 Ti 16 GB** — stejná karta. | duplikát #10040 | +| [#8654](https://github.com/ollama/ollama/issues/8654) | „Available memory check should be disabled when mmap is in use" | otevřené od 1/2025 | +| [#4895](https://github.com/ollama/ollama/issues/4895) + [PR #6854](https://github.com/ollama/ollama/pull/6854) | Žádost o globální řízení mmapu. | PR nesloučen | + +První výskyt `disabling mmap` v journalu nvidia.hell je **2026-06-05** — +předtím ani jednou za 13 měsíců. Jde tedy o regresi, ne o vlastnost od začátku. + +--- + +## 8. Chyby v systemd konfiguraci (obecně použitelné) + +- **`StartLimitIntervalSec` / `StartLimitBurst` patří do `[Unit]`, ne `[Service]`** — + tam se tiše ignorují. `RestartSec` naopak do `[Service]`. Property se navíc + jmenuje `RestartUSec` → `systemctl show -p RestartSec` nevrátí nic. +- **`MemoryMax` sám nelimituje swap** → nutné `MemorySwapMax` (§4.4). +- **Instalátor ollamy přepisuje unit soubor.** `install.sh` (ř. 215) + bezpodmínečně přepíše `/etc/systemd/system/ollama.service` přes `tee`, + do `ollama.service.d/` nesahá → vlastní nastavení patří do drop-inu. + *Zavrženo:* držet kopii unitu a po upgradu ji kopírovat zpět — konzervuje + i upstream řádky (`ExecStart`, `User`, `PATH`). +- **⚠ Limity z 12. 9. ze stroje nevysvětleně zmizely.** Zapsány ve 21:10, + ve 21:44 už v `override.conf` nebyly (zůstaly jen `StartLimit*`, `RestartSec`, + `Environment`). Při incidentu 13. 9. proto `systemctl show ollama` hlásil + `MemoryMax=infinity`. **Příčina nikdy nezjištěna.** Proto existuje záloha + `override.conf.bak-20260913` a **kontrola limitů musí být součástí každého ověření**. +- **Překlep v drop-inu:** zakomentovaný řádek `Environment="LLAMA_MAX_LOADED_MODELS=1"` + — správně `OLLAMA_MAX_LOADED_MODELS`, nefungoval by ani po odkomentování. + +--- + +## 9. Ostatní zjištění k ollamě / modelům + +### `OLLAMA_KV_CACHE_TYPE=q4_0` rozbíjí modely s head_dim nedělitelným 32 + +`granite-code` (`n_embd_head_k=80`) padá na +`K cache type q4_0 with block size 32 does not divide n_embd_head_k=80`. +12. 9. kvůli tomu spadl **6× po sobě** (12:08:36–12:09:04) a každý pokus přitom +nastartoval llama-server a načetl 1,9 GiB s vypnutým mmapem. Proměnná je +**globální** — nastavit jde jen pro všechny modely naráz. +**Stále nastaveno, neopraveno.** + +### Capability `tools` neznamená, že model nástroje použije + +Za 13. 9. odešly jen 3 `tools/call`: `gemma4:e4b` (2×) a `glm-5.3:cloud` (1×). +`mistral:latest` dostal ve stejné relaci **stejných 5 nástrojů** jako glm-5.3 +a nezavolal ani jeden (job skončil za 4 s textovou odpovědí), přestože +v `ollama show` **má** capability `tools`. Flag říká jen to, že šablona +nástroje podporuje. + +Modely **bez** `tools` (nikdy nebudou fungovat): `llama3`, `llama2-uncensored`, +`tinyllama`, `aya`, `phi4`, `phi3.5`, `codellama`, `exaone-deep`, +`deepseek-coder-v2`, `granite-code:8b`. + +### `sar` přežije reboot a chybějící vzorek je sám o sobě důkaz + +`/var/log/sysstat/saDD` + perzistentní journal umožnily dohledat incident až +po restartu VM. Kolektor `sa1` běží à 10 min z `/etc/cron.d/sysstat`; **když +vzorek ve výpisu chybí, stroj byl v tu chvíli tak zahlcený, že cron nedoběhl** — +tím se dá datovat začátek incidentu (vzorek 12:50 chyběl). + +--- + +## 10. Aktuální stav (po rebootu 2026-09-13 20:26) + +``` +MemAvailable 7,6 GiB (bylo 89 MB) +MemFree 5,8 GiB +Inactive(anon) 0 (bylo 5,9 GiB) +foll_pin delta 252 949 stránek = 0,96 GiB ← legitimní, drží běžící model +OOM killů od bootu: 0 +``` + +Běží: `ollama`, `nvidia-persistenced`, `traefik`, `jupyterhub`, `docker`, `ssh`. +Cgroup pojistka aktivní a ve správné podobě: `MemoryMax=6G`, `MemorySwapMax=0`, +`MemoryHigh=infinity`, `CPUQuota=200%`, `StartLimitBurst=3/5min`. + +--- + +## 11. Co zbývá udělat + +Seřazeno podle priority: + +1. **Zastavit dávky z nanobot.hell (192.168.4.64)** — bez toho je leak zpátky + během minut. Zatím neuděláno. +2. **Retest cgroup pojistky bez `MemoryHigh`** — potvrdit, že load selže + v řádu sekund přes cgroup OOM (`memory.events` → `oom_kill > 0`) místo + desetiminutového plazení. **Odblokováno** rebootem. Kritéria z minulého testu: + SSH heartbeat à 2 s bez výpadku, `MemAvailable` > 2 GiB, `loadavg` pod kontrolou, + `dmesg` → `constraint=CONSTRAINT_MEMCG` (ne `CONSTRAINT_NONE`). +3. **Doladit `MemoryMax`** podle naměřeného `memory.peak` z retestu. +4. **Rozhodnout osud gemma4** — `gemma4:latest` / `gemma4:12b` / `gemma4:e4b` + potřebují kvůli PLE ~5,9 GiB host bufferu bez ohledu na volnou VRAM. + Na 9,5GiB stroji se nevejdou nikdy. *Otázka pro uživatele: vyřadit je?* + Jediné skutečné „admission control", které ollama nabízí, je nenabízet + nebezpečné modely. +5. **`OLLAMA_KV_CACHE_TYPE=q4_0`** — buď proměnnou zrušit, nebo `granite-code` + nepoužívat. +6. Drobnosti: + - `apt purge earlyoom` (balík ve stavu `rc`, zbyly `/etc/default/earlyoom` + a `/etc/default/earlyoom.bak-20260913`) + - snížit `--log-verbosity 4` u llama-serveru (journald při incidentu žral + 1,9 % CPU, journal zaplevelený) + - opravit `Hostname=Zabbix server` v `/etc/zabbix/zabbix_agentd.conf` + na `nvidia` (agent běží a míří na `zabbix.hell`, ale s defaultním jménem) + - LibreChat: `titleConvo: true` + `titleModel: "current_model"` posílá na týž + model druhý souběžný požadavek (v logu `Title generation timeout`) + - *otázka:* jaký monitoring doinstalovat? `sysstat` na postmortem stačil. + Chybí (a) alerting v reálném čase a (b) hlídač, který zakročí — ale + pozor, „hlídač, který killuje" je právě ta zavržená cesta (§5.2). + +--- + +## 12. Rychlá kuchařka pro triáž + +```bash +# 1) Leakuje pinned paměť? +awk '/nr_foll_pin_acquired/{a=$2} /nr_foll_pin_released/{r=$2} \ + END{print (a-r), "stránek =", (a-r)*4096/1073741824, "GiB"}' /proc/vmstat +grep -E 'MemAvailable|AnonPages|Active\(anon\)|Inactive\(anon\)' /proc/meminfo +# Active+Inactive(anon) >> AnonPages → leak. +# Když neběží žádný llama-server a delta je nenulová → leak. Řešení: REBOOT. + +# 2) Platí vůbec limity? (už jednou zmizely!) +systemctl show ollama -p MemoryMax -p MemorySwapMax -p MemoryHigh -p CPUQuotaPerSecUSec +grep . /sys/fs/cgroup/system.slice/ollama.service/memory.{max,swap.max,high,current,peak} +cat /sys/fs/cgroup/system.slice/ollama.service/memory.events + +# 3) Spadla ollama na cgroup stropu, nebo globálně? +dmesg | grep -iE 'oom|constraint' +# CONSTRAINT_MEMCG → pojistka zafungovala +# CONSTRAINT_NONE / global_oom → stroj byl sežraný leakem, pojistka se nedostala ke slovu + +# 4) Kdo to spustil? +journalctl -u ollama --since -2h | grep -E 'disabling mmap|fits alongside|Load failed|system_free' +journalctl -u ollama --since -2h | grep -oE '192\.168\.4\.[0-9]+' | sort | uniq -c +# 192.168.4.64 = nanobot.hell (skutečný zdroj), 192.168.4.45 = LibreChat (zesilovač) + +# 5) Postmortem po rebootu +sar -r -f /var/log/sysstat/sa$(date +%d) # chybějící vzorek = stroj nestíhal ani cron +sar -q -f /var/log/sysstat/sa$(date +%d) # ldavg +journalctl -b -1 -u ollama +``` + +--- + +## 13. Zálohy a rollback na stroji + +| Co | Kde | +|---|---| +| Unit + skripty před zásahem 12. 9. | `~/backup/ollama-20260912-2108/` | +| Drop-in před cgroup pojistkou | `/etc/systemd/system/ollama.service.d/override.conf.bak-20260913` | +| earlyoom config | `/etc/default/earlyoom.bak-20260913` | +| SSH OOM ochrana (přidáno) | `/etc/systemd/system/ssh.service.d/10-oom-protect.conf` | +| Upgrade skripty | `~/bin/upgrade-ollama.sh`, `~/bin/upgrade-openwebui.sh` | + +```bash +# rollback cgroup pojistky +sudo cp -a /etc/systemd/system/ollama.service.d/override.conf.bak-20260913 \ + /etc/systemd/system/ollama.service.d/override.conf +sudo rm -f /etc/systemd/system/ssh.service.d/10-oom-protect.conf +sudo systemctl daemon-reload && sudo systemctl restart ollama ssh + +# návrat driveru po rmmod (kdyby to někdo zkusil znovu — nemá to smysl) +sudo modprobe nvidia && sudo modprobe nvidia_uvm && sudo modprobe nvidia_modeset +sudo systemctl start nvidia-persistenced +``` + +**Pozn.:** `~/bin/nvidia-reload` na stroji existuje, ale **nemá smysl** — +postaven na předpokladu, že `rmmod` leak uvolní, což bylo vyvráceno (§4.3). + +--- + +## 14. Plné záznamy + +Chronologicky v `history.md`: + +| Záznam | Obsah | +|---|---| +| 2026-09-12 21:10 | Paměťové limity přes systemd drop-in (limity pak záhadně zmizely) | +| 2026-09-13 12:05 | LibreChat: web search bez klíčů + Python přes MCP | +| 2026-09-13 13:40 | Průzkum: nvidia.hell zahlcená na 45 minut (load 81) | +| 2026-09-13 14:00 | Oprava diagnózy: viník není LibreChat, ale práh pro mmap | +| 2026-09-13 14:20 | Rešerše upstreamu + nasazení earlyoom | +| 2026-09-13 15:45 | Ollama nefunkční, 9,3 GiB leaklé pinned paměti | +| 2026-09-13 17:10 | Cgroup pojistka nasazena a otestována, `MemoryHigh` past | +| 2026-09-13 20:20 | `rmmod` nvidia leak NEuvolnil, leak vyrostl na 8,8 GiB | +| 2026-09-13 21:30 | Reboot uvolnil leak, stroj zdravý | + +Další: `knowledge.md` (ověřená fakta), `todo.md` (otevřené body), +`explore/negativni-zjisteni.md` (podrobný soupis negativních zjištění). \ No newline at end of file diff --git a/projects/devops/memory.md b/projects/devops/memory.md index 374a04e..b1cc68d 100644 --- a/projects/devops/memory.md +++ b/projects/devops/memory.md @@ -36,3 +36,21 @@ Shrnutí obsahu: **Drobnosti k opravě (otevřené):** zabbix-agent má defaultní `Hostname=Zabbix server` (má být nvidia); llama-server `--log-verbosity 4` (journald žral 1,9 % CPU, zaplevelený journal); LibreChat titleConvo posílá druhý souběžný požadavek na týž model; earlyoom ve stavu `rc` — zbývá `apt purge` (na disku /etc/default/earlyoom a .bak). Koresponduje s dřívějším zjištěním z projektu ai (2026-09-13): Ollama na nvidia.hell v praxi nepoužitelná, memory watchdog zabíjí llama-server. Tenhle report dodává root cause: kill uprostřed CUDA loadu → leak napinované paměti, kterou neukáží standardní nástroje. +- 2026-09-14: Záznam druhého reportu od Claude Code: „Ollama na nvidia.hell — ucelený report" (stav k 2026-09-13 21:30). Uložen verbatim jako artifact: `projects/devops/artifacts/2026-09-13_ollama-nvidia-full-report.md`. Je to nadstavba předchozího „Negativní zjištění" reportu (uložený den předtím) — obsahuje kauzální řetěz, ověřená fakta, aktuální stav a todo list. + +**Kauzální řetěz (5 kroků):** (1) ollama rozhoduje „fits alongside existing models" podle VRAM, ne volné RAM → pustí model i při system_free 115 MiB; (2) týž dechem vypne mmap (podmínka na 9,5 GiB stroji nesplnitelná nikdy) → model jde do anonymní paměti místo page cache; (3) gemma4 PLE drží 5,9 GiB host bufferu navíc; (4) RAM dojde → swap thrashing (pswpin 4512/s, %system 90 %, load 81, SSH nedostupné 45 min); (5) přerušený load → leak napinované paměti. Body [1] a [2] si odporují v téže vteřině. + +**Nová fakta oproti předchozímu reportu:** +- **correction: rmmod nvidia driveru leak NEUVOLNÍ** — ověřeno 20:20, proběhl čistě, foll_pin delta bit za bit stejná (2 307 318 stránek). Moje předchozí shrnutí říkalo „uvolní ho jen driver teardown nebo reboot" — platí **jen reboot** (ověřeno 20:26: MemAvailable 89 MB → 7,6 GiB). Skript `~/bin/nvidia-reload` na stroji je tedy bezcenný. +- **Cgroup pojistka funguje a je ověřená**: `MemoryMax=6G`, `MemorySwapMax=0` (klíčový řádek — nedostupnost dělal swap thrash, ne OOM; MemoryMax sám swap nelimituje), `CPUQuota=200%`, `CPUWeight=20`, MemoryHigh záměrně vynechán. Plus SSH ochrana (`OOMScoreAdjust=-900`, `MemoryMin=32M` v ssh.service.d/10-oom-protect.conf). Zátěžový test 16:55–17:05 (gemma4 load, SSH heartbeat à 2 s): 240/240 úderů, 0 výpadků, load max 3,41 (vs 81 při incidentu), MemAvailable min 3204 MiB. +- **Diagnostika OOM**: `dmesg` rozlišuje `constraint=CONSTRAINT_MEMCG` (pojistka zafungovala) vs `CONSTRAINT_NONE/global_oom` (stroj sežraný leakem, pojistka se ke slovu nedostala). `failed (Result: oom-kill)` tedy neznamená automaticky zafungovaný strop. +- **První výskyt `disabling mmap` v journalu je 2026-06-05** — předtím 13 měsíců čisto. Jde o regresi, ne stávající vlastnost. +- **`sar` chybějící vzorek = sám o sobě důkaz** (stroj nestíhal ani cron à 10 min) — datování začátku incidentu. +- **Zavržené nově:** zvedání `OLLAMA_LOAD_TIMEOUT` („turns a hard failure into a slow success" — jen by prodloužilo thrashing); Proxmox ballooning → řešení `balloon: 0` + pevná paměť (pvestatd počítá cíl z volné paměti hostitele, ~10 MB/s vs 17 s load modelu). +- **Capability `tools` ≠ model nástroje použije**: mistral:latest dostal stejných 5 nástrojů jako glm-5.3, nezavolal ani jeden; flag říká jen, že šablona podporuje tools. Seznam modelů bez `tools` capability (nikdy nebudou fungovat): llama3, llama2-uncensored, tinyllama, aya, phi4, phi3.5, codellama, exaone-deep, deepseek-coder-v2, granite-code:8b. +- **Prostředí:** VM pod pve.hell (192.168.4.47), RAM snížena 11,4 → 9,5 GiB, swap 32 GB swappiness=60, 4 jádra, RTX 4060 Ti 16 GB, ollama 0.33.2 nativně. Skutečný zdroj zátěže = nanobot.hell (192.168.4.64), LibreChat jen zesilovač. +- **Kuchařka pro triáž** (awk foll_pin delta, kontrola cgroup limitů — už jednou zmizely, constraint grep, journalctl IP grep, sar postmortem) + **zálohy a rollback** (override.conf.bak-20260913, ~/backup/ollama-20260912-2108/, upgrade skripty). + +**Otevřené body (prioritně, z §11):** (1) zastavit dávky z nanobot.hell — bez toho leak zpátky během minut; (2) retest cgroup pojistky bez MemoryHigh (odblokováno rebootem, kritéria: heartbeat bez výpadku, MemAvailable > 2 GiB, constraint=MEMCG); (3) doladit MemoryMax podle memory.peak z retestu; (4) rozhodnout osud gemma4 (PLE ~5,9 GiB host bufferu, na 9,5 GiB stroji nikdy); (5) OLLAMA_KV_CACHE_TYPE=q4_0 zrušit nebo nepoužívat granite-code; (6) drobnosti: apt purge earlyoom, log-verbosity 4, zabbix Hostname, LibreChat titleConvo, otázka monitoringu (hlídač co killuje = zavržená cesta). + +**Stav po rebootu 20:26:** stroj zdravý (MemAvailable 7,6 GiB, 0 OOM killů), pojistka aktivní ve správné podobě. diff --git a/projects/devops/state.md b/projects/devops/state.md index dfcde5f..5d0e9b0 100644 --- a/projects/devops/state.md +++ b/projects/devops/state.md @@ -7,9 +7,9 @@ timestamp: draft ## Kde to je - Projekt založen jako volný prostor pro admin/root poznámky o infrastruktuře a provozu. - LibreChat: běží jako podman kontejnery; jako Code Interpreter sandbox vybrán LibreCodeInterpreter (nsjail, 3 kontejnery). Research hotový (2026-09-13), rozhodnutí o nasazení (sdílená Docker VM vs dedikovaná Proxmox VM) ještě nepadlo. -- Ollama na nvidia.hell: po incidentech 12.–13. 9. 2026 zaevidován root cause pádů — kill llama-serveru uprostřed CUDA loadu způsobí leak napinované host paměti (neviditelný pro ps/nvidia-smi/cgtop, detekce jen přes `nr_foll_pin` delta v /proc/vmstat), uvolní ho jen driver teardown/reboot. Report „Negativní zjištění" uložen v `artifacts/2026-09-13_ollama-nvidia-negative-findings.md`, shrnutí v memory.md 2026-09-14. Zavržené cesty: earlyoom (i jakákoli externí kill varianta), MemoryHigh pod MemoryMax, navýšení RAM (headroom konstanta 7,5 GiB), limit počtu modelů, upgrade ollamy, mmap override (neexistuje). +- Ollama na nvidia.hell: po incidentech 12.–13. 9. 2026 zaevidován root cause pádů — kauzální řetěz: ollama rozhoduje load podle VRAM ne volné RAM + vypíná mmap (podmínka na 9,5 GiB stroji nesplnitelná nikdy, regrese od 2026-06-05) + PLE host buffer u gemma4 + přerušený load leakuje napinovanou host paměť (neviditelná pro ps/nvidia-smi/cgtop, detekce jen `nr_foll_pin` delta v /proc/vmstat), uvolní **jen reboot** (rmmod driveru ověřeně NE). Cgroup pojistka (`MemoryMax=6G`, `MemorySwapMax=0`, bez MemoryHigh) ověřena zátěžovým testem: 240/240 SSH heartbeatů, load 3,41 vs 81 při incidentu. Skutečný zdroj zátěže = nanobot.hell (dávky přes ~10 modelů + embedding), LibreChat jen zesilovač. Reporty v `artifacts/2026-09-13_ollama-nvidia-full-report.md` (ucelený, s kuchařkou pro triáž) a `artifacts/2026-09-13_ollama-nvidia-negative-findings.md` (negativní zjištění), shrnutí v memory.md 2026-09-14. Zavržené cesty: earlyoom i jakákoli externí kill varianta, MemoryHigh pod MemoryMax, navýšení RAM (headroom konstanta 7,5 GiB), limit počtu modelů, OLLAMA_LOAD_TIMEOUT, upgrade ollamy, mmap override (neexistuje), ballooning (`balloon: 0` + pevná paměť), rmmod jako remedy. ## Co dál - Rozhodnout umístění LibreCodeInterpreter (AI stack VM vs dedikovaná VM) a nasadit — viz memory.md 2026-09-13 pro capability požadavky (SYS_ADMIN, NET_ADMIN, apparmor:unconfined). -- Otevřené drobnosti z ollama reportu: `OLLAMA_KV_CACHE_TYPE=q4_0` stále nastaveno a rozbíjí granite-code; zabbix-agent `Hostname=Zabbix server` (má být nvidia); llama-server `--log-verbosity 4` → zaplevelený journal; earlyoom ve stavu `rc` → `apt purge`; LibreChat titleConvo duplicitní souběžné requesty. +- Ollama open body dle priority (report §11): (1) zastavit dávky z nanobot.hell — bez toho leak zpátky během minut; (2) retest cgroup pojistky bez MemoryHigh (odblokováno rebootem; kritéria: heartbeat bez výpadku, MemAvailable > 2 GiB, dmesg constraint=MEMCG); (3) doladit MemoryMax podle memory.peak; (4) rozhodnout osud gemma4 (PLE ~5,9 GiB host bufferu, na 9,5 GiB stroji nikdy); (5) `OLLAMA_KV_CACHE_TYPE=q4_0` zrušit nebo nepoužívat granite-code; (6) drobnosti: `apt purge` earlyoom (rc), llama-server `--log-verbosity 4`, zabbix `Hostname=Zabbix server` → nvidia, LibreChat titleConvo duplicitní requesty, otázka real-time monitoringu (hlídač co killuje = zavržená cesta). - Uživatel bude psát poznámky; podle obsahu doladit strukturu projektu. \ No newline at end of file