Fins ara tot el que has manejat estava quiet: fitxers, permisos, text. Aquesta lliçó canvia d'objecte i s'ocupa del que està viu. Un procés és un programa en execució, amb la seva pròpia memòria, els seus descriptors de fitxer oberts, la seva identitat i el seu lloc en un arbre genealògic que arrenca a systemd. Entendre'ls és el que et permet respondre la pregunta que tard o d'hora et farà la Marta: «per què va lent, el servidor?».

A la lliçó anterior vas descobrir que el 65 % dels errors d'acces.log es concentren a la franja de les 03:00, i que tot apunta que alguna cosa competeix per les connexions de la base de dades durant la finestra nocturna. Aquí tens les eines per esbrinar què és aquesta cosa, i per actuar-hi sense tirar el servei a terra.

Contingut

  1. Què és un procés
  2. L'arbre de processos
  3. Cicle de vida: fork, exec, wait, exit
  4. Zombis i orfes
  5. Estats de procés
  6. ps de debò
  7. top i htop: llegir la capçalera
  8. pgrep i pkill
  9. Senyals
  10. Prioritats: nice, renice i ionice
  11. Control de treballs a la sessió interactiva
  12. lsof i fuser
  13. Cas Tramontana: l'app penjada de matinada

  1. Què és un procés

Cada procés té una fitxa al nucli amb, entre altres coses:

Atribut Què és
PID identificador únic
PPID PID del procés pare
UID/GID efectius identitat amb què es comproven els permisos
Estat R, S, D, T o Z (apartat 5)
Prioritat (PRI) i nice (NI) quanta CPU li toca
VSZ / RSS memòria virtual reservada / memòria física realment utilitzada
Directori de treball el cwd amb què resol rutes relatives
Descriptors oberts els que vas veure a /proc/<pid>/fd a 03-04

La distinció VSZ enfront de RSS és la que més malentesos causa: VSZ inclou memòria reservada però mai tocada i biblioteques compartides, així que sumar els VSZ de tots els processos dona un número molt superior a la RAM instal·lada sense que això signifiqui res. El número que importa és RSS.

  1. L'arbre de processos

Tot procés descendeix d'un altre. L'arrel és systemd, amb PID 1, el primer procés que arrenca el nucli.

operador@srv-tramontana:~$ pstree -p | head -8
systemd(1)─┬─cron(742)
           ├─dbus-daemon(701)
           ├─executable(1284)─┬─{executable}(1285)
           │                  ├─{executable}(1286)
           │                  └─{executable}(1287)
           ├─sshd(889)───sshd(1502)───sshd(1508)───bash(1509)───pstree(1620)
           └─systemd-journald(412)

Es llegeix molt. executable(1284) és l'aplicació de Tramontana amb tres fils (entre claus, no són processos independents). La cadena de sshd mostra la teva pròpia connexió: el dimoni principal, el procés de la connexió, el de la sessió ja autenticada, el teu bash i el pstree que acabes de llançar com a fill seu. Aquí hi ha l'herència de l'entorn de 03-01, feta diagrama.

pstree -ps 1284 mostra els avantpassats d'un PID concret i retorna systemd(1)───executable(1284): l'app penja directament de systemd, no d'una sessió d'usuari. Això significa que sobreviu al fet que tanquis l'SSH, i és la diferència entre un servei i un programa llançat a mà.

  1. Cicle de vida: fork, exec, wait, exit

flowchart LR
    P["Pare (bash)"] -->|"fork()"| C["Fill: còpia del pare<br/>PID nou, mateix codi"]
    C -->|"exec()"| N["El fill es reemplaça<br/>pel programa nou"]
    N -->|"exit(codi)"| Z["Zombi: només queda<br/>el codi de sortida"]
    P -->|"wait()"| Z
    Z --> F["Alliberat de la taula<br/>de processos"]

Quan escrius ls a Bash passa això: Bash fa fork(), que crea un fill idèntic a ell; el fill crida exec(), que substitueix el seu contingut pel binari d'ls conservant el PID i els descriptors oberts —aquí és on encaixen les redireccions que Bash va preparar abans—; ls acaba cridant exit(0); i Bash, que era a wait(), recull aquell codi de sortida, que és el que després llegeixes a $?.

