diff --git a/lessons/2026-05-07-openclaw-v5.6-upgrade-completed.md b/lessons/2026-05-07-openclaw-v5.6-upgrade-completed.md index 371a635..dc7fb28 100644 --- a/lessons/2026-05-07-openclaw-v5.6-upgrade-completed.md +++ b/lessons/2026-05-07-openclaw-v5.6-upgrade-completed.md @@ -115,30 +115,46 @@ Backups: `*.bak-api-health-fix-20260507-151727` (do sed errado) + `*.bak-revert- **Root cause:** working set real do nox-mem-api é ~1.3-1.5G (chunks 63727 + FTS5 vector index + sqlite-vec embeddings + caches em memória). MemoryHigh=1500M estava **ABAIXO do baseline natural**. Service carregava chunks no startup, batia no throttle imediatamente, ficava degradado pelo restante da vida útil. Restart manual não resolvia — em 6s pós-startup já estava em 1.5G de novo (3204 high events). -**Fix aplicado:** bump systemd drop-in `/etc/systemd/system/nox-mem-api.service.d/limits.conf`: +**Fix aplicado em 2 fases — bump 1 era insuficiente:** + +**Bump 1 (16:51):** `MemoryHigh 1500M→1800M, MemoryMax 2G→2500M`. Backup `limits.conf.bak-pre-bump-20260507-165148`. Resultado pós-bump 5min watch: memory 1.5G estável, high events FROZEN em 4554, latency 1.0-1.2s. Aparentou resolvido. + +**Recorrência (T+1h45min):** canary voltou a alertar `FAIL(2) unreachable:18802` às 18:17. Investigação: +- Service voltou a 100% MemoryHigh (1.8G/1.8G) em uptime 43min +- High events subiu **4554 → 21793** em ~1h (17K novos hits) +- Latency degradou: 3s+ sequencial, 8-13s concurrent (2 reqs paralelas) +- Working set real cresce **com uso** (caches embedding/chunk carregados pelas queries diárias) — não estabiliza em snapshot inicial + +**Bump 2 (18:34):** `MemoryHigh 1800M→2400M, MemoryMax 2500M→3000M`. Backup `limits.conf.bak-pre-bump2-20260507-183456`. Config final: ```ini [Service] -MemoryHigh=1800M # era 1500M -MemoryMax=2500M # era 2G +MemoryHigh=2400M +MemoryMax=3000M TimeoutStopSec=20 StartLimitInterval=60s StartLimitBurst=5 ``` -Sistema host: 16GB total / 11GB free → safe headroom. Backup: `limits.conf.bak-pre-bump-20260507-165148`. -**Resultado pós-bump (5min watch):** -| Métrica | Pré-bump | Pós-bump | Delta | -|---|---|---|---| -| Memory current | 1.57G | 1.5G estável | flat | -| memory.events.high | 20432 (subindo) | 4554 (FROZEN) | sem novos hits | -| Latency `/api/search` | 6s+ (pico 9s) | 1.0-1.2s | -80% | -| Canary alerts em 10min | 1 | 0 | resolvido | +**Resultado pós-bump 2 (10min watch):** +| Métrica | Pré-bump 1 | Pós-bump 1 (5min) | Recorreu (T+1h) | Pós-bump 2 (10min) | +|---|---|---|---|---| +| Memory current | 1.57G | 1.5G | **1.8G** (100% limit) | **1.7G constante** | +| memory.events.high | 20432 | 4554 (frozen) | **21793** (subindo) | **0** (zero) | +| Latency `/api/search` | 6s+ pico 9s | 1.0-1.2s | 3s+ seq, 13s concurrent | **0.9-1.5s** consistente | +| Canary status | FAIL(2) Discord | 0 disparos | FAIL(1)+FAIL(2) | 2 OKs (debounce reset) | -**Lição (P2 estratégica):** `MemoryHigh` em systemd cgroup deve ser baseado em **working set steady-state**, não em valor "confortável" ou "metade do MemoryMax". Service cuja warm-up natural excede MemoryHigh fica permanentemente throttled — pior que estar acima do limite de uma vez (zero crashes mascaram problema). +**Lição (P2 estratégica, refinada após bump 1 falhar):** `MemoryHigh` em systemd cgroup deve ser baseado em **working set steady-state revelado em horas de uso real**, não em snapshot inicial pós-restart. Bump 1 pareceu resolver em 5min de watch (memory 1.5G estável), mas working set real era 1.8G+ revelado só após 1h+ de uso normal — caches embedding/chunk crescem com queries diárias. Service cuja warm-up natural excede MemoryHigh fica permanentemente throttled — pior que estar acima do limite de uma vez (zero crashes mascaram problema). **Diagnóstico empírico:** comparar `memory.current` (estável) vs `memory.events.high` (incrementando) em `/sys/fs/cgroup//`. Se high incrementa sem max/oom subir, é throttle silencioso. -**Padrão pra próxima service nova:** rodar 24h sob load real, observar `memory.peak` no journal `Consumed N memory peak`, MemoryHigh = peak * 1.2 minimum. Não confiar em estimativas estáticas. +**Padrão pra próxima service:** +1. Rodar **24h+ sob load real** (não 5min, não 1h — caches storage/embedding levam horas pra estabilizar) +2. Observar `memory.peak` no journal `Consumed N memory peak` +3. MemoryHigh = **peak * 1.4 minimum** (40% headroom, não 20%) +4. MemoryMax = MemoryHigh * 1.25 (margem extra) +5. Re-monitorar 24h pós-bump pra confirmar estabilidade + +**Anti-padrão:** declarar resolvido após 5min observação pós-restart — restart libera cache, queries não rodaram ainda, snapshot é falsamente estável. ### Incidente 4 (não-blocante): marker mismatch reapply vs canary