Cómo analizar el uso del SWAP en un sistema Linux
En informática existe la regla básica de que todo debe caber en RAM. El espacio SWAP no debería utilizarse. La realidad es más complicada y depende del sistema operativo. En Solaris, por ejemplo, no hay una distinción clara entre RAM y SWAP y, de hecho, al medir el espacio disponible se muestra la suma de ambos recursos y cuando un proceso reserva memoria, se reserva de ese total. En Linux, en cambio, existe el concepto de overcommit de memoria: un proceso puede pedir la memoria que le de la gana, pero no se reservarán bloques de memoria hasta que el proceso los vaya utilizando. Esto permite que un proceso tenga un espacio de direcciones inmenso si no lo utiliza de forma intensiva, pero la contrapartida es que si un proceso realmente emplea toda la memoria que ha solicitado, puede fallar a mitad de ejecución porque no hay recursos suficientes. En Solaris fallaría directamente en la solicitud de memoria inicial.
Sobre el SWAP hay muchos mitos. Por ejemplo, es frecuente reservar tanto espacio de SWAP como RAM tengas en la máquina o el doble de dicha cantidad. ¿Por qué? La respuesta habitual es "porque sí, todo el mundo sabe que es lo que hay que hacer". Hay algunas razones históricas, pero hoy en día no tienen sentido.
La verdadera regla de oro respecto al SWAP es que todo el working set de los procesos en ejecución en el sistema debe caber en RAM. Si tu working set no cabe en RAM, tu rendimiento será ridículo. Una vez que tienes RAM suficiente, el tamaño del SWAP depende de tus necesidades. En Solaris, por ejemplo, es conveniente proporcionar un SWAP amplio porque el sistema lo usará para enviar allí lo que menos se use y así hacer hueco en RAM para cosas más importantes. En Linux el SWAP es más secundario, en buena parte debido al overcommit. Hay que señalar que los entornos Linux que no pueden permitirse que mueran procesos arbitrarios por escasez de recursos, se configuran para desactivar el overcommit y las necesidades de SWAP cambian completamente.
¿Cómo sabremos cuánto SWAP está utilizando un proceso concreto? En Linux esto es fácil:
jcea@jcea:~$ cat /proc/3421/status | grep ^Vm VmPeak: 5857292 kB VmSize: 5849312 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 3327276 kB VmRSS: 3222616 kB VmData: 4758264 kB VmStk: 188 kB VmExe: 148 kB VmLib: 225096 kB VmPTE: 8632 kB VmPMD: 40 kB VmSwap: 141120 kB
Esta secuencia de comandos muestra el estado de la memoria utilizada por el navegador Firefox en mi sistema. Vemos que está reservando 5.8 Gigabytes de RAM (VmSize), aunque realmente está usando solo 3.2 Gigabytes (VmRSS) en memoria y 141 megabytes en el SWAP (VmSwap).
Cuando nuestra máquina Linux empieza a tirar de SWAP, el disco duro está permanentemente activo y el rendimiento se resiente, entonces podemos ver qué procesos están usando más el SWAP. En vez de revisar proceso a proceso, podemos hacer una revisión global y ordenar los procesos por uso de SWAP:
root@jcea:~$ { date; for f in /proc/[0-9]*/status; \ do awk '{k[$1]=$2} \ END { if (k["VmSwap:"]) print k["Pid:"],k["Name:"],k["VmRSS:"],k["VmSwap:"];}' \ $f 2>/dev/null; done | sort -n ; } | sort -n -k 4 3273 ksysguardd 1816 64 2145 acpid 1132 68 2815 anvil 1592 88 2970 start_kdeinit 0 88 3496 sh 504 92 7671 gvfs-udisks2-vo 3084 104 2867 startkde 1380 116 3433 gpg-agent 1604 116 4170 imap 37236 136 4174 imap 35400 136 4173 imap 27384 140 7679 gvfsd-trash 3520 140 2807 agetty 1384 148 3608 vmstat 740 164 7717 gvfsd-metadata 1644 168 4171 imap 12200 176 2131 atd 1060 180 2805 dovecot 1916 180 3007 dconf-service 1564 180 2160 cron 1328 196 1480 lvmetad 456 208 2020 systemd-timesyn 1256 212 1447 systemd-journal 7628 224 2164 systemd-logind 1460 228 2816 log 1368 228 2908 ssh-agent 568 232 3176 bluetoothd 1536 232 2166 avahi-daemon 1200 236 2965 dbus-daemon 1964 244 2133 zed 1108 272 2302 avahi-daemon 40 292 2544 dnsmasq 1824 312 3153 rtkit-daemon 1832 312 2320 accounts-daemon 2996 316 2912 dbus-daemon 2164 316 2956 at-spi-bus-laun 1904 340 2167 dbus-daemon 2948 360 2291 openvpn 2928 372 2736 dbus-daemon 1124 380 3663 imap 5664 396 2377 polkitd 4756 400 3495 cron 1616 408 3662 gconfd-2 2204 452 2727 dbus-launch 996 464 3470 gvfsd 1920 464 2911 dbus-launch 1148 468 2992 kwrapper5 1700 472 2968 at-spi2-registr 2012 512 2509 wpa_supplicant 1464 540 2819 config 2792 592 5100 usbmuxd 4612 612 2152 rsyslogd 1436 640 3784 ssh 2228 652 2856 systemd 1252 672 3785 ssh 2432 684 3957 ssh 2212 684 3752 ssh 2260 688 2520 systemd 940 700 3956 ssh 2200 724 4427 dbus 1912 780 1 systemd 3184 788 2831 upowerd 4592 796 4420 cupsd 2904 796 2418 sddm 2580 816 2533 dhclient 1532 860 3772 ssh 1952 892 3764 ssh 1896 904 3771 ssh 2008 916 2314 ofonod 1596 992 4421 cups-browsed 2324 1012 2855 sddm-helper 2980 1064 2824 udisksd 5900 1108 11175 bash 2548 1152 7699 bash 3304 1268 11172 bash 1648 1284 5650 bash 2960 1300 3102 kscreen_backend 3948 1308 3175 obexd 1536 1352 5230 bash 2864 1384 2676 whoopsie 2356 1524 2135 ModemManager 1344 1572 3152 pulseaudio 4660 1576 4565 bash 2148 1588 3897 bash 2056 1684 2857 (sd-pam) 592 1724 5213 bash 2308 1736 2524 (sd-pam) 432 1852 2321 NetworkManager 3284 1868 4579 bash 1984 1960 4546 bash 1968 1972 5289 vi 4580 1988 3619 bash 1700 2048 3717 bash 1756 2048 3586 bash 1604 2052 3702 bash 1740 2052 3706 bash 1700 2052 3728 bash 1672 2052 3749 bash 1664 2052 3753 bash 1672 2052 3873 bash 1740 2052 3923 bash 1604 2052 3932 bash 1748 2052 3908 bash 1792 2116 3431 bash 1756 2120 3880 bash 1852 2128 1507 systemd-udevd 1396 2160 3864 bash 1896 2300 3238 akonadi_baloo_i 4956 2720 4620 vi 1988 2760 3138 xembedsniproxy 3888 2952 2864 kwalletd 3276 2996 2971 kdeinit5 3256 3016 2866 kwalletd5 4764 3072 3398 kuiserver 2980 3224 3241 akonadi_contact 4244 3256 3263 akonadi_migrati 4476 3272 3122 polkit-kde-auth 4100 3284 2993 kaccess 3684 3300 3246 akonadi_maildir 5176 3316 2974 klauncher 4368 3452 3098 mission-control 3340 3456 3642 arcstat 4344 3488 3242 akonadi_followu 4084 3492 3239 akonadi_birthda 3564 3560 3393 kdeconnectd 4364 3568 3251 akonadi_maildis 6388 3604 2998 kglobalaccel5 5144 3616 3569 python3 3712 3684 3182 akonadi_control 4392 3700 3272 akonadi_newmail 3756 3960 3193 akonadiserver 7000 4016 2315 snapd 4936 5072 3144 korgac 5084 5312 3105 kactivitymanage 4848 5316 3236 akonadi_akonote 5400 5352 3244 akonadi_ical_re 5544 5708 2994 ksmserver 8688 6788 3283 akonadi_notes_a 7072 6872 3286 akonadi_sendlat 6648 6980 3256 akonadi_mailfil 3836 8016 3419 konsole 42524 8508 4000 python3 2580 9288 3237 akonadi_archive 4484 9500 4043 python3 5540 10672 2499 Xorg 58384 12000 3024 kwin_x11 38296 12204 3091 krunner 16644 16308 4172 imap 13676 21476 3094 plasmashell 96604 29556 2976 kded5 21628 30836 3497 getmail 29008 39116 3197 mysqld 37448 110728 3421 firefox 3252680 140492 3428 thunderbird 2117600 226724
El primer campo indica el PID del proceso. El segundo es su nombre. El tercer campo es cuánta memoria está usando el proceso en RAM mientras que el último campo es cuánto usa en el SWAP. Se observa que algunos procesos como getmail o mysqld tienen más memoria en el SWAP que en RAM. Esto es bueno porque si el proceso no necesita esos datos en memoria, prefiero que esa RAM se use para cosas más importantes.
Podemos ver el total de SWAP en uso (más o menos) cambiando el fragmento final por: [1]
| awk '{a+=$4} END {print(a);}'
[1] |
En realidad en Linux es más práctico usar los comandos free o vmstat. Por ejemplo: |
Por ejemplo:
root@jcea:~$ { date; for f in /proc/[0-9]*/status; \ do awk '{k[$1]=$2} \ END { if (k["VmSwap:"]) print k["Pid:"],k["Name:"],k["VmRSS:"],k["VmSwap:"];}' \ $f 2>/dev/null; done | sort -n ; } \ | awk '{a+=$4} END {print(a);}' 922907
En este momento tengo 923 Megabytes en el SWAP. El rendimiento es bueno porque el working set cabe en RAM. Al SWAP se envían los datos que no se han utilizado recientemente. Como he dicho antes, esto es bueno. Estos 923 Megabytes en el SWAP son datos que no necesitan estar en RAM, y esa RAM se puede usar para cosas más importantes. La cuestión es que esos datos en el SWAP no se necesiten para el funcionamiento normal del programa (al menos a corto plazo). Esa es la clave que he comentado antes y que siempre tendrías que tener en cuenta: Lo que importa no es la cantidad de RAM que soliciten los procesos o cuánto SWAP estén usando. Lo importante es que los working sets de todos los procesos activos quepan en RAM.
¿Y eso cómo se sabe?. Podemos echar un vistazo con el comando vmstat:
jcea@jcea:~$ vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st ... 5 0 1007940 493732 80 780728 0 0 0 0 1729 2829 29 4 67 0 0 ...
La columna que nos interesa es el si dentro de swap. Esta columna nos informa del tráfico de entrada desde el SWAP hacia la RAM. Es decir, la frecuencia y la cantidad de datos que el sistema necesita, pero que están en el SWAP. Cuando un programa necesita un dato que está en el SWAP, el programa se detiene mientras el sistema operativo lo carga en RAM. Si hay más procesos pendientes de ser ejecutados, la máquina seguirá progresando en su trabajo. Si todo está esperando por el SWAP, verás actividad en la columna si de swap, pero también en la columna wa dentro de cpu. Si estás en esa situación habrás notado que el rendimiento empieza a empeorar y en el límite el ordenador será inusable.