Aquesta separació entre fork i exec és la que fa possible la redirecció tal com la vas estudiar: hi ha un moment, entre les dues crides, en què el fill ja existeix i encara no és el programa nou, i és allà on el shell reconfigura els descriptors.

  1. Zombis i orfes

Són dues situacions oposades i convé no confondre-les.

Un zombi (estat Z) és un procés que ja ha acabat però el pare del qual no ha cridat wait(). No consumeix CPU ni memòria: només ocupa una entrada a la taula de processos amb el seu codi de sortida, esperant que algú el reculli.

Un zombi no es pot matar. Ja és mort; kill -9 sobre ell no fa res, perquè els senyals els reben processos vius. L'única manera d'eliminar-lo és que el seu pare el reculli o que el pare mori. Un grapat de zombis és irrellevant; milers indiquen un pare mal programat, i l'acció correcta és reiniciar el pare.

Per buscar-los: ps -eo stat,ppid,pid,comm | awk '$1 ~ /^Z/'. A srv-tramontana no retorna res.

Un orfe és el contrari: un procés viu el pare del qual ha mort. No és cap problema. El nucli el reassigna a systemd (el PPID passa a 1), que sí que crida wait() correctament. És el mecanisme en què es recolzen nohup i els dimonis.

  1. Estats de procés

Estat Nom Significa
R Running / runnable executant-se o a punt per fer-ho
S Interruptible sleep esperant alguna cosa (E/S, xarxa, un temporitzador); la majoria
D Uninterruptible sleep esperant E/S de disc, no accepta senyals
T Stopped aturat per Ctrl+Z o SIGSTOP
Z Zombie acabat, pendent de recollir

Modificadors que veuràs enganxats: s líder de sessió, l multifil, + en primer pla, < prioritat alta, N prioritat baixa.

Per què un procés en D no es pot matar. Està bloquejat dins del nucli esperant que es completi una operació de disc o de xarxa, i el nucli no li lliura senyals fins que aquella operació acabi. kill -9 es queda encuat: el senyal s'entregarà quan el procés torni a l'estat S o R. Si un procés porta minuts en D, el problema no és el procés: és l'emmagatzematge —un disc que falla, un muntatge NFS caigut— i és allà on cal mirar.

  1. ps de debò

ps té dues sintaxis històriques que conviuen: BSD (sense guionet) i UNIX (amb guionet). Les dues combinacions que es fan servir:

operador@srv-tramontana:~$ ps aux | head -3
USER         PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
root           1  0.0  0.4 168404 12856 ?     Ss   08:31   0:03 /sbin/init
svc-tram+   1284  2.1 12.4 982340 483920 ?    Ssl  08:32   1:47 /opt/tramontana/app/executable
Columna Significa
USER propietari efectiu (truncat a 8 caràcters: svc-tram+)
%CPU percentatge de CPU promitjat des que va arrencar, no instantani
%MEM percentatge de RAM física
VSZ / RSS memòria virtual / resident, en KiB
TTY terminal associat; ? significa que no en té, típic d'un servei
STAT estat més modificadors
START / TIME hora d'arrencada / CPU total consumida

Compte amb %CPU: és una mitjana des de l'arrencada del procés. Un procés que va devorar la CPU fa vuit hores i ara dorm pot continuar mostrant un percentatge alt. Per saber què consumeix ara, fes servir top.

ps -ef dona la vista UNIX, amb PPID explícit, que és el que vols per seguir relacions pare-fill. I ps -o construeix la sortida a mida:

operador@srv-tramontana:~$ ps -eo pid,ppid,user,ni,stat,rss,etime,cmd --sort=-rss | head -4
    PID    PPID USER      NI STAT   RSS     ELAPSED CMD
   1284       1 svc-tram   0 Ssl 483920    04:12:33 /opt/tramontana/app/executable
    889       1 root       0 Ss   12404    04:13:05 sshd: /usr/sbin/sshd -D
    412       1 root       0 Ss   11208    04:13:11 systemd-journald

