Fecha de corte: 18 de septiembre de 2026
Nodo de validación principal: o6hsmartos10
Versión validada en ejecución: v1.0.2
Modo operativo: dry-run
Estado de activación: armed no activado y no autorizado todavía
o6h-memory-guard es una protección específica para la global zone de SmartOS. Su objetivo es detectar con antelación una trayectoria de agotamiento de páginas físicas que pueda terminar en un panic pageout_deadman, identificar de forma conservadora qué zona y qué proceso están contribuyendo a la presión y, sólo después de una validación suficiente, permitir una acción correctiva limitada.
El problema que motivó el proyecto no es una alarma genérica de porcentaje de RAM. En dos hosts SmartOS de unos 32 GiB se observaron panics donde pageout quedó 90 segundos intentando evacuar la misma página con freemem prácticamente a cero. En ambos dumps, el camino de escritura de swap atravesaba un zvol de ZFS y necesitaba asignar memoria adicional dentro de DMU, ARC y ABD. Esa dependencia puede impedir que pageout progrese precisamente cuando el host ya no dispone de páginas.
La conclusión operativa hasta este corte es:
v1.0.2 está validada en SmartOS real.WOULD_ACTION bajo presión real, todavía no están validados de extremo a extremo.armed todavía.El mensaje común fue:
pageout_deadman: stuck pushing the same page for 90 seconds
El panic indica que el hilo pageout no consiguió avanzar durante 90 segundos al intentar expulsar una página. No identifica por sí solo al proceso que creó la presión ni demuestra por sí solo que el disco estuviera bloqueado.
En los dos casos analizados apareció esencialmente esta ruta:
pageout
-> swap_putpage
-> swap_putapage
-> zvol_strategy
-> dmu_write
-> arc_alloc_buf / arc_hdr_alloc
-> arc_get_data_abd
-> abd_alloc
-> kmem_cache_alloc / vmem_alloc
-> segkmem_zio_alloc
-> page_create_va
Interpretación:
pageout intenta liberar RAM escribiendo memoria anónima a swap.pageout no progresa y finalmente dispara pageout_deadman.También se observó un camino de swapout que alcanzaba zvol_strategy, dmu_tx_assign, dmu_tx_wait y txg_wait_synced. No se encontró un stack real detenido en zio_wait; por ello, la evidencia encaja mejor con inanición de páginas y dependencia de memoria que con una simple escritura de disco bloqueada durante 90 segundos.
| Evidencia | o6hsmartos20 |
o6hsmartos10 |
|---|---|---|
| RAM física | ~32 GiB | ~32 GiB |
| Panic | pageout_deadman |
pageout_deadman |
freemem en el panic |
22 páginas | 57 páginas |
| Equivalente con páginas de 4 KiB | ~88 KiB | ~228 KiB |
Anon en ::memstat |
~23,6 GiB, 72 % | 21.486 MiB, 66 % |
Kernel en ::memstat |
~6,8 GiB, 21 % | 8.899 MiB, 27 % |
| ZFS File Data | ~1,8 GiB | 1.896 MiB, 6 % |
Ruta pageout -> swap -> zvol |
sí | sí |
| Ruta DMU/ARC/ABD que necesita páginas | sí | sí |
zio_wait evidente |
no | no |
En o6hsmartos10, ::memstat mostró:
Page Summary Pages MB %Tot
Kernel 2278204 8899 27%
Boot pages 87855 343 1%
ZFS File Data 485621 1896 6%
Anon 5500542 21486 66%
Exec and libs 9849 38 0%
Page cache 13864 54 0%
Free (cachelist) 66 0 0%
Free (freelist) 2 0 0%
Total 8376003 32718
Physical 8376002 32718
La diferencia entre las 57 páginas del mensaje del panic y las 68 páginas libres contabilizadas después por ::memstat no cambia la conclusión: el sistema estaba prácticamente a cero.
Es una decisión fundamental del proyecto mantener separadas estas dos preguntas.
Es aquello que consume o compromete la memoria hasta atravesar lotsfree, desfree y minfree. En los dumps, la mayor categoría era memoria Anon; los consumidores probables incluían Apache, PHP-FPM, PHP-CGI, MySQL y otros procesos de zonas. También había una cantidad importante de memoria de kernel, que debe estudiarse por separado y no atribuirse automáticamente a una zona.
Es la dependencia circular del camino de pageout con swap sobre ZFS:
presión extrema de RAM
-> pageout intenta liberar memoria
-> escritura a swap en zvol
-> ZFS/DMU/ARC/ABD necesita memoria
-> no quedan páginas
-> pageout no avanza
-> pageout_deadman
Apache prefork puede explicar parte de por qué se llegó al agotamiento. No explica por sí solo por qué el agotamiento terminó en pageout_deadman. Del mismo modo, mejorar el zvol de swap reduce el riesgo del mecanismo final, pero no elimina la necesidad de controlar a los consumidores de memoria.
En el momento de los panics, los dos servidores relevantes usaban mpm_prefork. En un dump se contaron 301 procesos apache2:
zone_id=7.zone_id=9.Los zone_id eran válidos sólo en el instante del crash y cambiaron después del reinicio. El análisis resolvió la antigua zona 9 al UUID estable bc806d9e-fca0-e333-aee6-93883689efe5.
Un Apache de ejemplo, PID 47998 en el dump, tenía:
a_size ~= 514,9 MiB
a_resvsize ~= 523,8 MiB
segments = 664
Estos valores describen el espacio de direcciones y la reserva contable; no son RSS y no deben multiplicarse por el número de workers como si fueran memoria física. Aun así, una población de cientos de procesos prefork es compatible con muchos GiB agregados de memoria anónima privada.
Después se migraron ambos servidores a mpm_event. En web5 quedó demostrado:
Server MPM: event
mpm_event_module (shared)
Configuración activa:
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 150
Esto permite aproximadamente seis procesos worker para 150 workers lógicos, en lugar de hasta 150 procesos independientes con prefork.
Medición posterior en web5:
Procesos Apache: 5
RSS total: 139,4 MiB
RSS medio: 27,9 MiB
El conteo fiable de threads desde /proc/<pid>/task mostró tres hijos con 27 threads y procesos padre o transitorios con un thread. ps -o nlwp dentro de la LX zone mostraba incorrectamente 1, por lo que no debe usarse allí como prueba definitiva.
Conclusión: la migración prefork -> event reduce de forma convincente una fuente importante de presión de memoria, pero no demuestra por sí sola qué fracción exacta de Anon pertenecía a Apache. Al evaluar el consumo web actual hay que sumar Apache y PHP-FPM, porque con event PHP reside en los pools FPM.
libkstat y /proc./opt/custom.fork() ni comandos externos en la ruta crítica.Rutas instaladas observadas:
/opt/custom/bin/o6h-memory-guard
/opt/custom/etc/o6h-memory-guard.conf
/opt/custom/smf/o6h-memory-guard.xml
/opt/custom/var/log/o6h-memory-guard/guard.log
La razón para evitar shell y procesos externos durante la emergencia es que, cerca de minfree, incluso ps, awk, sort, prstat, vmadm o mdb podrían no poder hacer fork() o reservar memoria.
dry-run: modo actual y predeterminado. Puede observar, puntuar candidatos y registrar lo que haría, pero no envía señales.--force-dry-run: salvaguarda de línea de comandos usada en --probe.armed: implementado, pero no activado ni aceptado para producción.allow sólo podría ser señalizada si ambas están abiertas.protect, observe, una zona ausente de la configuración y unmapped nunca son elegibles, ni siquiera al alcanzar el floor.Estados implementados o definidos:
NORMAL
PRE-PRESSURE
PRESSURE
CRITICAL
EMERGENCY
RECOVERY
La lógica se apoya en los umbrales que ofrece el propio kernel:
NORMAL: memoria por encima de lotsfree y sin señales de presión.PRE-PRESSURE y PRESSURE: cruce persistente de lotsfree; se intensifica diagnóstico y se prepara candidato, sin concluir por una sola muestra.CRITICAL: entorno de desfree, persistente y corroborado por tendencia, scanner o pageout.EMERGENCY: entorno de minfree, con acción mucho más urgente si el modo estuviera armado.RECOVERY: histéresis y cooldown; no se considera recuperación por un rebote momentáneo.El floor absoluto es minfree / 2. Es un último umbral de protección, no un permiso para ignorar la política: una zona no autorizada sigue sin ser elegible.
El guard evita reaccionar a una sola caída rápida de freemem. Mantiene deltas de 5, 15 y 60 segundos para distinguir:
La recuperación requiere estabilidad por encima del umbral, no un único sample. Al reiniciar o releer la configuración, el histórico se reinicia y aparece temporalmente como NA; esto es esperado.
El identificador persistente es el UUID de la zona, nunca zone_id. Los números de zona cambian tras un reinicio.
La selección no debe ser:
zona con mayor RSS -> matar su proceso mayor
ni:
PID con mayor RSS global -> matar
Debe combinar:
allow.d5/d15/d60 del PID.Procesos o clases que no deben tocarse por defecto incluyen la global zone, PID 0/1, pageout, fsflush, zsched, zoneadmd, svc.startd, svc.configd, procesos zpool-*, vmadmd y VMs como qemu-system-x86 o bhyve salvo autorización explícita extraordinaria.
| Métrica | Fuente/uso | Interpretación correcta |
|---|---|---|
freemem / free_pages |
unix:0:system_pages |
páginas físicas libres; señal principal de margen inmediato |
availrmem |
system_pages |
memoria disponible para ciertos compromisos; no equivale a RAM libre |
lotsfree |
system_pages |
frontera de reclamación activa y comienzo del diagnóstico intensivo |
desfree |
system_pages |
presión seria |
minfree |
system_pages |
situación extrema |
pp_kernel |
system_pages |
páginas atribuidas al kernel; útil como serie y delta, no como trigger directo de kill |
pageslocked |
system_pages |
páginas bloqueadas; se registra y sigue su delta |
nscan |
system_pages |
actividad del page scanner; corrobora presión real |
| ARC | kstat ARC | tamaño/variación del ARC; no fue el consumidor dominante en los dumps |
swap_committed_pages |
equivalente a swap -s usado |
compromiso virtual: allocated + reserved; no significa bytes escritos al zvol |
swap_physical_used_bytes |
equivalente a swap -l |
ocupación física: (blocks - free) * 512 |
anon_pageout_pages |
suma de cpu:*:vm:anonpgout |
páginas anónimas realmente expulsadas; no duplicar con cpu_stat:* |
El swap físico y anonpgout corroboran presión sólo junto con el estado de memoria; no disparan acciones por sí solos.
Página del sistema: 4096 bytes.
Valores estables observados de system_pages:
| Métrica | Páginas | Aproximación |
|---|---|---|
physmem |
8.376.003 | 32.718,8 MiB |
lotsfree |
130.875 | 511,2 MiB |
desfree |
65.437 | 255,6 MiB |
minfree |
49.077 | 191,7 MiB |
floor minfree/2 |
~24.538 | ~95,8 MiB |
Ejemplos de situación normal:
freemem=255449 pages ~= 997,8 MiB
availrmem=5099973 pages ~= 19.921,8 MiB
pp_kernel=3251495 pages ~= 12.701,2 MiB
Otro sample del probe v1.0.1:
free=274591 pages ~= 1.072,6 MiB
nscan=0
pp_kernel=3108718 pages ~= 11,86 GiB
pageslocked=3133407 pages ~= 11,95 GiB
arc_bytes=7001795280 ~= 6,52 GiB
swap_committed_pages=7621435 ~= 29,07 GiB
swap_physical_used_bytes=4061863936 ~= 3,78 GiB
anon_pageout_pages=6553284
Interpretaciones que deben conservarse:
availrmem de unos 20 GiB no significa que haya 20 GiB físicamente libres.pp_kernel puede ser mayor que la categoría Kernel de un ::memstat; no se deben tratar como cifras equivalentes ni usar pp_kernel > X como trigger sin más análisis.swap_committed_pages puede ocurrir sin crecimiento de swap físico, sin anonpgout y sin nscan; ese caso no es presión de pageout.En una lectura casi simultánea:
swap_committed_pages = 7.632.011
7.632.011 * 4 KiB = 30.528.044 KiB
swap -s: 30.525.928 KiB used
diferencia ~= 2,07 MiB
Swap físico:
swap -l blocks = 67.024.888
swap -l free = 59.100.824
used_blocks = 7.924.064
physical_used = 7.924.064 * 512 = 4.057.120.768 bytes
El probe cercano dio 4.061.863.936 bytes; la diferencia de unos 4,5 MiB era compatible con actividad entre lecturas.
anonpgout:
cpu:0..7:vm:anonpgout sumados = 6.553.284
guard anon_pageout_pages = 6.553.284
La coincidencia fue exacta. Las entradas cpu_stat:*:anonpgout duplican los mismos contadores y no deben sumarse otra vez.
Primera entrega con daemon C, configuración, Makefile, SMF, instalador, pruebas, checksums, dry-run y modo armed implementado. Se validó inicialmente en Linux, pero no estaba aún certificada en SmartOS.
Primer defecto descubierto al instalar en SmartOS:
<stability value="Uncommitted"/>
no era válido para el DTD de SMF usado. La forma correcta fue:
<stability value="Unstable"/>
Cambios principales:
Uncommitted -> Unstable.swap_used_pages por swap_committed_pages.swap_physical_used_bytes.anon_pageout_pages.La lectura puntual mediante --probe quedó validada en SmartOS. Sin embargo, el daemon continuo seguía registrando la nomenclatura antigua swap_used_pages y no exponía de forma continua el swap físico ni anon_pageout. Esto fue un FAIL del contrato de logging, no de la lectura puntual.
Corrigió el runtime continuo:
event=sample incluye swap_committed_pages, swap_physical_used_bytes, anon_pageout_pages y sus flags *_ok.event=delta incluye d5/d15/d60 para las tres.swap_used_pages desaparece del runtime nuevo.swap_alloc_pages, swap_reserved_pages y swap_available_pages permanecen sólo como auxiliares de semántica explícita.En el paquete se ejecutaron 113 pruebas de política y 50 de runtime, ASan, UBSan, -fanalyzer, C99 estricto y validaciones shell/XML. Después se compiló y probó nativamente en SmartOS.
El README de v1.0.2 no traía una sección de upgrade. Se realizó una actualización controlada sustituyendo sólo el binario, preservando configuración, manifiesto y logs, con copia de rollback de v1.0.1.
| Componente | Estado |
|---|---|
| Compilación nativa SmartOS | PASS |
--probe --force-dry-run |
PASS |
system_pages |
PASS |
| ARC | PASS |
| swap comprometido | PASS |
| swap físico | PASS |
anonpgout |
PASS |
| SMF online | PASS |
| muestreo 1 s | PASS |
| logging continuo v1.0.2 | PASS |
| delta 5 s | PASS |
| delta 15 s | PASS |
| delta 60 s | PASS |
clasificación NORMAL |
PASS |
proc_scan |
PASS |
dry-run |
PASS |
| política UUID/eligible inicial | PASS |
| selección final zona/PID bajo presión | PENDIENTE |
WOULD_ACTION real y razonable |
PENDIENTE |
armed |
NO GO |
En un intervalo real:
free_pages d5 = -110448 pages ~= -431 MiB
swap_committed_pages d5 = +113850 pages ~= +445 MiB
swap_physical_used_bytes d5 = -204800 bytes
anon_pageout_pages d5 = 0
nscan_pages d5 = 0
Aunque el compromiso virtual creció con rapidez, no aumentaron el swap físico, anonpgout ni nscan, y freemem seguía por encima de lotsfree. El guard mantuvo correctamente:
state=NORMAL action_pressure=0 floor=0
A las 17:19:06 se observó:
swap_committed_pages: d5=+45584 d15=-187569 d60=-155145 pages
swap_physical_used_bytes: d5=-40960 d15=-30179328 d60=+75329536 bytes
anon_pageout_pages: d5=0 d15=0 d60=+27274 pages
La ventana de 60 s conservaba un episodio de unos 106,5 MiB de pageout anónimo y +75,3 MiB de swap físico, pero las ventanas de 5 y 15 s mostraban que ya no seguía activo. Es exactamente el contexto temporal que se quería obtener.
Gramática confirmada:
zone <lowercase-UUID> <alias-sin-espacios> <allow|protect|observe>
Semántica:
allow: elegible para simulación; en armed, sólo con las dos compuertas abiertas.protect: visible y nunca señalizable.observe: visible y nunca señalizable.unmapped: observada pero nunca elegible.global: nunca elegible.| UUID | Alias | Estado que puede afirmarse |
|---|---|---|
c82f1d64-fc20-4a80-9b72-b0940af83249 |
web5.open6hosting.com / alias configurado web5 |
allow confirmado explícitamente |
fac1f403-e42c-ee4f-c0f6-cbaf7a6d7def |
webscorp.unita.es |
aparentemente autorizada/visible con alias; no consta aquí la línea exacta de política |
344df936-1577-e8d7-b6d0-d9159fb15c33 |
servidor.correccionencatala.cat |
aparentemente autorizada/visible con alias; no consta aquí la línea exacta de política |
54e0531f-da35-c877-9fc8-92454565c9c5 |
03.base0.es |
aparentemente autorizada/visible con alias; no consta aquí la línea exacta de política |
81790093-33cb-45b5-d91e-8d38e9b4902a |
servidor.consultaerte.com |
aparentemente autorizada/visible con alias; no consta aquí la línea exacta de política |
be9a7015-33ae-461b-d4e7-dab81ffc3c26 |
sailandfun.bz2 |
añadida y visible con alias; aparentemente autorizada, pero la línea exacta allow no está reproducida |
bc806d9e-fca0-e333-aee6-93883689efe5 |
sin alias en la política actual | deliberadamente no elegible, unmapped |
d0a34514-aa7f-c6ad-fee5-b6c7489787a6 |
sin alias en la política actual | deliberadamente no elegible, unmapped |
global |
unmapped |
deliberadamente no elegible y siempre protegida |
Nota histórica: antes de añadir sailandfun.bz2, las tres entradas deliberadamente fuera eran bc806d9e-..., d0a34514-... y be9a7015-..., además de global. Tras añadir be9a7015-... con alias sailandfun.bz2, las que siguen inequívocamente fuera son bc806d9e-..., d0a34514-... y global.
Que un UUID aparezca con alias demuestra que el daemon ha leído inventario/política para él, pero no demuestra por sí solo si la regla exacta es allow, protect u observe. Antes de armed debe revisarse el fichero de configuración literal.
web5.open6hosting.com se ha observado aproximadamente entre 7 y 9 GiB de suma de RSS. En distintas ventanas pasó por:
~8,58 GiB con d60 ~= +1,23 GiB
~7,49 GiB con d60 ~= -734 MiB
~7,73 GiB con d60 ~= +241 MiB
Por tanto mueve mucha memoria y es volátil, pero puede estar liberándola. Su tamaño total no demuestra que sea el culpable de cada episodio.
Además, distribuye el consumo entre muchos procesos. Los primeros top_process autorizados mostraron PHP-FPM individuales de aproximadamente 185 y 212 MiB. Un proceso único de otra zona con 800 MiB o 1 GiB puede ser un mejor objetivo de rescate aunque su zona sea menor.
webscorp.unita.es: aproximadamente 2,0-2,5 GiB; ventanas observadas desde crecimiento modesto hasta descenso.servidor.consultaerte.com: aproximadamente 1,8-2,0 GiB; en general estable, con algún intervalo cercano a +85 MiB/min.sailandfun.bz2: aproximadamente 2,9-3,6 GiB en las primeras muestras; candidata importante para comparar procesos individuales pesados.unmapped se siguen midiendo, pero eligible=0 evita que entren en cualquier acción.Los backslashes que aparecían al copiar algunos logs eran escapes del chat; en el fichero real los nombres son free_pages, swap_committed_pages, etc.
2026-09-18T17:16:49Z mono=296136.349 event=sample state=NORMAL action_pressure=0 floor=0 free_pages=348087 lotsfree=130875 desfree=65437 minfree=49077 nscan=0 pp_kernel=2993989 pageslocked=3018668 arc_ok=1 arc_bytes=6152011944 swap_committed_ok=1 swap_committed_pages=7752388 swap_physical_used_ok=1 swap_physical_used_bytes=4136677376 anon_pageout_ok=1 anon_pageout_pages=6576887 swap_alloc_pages=5889225 swap_reserved_pages=1863163 swap_available_pages=5851985
2026-09-18T17:19:06Z mono=296273.346 event=delta metric=swap_committed_pages d5=+45584@5.00s d15=-187569@15.00s d60=-155145@60.00s
2026-09-18T17:19:06Z mono=296273.346 event=delta metric=swap_physical_used_bytes d5=-40960@5.00s d15=-30179328@15.00s d60=+75329536@60.00s
2026-09-18T17:19:06Z mono=296273.346 event=delta metric=anon_pageout_pages d5=+0@5.00s d15=+0@15.00s d60=+27274@60.00s
2026-09-18T17:48:43Z mono=298050.579 event=zone UUID=c82f1d64-fc20-4a80-9b72-b0940af83249 alias=web5.open6hosting.com generation=6 rss_sum_kib=8377060 complete=1 d5_kib=+52884@6.00s d15_kib=NA d60_kib=+649088@61.00s
2026-09-18T17:53:33Z mono=298340.974 event=zone UUID=be9a7015-33ae-461b-d4e7-dab81ffc3c26 alias=sailandfun.bz2 generation=1 rss_sum_kib=3380020 complete=1 d5_kib=-11692@6.00s d15_kib=NA d60_kib=+548@61.00s
En el primer escaneo después de autorizar web5 se observaron, entre otros, PHP-FPM de aproximadamente 212 MiB y 185 MiB con:
event=top_process UUID=c82f1d64-fc20-4a80-9b72-b0940af83249 alias=web5.open6hosting.com zone_id=6 pid=57890 comm=php-fpm rss_kib~=217000 eligible=1 d5_kib=NA d15_kib=NA d60_kib=NA
event=top_process UUID=c82f1d64-fc20-4a80-9b72-b0940af83249 alias=web5.open6hosting.com zone_id=6 pid=60832 comm=php-fpm rss_kib~=189000 eligible=1 d5_kib=NA d15_kib=NA d60_kib=NA
Estas dos líneas son una normalización de los campos y valores descritos en el hilo, no una copia byte a byte del fichero original. En la misma salida, procesos de be9a7015-... y bc806d9e-... aparecían como alias=unmapped eligible=0.
2026-09-18T17:16:50Z mono=296137.359 event=proc_scan complete=1 duration_ms=12.7 capacity=4096
También se observó otro scan completo en unos 14,0 ms. El coste en estado normal parece aceptable.
v1.0.2.--force-dry-run.system_pages, ARC, swap comprometido, swap físico y anonpgout.kstat, swap -s y swap -l.NORMAL coherente.proc_scan completo.d5/d15/d60 por PID de forma sostenida en event=top_process.WOULD_ACTION, todavía en dry-run.allow/protect/observe antes de armado.pp_kernel/pageslocked; si crecen mientras las zonas se mantienen estables, no acusar automáticamente a una zona.dry-run y acumular varios minutos o episodios reales.event=top_process para todas las zonas con alias y comprobar que los PID persistentes adquieren d5, d15 y d60.event=zone con los top_process del mismo intervalo.web5 y sailandfun.bz2: una zona enorme con procesos moderados frente a una zona menor que puede contener uno o dos procesos pesados.WOULD_ACTION provocado por presión real; no provocar artificialmente un estado peligroso en producción sólo para probarlo.allow confirmada;armed.WOULD_ACTION coherente en presión real.protect o fuera del inventario de acción.global y las UUID no autorizadas siempre producen eligible=0.svcs svc:/site/o6h-memory-guard:default
svcs -xv svc:/site/o6h-memory-guard:default
svcs -l svc:/site/o6h-memory-guard:default
pgrep -fl o6h-memory-guard
grep -Ei 'mode|armed|dry' /opt/custom/etc/o6h-memory-guard.conf
grep '^zone ' /opt/custom/etc/o6h-memory-guard.conf
/opt/custom/bin/o6h-memory-guard --probe --force-dry-run
tail -f /opt/custom/var/log/o6h-memory-guard/guard.log
grep 'event=sample' /opt/custom/var/log/o6h-memory-guard/guard.log | tail -20
grep 'event=delta' /opt/custom/var/log/o6h-memory-guard/guard.log | tail -50
grep 'event=zone ' /opt/custom/var/log/o6h-memory-guard/guard.log | tail -50
grep 'event=top_process' /opt/custom/var/log/o6h-memory-guard/guard.log | tail -100
grep 'event=proc_scan' /opt/custom/var/log/o6h-memory-guard/guard.log | tail -20
tail -1000 /opt/custom/var/log/o6h-memory-guard/guard.log |
egrep 'metric=(swap_committed_pages|swap_physical_used_bytes|anon_pageout_pages)' |
tail -30
grep 'event=delta metric=swap_used_pages' \
/opt/custom/var/log/o6h-memory-guard/guard.log | tail
Las coincidencias históricas de v1.0.1 son posibles; no debe haber ninguna nueva después del arranque de v1.0.2.
pagesize
kstat -p unix:0:system_pages
kstat -p | egrep -i 'anon.*pageout|pageout.*anon|anonpgout'
vmstat 1 20
Vista compacta:
PAGESIZE=$(pagesize)
kstat -p unix:0:system_pages |
nawk -v p="$PAGESIZE" '
$1 ~ /:(freemem|availrmem|lotsfree|desfree|minfree|physmem|pp_kernel|pageslocked|nscan)$/ {
split($1,a,":")
printf "%-12s %12d pages %10.1f MiB\n", a[4], $2, ($2*p)/(1024*1024)
}'
swap -s
swap -l
swap -l | nawk '
NR > 1 { used_blocks += ($4 - $5) }
END {
printf "used_blocks=%d\n", used_blocks
printf "physical_used_bytes=%.0f\n", used_blocks * 512
printf "physical_used_MiB=%.1f\n", used_blocks * 512 / 1024 / 1024
}'
zoneadm list -cp
vmadm get <UUID> | json alias zonename state
zoneadm list -cp | grep '<UUID>'
No usar zone_id como identidad persistente.
apache2ctl -V | grep -i 'Server MPM'
apache2ctl -M | egrep 'mpm|php|proxy_fcgi'
for p in $(pgrep apache2); do
printf "%-7s threads=%s\n" "$p" "$(ls /proc/$p/task 2>/dev/null | wc -l)"
done
ps -C apache2 -o rss= | awk '{sum+=$1; n++} END {
printf "Procesos: %d\nRSS total: %.1f MB\nRSS medio: %.1f MB\n",
n, sum/1024, n ? sum/n/1024 : 0
}'
freemem como métrica física crítica; no sustituirla por availrmem ni por porcentaje genérico de RAM.lotsfree, desfree y minfree del host; no codificar porcentajes arbitrarios.minfree/2, pero nunca usarlo para saltarse la política de elegibilidad.anonpgout desde cpu:* y cpu_stat:*.zone_id sólo sirve para el instante observado.allow sin revisar la regla exacta.global, las zonas unmapped, observe, protect o ausentes nunca son sacrificables.web5 es siempre culpable porque sea la zona mayor. Es grande y volátil, y sus procesos individuales observados son moderados.sailandfun.bz2.a_size o a_resvsize de un dump como RSS físico.Kernel de ::memstat a una zona sin evidencia. Seguir pp_kernel como diagnóstico, no como trigger directo./proc/<pid>/task; ps -o nlwp resultó engañoso.dry-run hasta observar y revisar WOULD_ACTION bajo presión real.armed por el mero hecho de que compilación, probe y logging estén en PASS.La próxima sesión debería comenzar obteniendo histórico por proceso:
grep 'event=top_process' \
/opt/custom/var/log/o6h-memory-guard/guard.log |
tail -100
Después debe correlacionarlo con:
grep 'event=zone ' \
/opt/custom/var/log/o6h-memory-guard/guard.log |
tail -50
La pregunta inmediata no es si el daemon mide memoria correctamente; eso ya está aceptado. La pregunta pendiente es si el ranking por PID identifica de manera repetible al proceso que mejor explica el crecimiento y que más memoria podría liberar, respetando la política de zonas, antes de que se autorice cualquier acción real.