--sort=-rss ordena per memòria resident descendent (el - inverteix). etime dona el temps transcorregut des de l'arrencada, molt més útil que l'hora absoluta quan estàs diagnosticant.

Filtres: -u operador per usuari, -C executable per nom d'ordre, -p 1284 per PID, --forest per veure la jerarquia a la mateixa sortida de ps.

  1. top i htop: llegir la capçalera

top - 12:44:18 up  4:13,  2 users,  load average: 3.42, 1.87, 0.94
Tasks: 132 total,   2 running, 130 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.3 us,  4.1 sy,  0.0 ni, 18.2 id, 64.8 wa,  0.3 hi,  0.3 si,  0.0 st
MiB Mem :   3844.0 total,    198.4 free,   2914.2 used,    731.4 buff/cache
MiB Swap:   2048.0 total,   1620.0 free,    428.0 used.    612.8 avail Mem

La càrrega mitjana

Els tres números són la mitjana de processos en estat R o D durant 1, 5 i 15 minuts. Dues conseqüències que gairebé ningú té clares:

  1. No és un percentatge. Cal comparar-lo amb el nombre de nuclis: a la VM de srv-tramontana, amb 2 vCPU, una càrrega de 2,00 és plena ocupació i 3,42 significa que hi ha més feina de la que la màquina pot atendre.
  2. Inclou els processos en D, és a dir, els que esperen disc. Una càrrega de 3,42 amb la CPU gairebé ociosa no indica manca de CPU: indica que hi ha processos encallats esperant E/S.

I la comparació entre els tres números dona la tendència: 3.42, 1.87, 0.94 és una corba ascendent. El problema està empitjorant ara mateix, no remetent.

El desglossament de CPU

Sigla Significa
us temps en codi d'usuari
sy temps al nucli
ni processos amb el nice modificat
id ociós
wa esperant E/S: la CPU està lliure però no pot avançar
hi / si interrupcions de maquinari / de programari
st steal: CPU que l'hipervisor va donar a una altra VM

Aquest 64.8 wa és la dada de la capçalera de dalt. La CPU no està saturada: està esperant el disc o la base de dades. Perseguir un procés que consumeix CPU seria buscar al lloc equivocat. I un st alt en una màquina virtual significa que el problema no és a la teva VM sinó a l'amfitrió, cosa que convé saber abans d'optimitzar codi.

Sobre la memòria: buff/cache no és memòria perduda, és memòria cau de disc que el nucli allibera tan bon punt algú la necessita. La xifra que importa és avail Mem. Veure poca memòria lliure a Linux és normal i desitjable.

Tecles útils a top: M ordena per memòria, P per CPU, 1 desglossa per nucli, k envia un senyal, u filtra per usuari, c mostra la línia d'ordres completa. htop fa el mateix amb colors, ratolí i arbre amb F5; s'instal·la a part però val la pena.

  1. pgrep i pkill

operador@srv-tramontana:~$ pgrep -a executable
1284 /opt/tramontana/app/executable --config /etc/tramontana/app.conf

-a mostra la línia d'ordres, -c compta, -u filtra per usuari, -f coincideix contra la línia completa i no només amb el nom, -x exigeix coincidència exacta, -n/-o el més nou / el més antic.

Per què són millors que ps | grep | awk | kill: aquesta canonada té dos defectes. El primer és que el mateix grep apareix a la llista i pots acabar matant un PID que ja no existeix o, pitjor, un de reciclat. El segon és que una coincidència parcial s'emporta per davant processos que no volies. pgrep consulta directament /proc i no s'hi inclou a si mateix.

Abans de pkill, executa sempre el pgrep equivalent. És la mateixa convenció que ls abans de rm:

operador@srv-tramontana:~$ pgrep -a -f 'executable --config'
1284 /opt/tramontana/app/executable --config /etc/tramontana/app.conf
operador@srv-tramontana:~$ pkill -f 'executable --config'

  1. Senyals

Un senyal és una notificació asíncrona que el nucli lliura a un procés.

Núm. Nom Efecte per defecte Es pot capturar?
1 SIGHUP acabar; per convenció, recarregar la configuració sí
2 SIGINT interrompre (Ctrl+C) sí
3 SIGQUIT acabar i abocar el core (Ctrl+\) sí
9 SIGKILL matar immediatament no
15 SIGTERM acabar ordenadament (per defecte) sí
18/19 SIGCONT / SIGSTOP reprendre / aturar CONT sí, STOP no
10/12 SIGUSR1 / SIGUSR2 lliures, definides per l'aplicació sí

kill -l llista els 64 senyals del sistema. kill 1284 envia SIGTERM. Per a un altre: kill -TERM 1284, kill -15 1284 o kill -s SIGTERM 1284, totes equivalents. killall nom actua per nom en comptes de per PID —amb el risc evident d'abastar més del que preteníes.

La regla professional: SIGTERM, esperar, i només llavors SIGKILL

SIGTERM és una petició: el procés la rep, executa la seva rutina de tancament i acaba quan ha enllestit. SIGKILL és una execució sumària: el nucli destrueix el procés sense avisar-lo. El procés no se n'assabenta i per tant no pot fer res.

Què es perd amb -9:

  • Les dades a memòries intermèdies que encara no s'havien escrit al disc.
  • Les transaccions obertes a la base de dades, que queden sense confirmar i bloquejant files fins que expirin.
  • Les peticions HTTP en curs, que es tallen en sec: el client veu un error.
  • Els fitxers temporals i els fitxers de bloqueig, que queden orfes i poden impedir l'arrencada següent.
  • L'oportunitat que el procés escrigui al registre per què es va tancar.

El procediment correcte:

operador@srv-tramontana:~$ kill -TERM 1284
operador@srv-tramontana:~$ sleep 10; pgrep -c executable
0

Deu segons és un marge raonable per a una aplicació web; si el procés ja no hi és, hem acabat bé. Només si continua viu passat aquest termini es recorre a kill -9, i aleshores es documenta com a incident, perquè significa que la rutina de tancament de l'aplicació no funciona i això és una fallada que cal corregir.

SIGHUP mereix una menció: per convenció, molts dimonis l'interpreten com a «rellegeix la teva configuració sense reiniciar». Quan funciona, és la manera d'aplicar un canvi a app.conf sense tallar ni una petició.

  1. Prioritats: nice, renice i ionice

El valor nice va de -20 (prioritat màxima) a 19 (mínima). El nom ve de «ser amable»: com més alt, més cedeix el procés davant dels altres. Un usuari normal només el pot pujar —baixar la seva pròpia prioritat—; reduir-lo exigeix root.

operador@srv-tramontana:~$ nice -n 15 tar -czf /srv/tramontana/backups/enviaments/dades.tar.gz /home/operador/dades
operador@srv-tramontana:~$ sudo renice -n 5 -p 1284
1284 (process ID) old priority 0, new priority 5
operador@srv-tramontana:~$ ionice -c 3 tar -czf /srv/tramontana/backups/enviaments/dades.tar.gz /home/operador/dades

nice llança una ordre amb la prioritat modificada; renice canvia la d'un procés ja en marxa, també per usuari (-u) o per grup. I per a l'E/S, que en el nostre cas és el recurs escàs, hi ha ionice. La seva classe 3 és idle: la còpia només llegeix del disc quan ningú més no el necessita. Amb un wa del 64,8 %, ionice resol més que nice: baixar la prioritat de CPU d'un procés que no fa servir CPU no serveix de res. Diagnosticar abans d'actuar també significa triar la palanca correcta.

  1. Control de treballs a la sessió interactiva

Acció Com
Llançar en segon pla ordre &
Llistar els treballs de la sessió jobs -l
Portar al primer pla fg %1
Continuar en segon pla bg %1
Suspendre l'actual Ctrl+Z (envia SIGSTOP)
Deslligar de la sessió disown -h %1
Immune al tancament de sessió nohup ordre &
operador@srv-tramontana:~$ tar -czf /tmp/copia.tar.gz /opt/tramontana/releases/3.1.0 &
[1] 2041
operador@srv-tramontana:~$ jobs -l
[1]+  2041 Running     tar -czf /tmp/copia.tar.gz /opt/tramontana/releases/3.1.0 &

En tancar la sessió, el shell envia SIGHUP als seus treballs. nohup els immunitza i redirigeix la sortida a nohup.out; disown -h aconsegueix el mateix amb un treball ja llançat.

I ara l'advertiment important: res d'això no serveix per a un servei de debò. Un nohup ./executable & no es reinicia si el procés mor, no arrenca en encendre el servidor, no té control de recursos, no gestiona els seus registres i no pot aturar-se de manera ordenada per ningú que no siguis tu. El control de treballs és per a tasques llargues de la teva sessió —una còpia, una compilació—, no per a producció. Els serveis es gestionen amb systemd, i això és la lliçó 05-05.

  1. lsof i fuser

lsof («list open files») respon la pregunta «qui té això obert?». Com que a Linux gairebé tot és un fitxer, serveix també per a sòcols i ports.

Cas «no puc desmuntar».

operador@srv-tramontana:~$ sudo umount /srv/tramontana/backups
umount: /srv/tramontana/backups: target is busy.
operador@srv-tramontana:~$ sudo lsof +D /srv/tramontana/backups
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash     1509 opera  cwd    DIR  8,1      4096 262148 /srv/tramontana/backups/enviaments
tar      2041 opera    3w   REG  8,1  10485760 262203 /srv/tramontana/backups/enviaments/dades.tar.gz

Dos culpables: un bash el directori de treball del qual (cwd) és a dins —n'hi ha prou amb un cd a fora— i un tar escrivint (3w, descriptor 3 en mode escriptura). Amb això ja saps què esperar i a qui avisar, en comptes de forçar el desmuntatge.

Cas «el port 8080 està ocupat».

operador@srv-tramontana:~$ sudo lsof -i :8080
COMMAND     PID           USER   FD   TYPE  DEVICE NODE NAME
executable 1284 svc-tramontana   7u  IPv4 1284091  TCP *:http-alt (LISTEN)

El PID 1284 té el port a l'escolta. És la resposta directa a «no puc arrencar l'aplicació nova perquè el port està en ús»: la vella continua viva.

fuser és més escarit i molt pràctic per actuar: fuser -v /ruta llista els processos, fuser -k /ruta els mata (amb compte) i fuser -k -TERM 8080/tcp envia SIGTERM a qui ocupi aquell port.

/proc/<pid>/ és la font de veritat de la qual beuen totes aquestes eines: cmdline l'ordre exacta, environ l'entorn amb què va arrencar, cwd i exe com a enllaços simbòlics, fd/ els descriptors, status un resum llegible, limits els límits de recursos. Quan una eina et doni una dada dubtosa, ves al fitxer.

  1. Cas Tramontana: l'app penjada de matinada

03:05. L'aplicació no respon. La Marta t'escriu. Procediment, amb la conclusió de 03-05 com a hipòtesi de partida.

Pas 1: és viva i en quin estat?

operador@srv-tramontana:~$ ps -o pid,stat,ni,rss,etime,pcpu -p $(pgrep -x executable)
    PID STAT  NI   RSS     ELAPSED %CPU
   1284 Dsl    0 483920    04:12:33  2.1

Estat D: no està penjada en un bucle, està bloquejada esperant E/S. Amb només un 2,1 % de CPU, no és un problema de càlcul. Un kill -9 aquí ni tan sols tindria efecte immediat.

Pas 2: què diu la càrrega? El load average: 3.42, 1.87, 0.94 amb 64.8 wa de la capçalera de l'apartat 7 confirma el mateix des d'un altre angle: cua creixent i espera d'E/S, no manca de CPU.

Pas 3: qui hi competeix?

operador@srv-tramontana:~$ ps -eo pid,user,stat,pcpu,etime,cmd --sort=-pcpu | head -4
    PID USER     STAT %CPU     ELAPSED CMD
   2210 operador D    38.4       05:12 tar -czf /srv/tramontana/backups/enviaments/nocturna.tar.gz /opt/tramontana
   1284 svc-tram Dsl   2.1    04:12:33 /opt/tramontana/app/executable

Aquí està. Una còpia de seguretat nocturna porta cinc minuts llegint /opt/tramontana sencer —inclosos els quatre releases amb els seus executable de 48 MB— i satura el disc de la VM. L'aplicació, que necessita el disc per atendre consultes, es queda esperant.

Pas 4: alleujar sense matar res. La còpia és legítima; el que està malament és la seva prioritat.

operador@srv-tramontana:~$ sudo ionice -c 3 -p 2210
operador@srv-tramontana:~$ sudo renice -n 19 -p 2210
2210 (process ID) old priority 0, new priority 19

Tots dos canvis s'apliquen al procés en marxa, sense interrompre'l. Dos minuts després el wa baixa i l'aplicació torna a respondre.

Pas 5: si hagués calgut reiniciar l'app, el procediment hauria estat kill -TERM $(pgrep -x executable), esperar que les peticions en curs acabin, verificar amb pgrep que ja no hi és i només llavors arrencar-la de nou. Mai kill -9 d'entrada: tallaria les reserves que s'estiguessin confirmant en aquell moment, i una reserva a mitges és un problema amb el client al davant.

Informe per a la Marta. La caiguda no va ser una fallada de l'aplicació sinó una competència pel disc: la còpia de seguretat nocturna s'executava amb la mateixa prioritat que el servei i el deixava sense accés a l'emmagatzematge. La mesura aplicada —donar a la còpia la prioritat d'E/S més baixa— protegeix que torni a bloquejar el servei, i no protegeix davant d'un augment general de la càrrega: si creix el nombre de reserves, caldran més recursos o separar la base de dades. A més, la còpia inclou els quatre releases sencers quan n'hi hauria prou amb l'actiu, cosa que la fa innecessàriament pesada. Pendent: ajustar l'abast de la còpia i el seu horari, que és exactament el que veurem a la lliçó següent.

Errors Comuns i Consells

  • Fer servir kill -9 com a primera opció. És l'última. SIGTERM, esperar, verificar.
  • Intentar matar un zombi. Ja és mort. Actua sobre el pare.
  • Insistir amb un procés en D. No rebrà el senyal fins que l'E/S acabi. Investiga l'emmagatzematge.
  • Llegir el %CPU de ps com a valor instantani. És una mitjana des de l'arrencada. Fes servir top.
  • Alarmar-se per poca memòria lliure. buff/cache és memòria cau reutilitzable. Mira avail Mem.
  • Comparar la càrrega mitjana amb 100. Compara-la amb el nombre de nuclis, i recorda que inclou l'espera d'E/S.
  • ps | grep | kill sobre un nom curt. El mateix grep surt a la llista i una coincidència parcial mata de més. Fes servir pgrep -a i després pkill.
  • Deixar un servei amb nohup &. No sobreviu a un reinici ni es recupera sol.
  • Consell: davant d'un «el servidor va lent», mira sempre primer el wa de top. Si és alt, el coll d'ampolla és el disc i la meitat de les hipòtesis es descarten de cop.
  • Consell: ps -eo accepta qualsevol combinació de columnes; guarda't un àlies amb les teves a ~/.bashrc, com vas aprendre a 03-01.

Exercicis

Exercici 1. Esbrina amb quina línia d'ordres exacta, amb quin directori de treball i amb quines variables d'entorn va arrencar el procés de Tramontana, sense fer servir ps. Explica què et diu cada dada.

Exercici 2. Llança una tasca llarga en segon pla, suspèn-la, reprèn-la en segon pla, baixa-li la prioritat de CPU i d'E/S, i deslliga-la de la teva sessió perquè sobrevisqui a un tancament d'SSH. Mostra la comprovació de cada pas.

Exercici 3. Simula el diagnòstic de «el port 8080 no accepta la versió nova»: identifica quin procés l'ocupa, de qui és, des de quan, i atura aquell procés de manera ordenada verificant que ha acabat abans de donar el pas per bo.

Solucions

Solució 1.

operador@srv-tramontana:~$ PID=$(pgrep -x executable)
operador@srv-tramontana:~$ tr '\0' ' ' < /proc/$PID/cmdline; echo
/opt/tramontana/app/executable --config /etc/tramontana/app.conf
operador@srv-tramontana:~$ sudo ls -l /proc/$PID/cwd /proc/$PID/exe
lrwxrwxrwx 1 svc-tramontana tramontana 0 Aug 18 12:52 /proc/1284/cwd -> /opt/tramontana/app
lrwxrwxrwx 1 svc-tramontana tramontana 0 Aug 18 12:52 /proc/1284/exe -> /opt/tramontana/releases/3.2.1/executable
operador@srv-tramontana:~$ sudo tr '\0' '\n' < /proc/$PID/environ | grep -E 'PATH|LANG'
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8

cmdline guarda els arguments separats per bytes nuls, d'aquí el tr. Confirma que l'app llegeix /etc/tramontana/app.conf, així que un canvi allà l'afecta. El cwd és /opt/tramontana/app, l'enllaç simbòlic: significa que les seves rutes relatives es resolen a través d'ell.

La dada reveladora és exe, que apunta a /opt/tramontana/releases/3.2.1/executable, la ruta ja resolta. És la prova que el desplegament atòmic funciona com esperàvem: el nucli va fixar el binari real en arrencar, de manera que canviar l'enllaç app a un altre release no afecta el procés en marxa. Saps quina versió està servint de debò, no quina diu l'enllaç ara mateix. I environ mostra un PATH mínim i LANG=C.UTF-8: el servei no hereta el teu entorn interactiu, cosa que ja sabies des de 03-01 i que tornarà a aparèixer a la lliçó següent.

Solució 2.

operador@srv-tramontana:~$ tar -czf /tmp/rel.tar.gz /opt/tramontana/releases &
[1] 2311
operador@srv-tramontana:~$ fg %1
tar -czf /tmp/rel.tar.gz /opt/tramontana/releases
^Z
[1]+  Stopped                 tar -czf /tmp/rel.tar.gz /opt/tramontana/releases
operador@srv-tramontana:~$ ps -o pid,stat -p 2311
    PID STAT
   2311 T
operador@srv-tramontana:~$ bg %1
[1]+ tar -czf /tmp/rel.tar.gz /opt/tramontana/releases &
operador@srv-tramontana:~$ renice -n 15 -p 2311 && ionice -c 3 -p 2311
2311 (process ID) old priority 0, new priority 15
operador@srv-tramontana:~$ disown -h %1
operador@srv-tramontana:~$ ps -o pid,ni,stat -p 2311
    PID  NI STAT
   2311  15 SN

Cada comprovació aporta alguna cosa: STAT en T confirma que Ctrl+Z el va aturar de debò (SIGSTOP), i després de bg i dels ajustos, SN indica que dorm amb prioritat baixa (N) i NI és 15. renice a 15 no ha necessitat sudo perquè pujar el nice propi està permès a qualsevol usuari; baixar-lo requeriria privilegis. disown -h no el treu de la llista de treballs, però marca que no ha de rebre SIGHUP en tancar la sessió. Si haguéssim sabut per endavant que la tasca és llarga, el que hauria estat net és nohup ... & des del principi.

Solució 3.

operador@srv-tramontana:~$ sudo lsof -i :8080 -sTCP:LISTEN
COMMAND     PID           USER   FD   TYPE  DEVICE NODE NAME
executable 1284 svc-tramontana   7u  IPv4 1284091  TCP *:http-alt (LISTEN)
operador@srv-tramontana:~$ ps -o pid,user,etime,cmd -p 1284
    PID USER         ELAPSED CMD
   1284 svc-tram    04:31:12 /opt/tramontana/app/executable --config /etc/tramontana/app.conf

Ja tenim les tres respostes: l'ocupa executable, pertany a svc-tramontana i porta quatre hores i mitja en marxa. -sTCP:LISTEN filtra els sòcols a l'escolta i descarta les connexions establertes, que serien soroll.

operador@srv-tramontana:~$ sudo kill -TERM 1284
operador@srv-tramontana:~$ sleep 10; pgrep -x executable || echo 'ha acabat correctament'
ha acabat correctament
operador@srv-tramontana:~$ sudo lsof -i :8080
operador@srv-tramontana:~$ echo "port lliure: $?"
port lliure: 1

Dues verificacions diferents i totes dues necessàries. pgrep confirma que el procés ja no existeix; lsof sense sortida confirma que el port està lliure, que no és exactament el mateix: un sòcol pot quedar uns segons en TIME_WAIT després de tancar-se el procés, i intentar arrencar la versió nova en aquell forat fallaria per un motiu diferent i desconcertant. Comprovar el recurs que de debò necessites, i no només el procés, és el que evita aquest diagnòstic erroni. L'estat TIME_WAIT i la resta d'estats TCP els veuràs a 03-08.

Conclusió

Has deixat de mirar fitxers per mirar el que s'està executant, i amb això has resolt una incidència real de principi a fi.

  • Saps què guarda el nucli de cada procés —PID, PPID, UID efectiu, estat, prioritat, VSZ i RSS— i que el número de memòria que importa és RSS.
  • Recorres l'arbre de processos amb pstree des de systemd (PID 1) i entens el cicle fork / exec / wait / exit, que és on encaixa la redirecció de 03-04.
  • Distingeixes zombi d'orfe: el zombi no es pot matar i s'actua sobre el pare; l'orfe l'adopta systemd i no és cap problema.
  • Coneixes els estats R, S, D, T, Z i per què un procés en D no respon a cap senyal, ni tan sols a -9.
  • Llegeixes ps aux i ps -ef columna a columna, construeixes vistes amb ps -eo ... --sort=, i saps que el %CPU de ps és una mitjana des de l'arrencada.
  • Interpretes la capçalera de top: la càrrega mitjana enfront del nombre de nuclis i la seva tendència, el desglossament us/sy/ni/id/wa/hi/si/st —amb wa com el senyal que el coll d'ampolla és el disc— i que buff/cache no és memòria perduda.
  • Fas servir pgrep/pkill en comptes de ps | grep | kill, comprovant sempre abans de matar, i apliques la regla professional dels senyals: SIGTERM, esperar, verificar i només llavors SIGKILL, sabent què es perd amb -9.
  • Ajustes prioritats amb nice, renice i ionice, triant la palanca segons on sigui el coll d'ampolla.
  • Controles treballs amb &, jobs, fg, bg, Ctrl+Z, disown i nohup, i tens clar que res d'això no val per a un servei de producció.
  • Respons amb lsof i fuser a «qui té això obert?» i «qui ocupa aquest port?», i vas a /proc/<pid>/ quan vols la veritat sense intermediaris.

El diagnòstic ha deixat una tasca pendent molt concreta: la còpia nocturna s'executa a l'hora equivocada, amb la prioritat equivocada i sobre més dades de les necessàries. Arreglar-la és el tema de la lliçó següent. Programació de Tasques amb Cron t'ensenyarà la sintaxi dels cinc camps fins als seus casos més recargolats, les tres fallades clàssiques que causen el 90 % de les incidències —el PATH mínim, el correu de sortida que ningú llegeix i la zona horària—, com depurar una tasca que «funciona a mà i a cron no», i com evitar amb flock que dues execucions se solapin, que és precisament el que pot haver passat aquesta matinada.

Curs de Linux: De Principiant a Administrador de Sistemes

Mòdul 1: Introducció a Linux

Mòdul 2: Comandes Bàsiques de Linux

Mòdul 3: Habilitats Avançades en la Línia de Comandes

Mòdul 4: Scripting en Shell

Mòdul 5: Administració del Sistema

Mòdul 6: Xarxes i Seguretat

Mòdul 7: Temes Avançats

Mòdul 8: Projectes Pràctics

© Copyright 2026. Tots els drets reservats