Cómo cambiar el tamaño del espacio de intercambio (SWAP) en SmartOS
Nota
En este documento voy a usar los términos SWAP y espacio de intercambio de forma indistinta.
Cuando se realiza una instalación nueva, SmartOS crea un dataset de SWAP del mismo tamaño que la memoria RAM del ordenador. Esto puede ser apropiado para máquinas grandes, pero cuando vamos escasos de memoria un SWAP tan pequeño es problemático porque bajo Illumos (Solaris) no existe el concepto de overcommit de memoria como en Linux. Es decir, un kernel Illumos limita el espacio de direccionamiento disponible para los programas a la suma de la memoria RAM y el espacio de intercambio (SWAP).
Por tanto, en SmartOS es común ampliar el espacio de intercambio.
Una de mis máquinas tiene solo 8GB de RAM y veo lo siguiente:
[root@X ~]# swap -s total: 3928724k bytes allocated + 221992k reserved = 4150716k used, 8223728k available [root@X ~]# zfs get all zones/swap NAME PROPERTY VALUE SOURCE zones/swap type volume - zones/swap creation vie. dic. 2 8:38 2022 - zones/swap used 8,22G - zones/swap available 614G - zones/swap referenced 3,71G - zones/swap compressratio 2.18x - zones/swap reservation none default zones/swap volsize 7,97G local zones/swap volblocksize 8K default zones/swap checksum on default zones/swap compression lz4 inherited from zones zones/swap readonly off default zones/swap createtxg 92 - zones/swap copies 1 default zones/swap refreservation 8,22G local zones/swap guid 1242262060458694733 - zones/swap primarycache all default zones/swap secondarycache all default zones/swap usedbysnapshots 0 - zones/swap usedbydataset 3,71G - zones/swap usedbychildren 0 - zones/swap usedbyrefreservation 4,52G - zones/swap logbias latency default zones/swap dedup off default zones/swap mlslabel none default zones/swap sync standard default zones/swap refcompressratio 2.18x - zones/swap written 3,71G - zones/swap logicalused 8,01G - zones/swap logicalreferenced 8,01G - zones/swap snapshot_limit none default zones/swap snapshot_count none default zones/swap redundant_metadata all default zones/swap encryption off default zones/swap keylocation none default zones/swap keyformat none default zones/swap pbkdf2iters 0 default
Por necesidades de servicio, requiero ampliar bastante el espacio de intercambio que, como he dicho, limita el espacio de direccionamiento total disponible para todos los programas.
En la configuración de zones/swap creada por SmartOS veo que toda la configuración tiene sus valores por defecto [1], con la excepción evidente de volsize y su compañera refreservation.
[1] | En arquitecturas SPARC el tamaño de página es de 8KBytes, pero en x86 el tamaño es de 4KBytes. Que en SmartOS el atributo volblocksize tenga el valor de 8KB en x86 es algo en lo que profundizar. |
Si tuviésemos espacio de sobra en RAM, podríamos desactivar el SWAP, cambiar su tamaño y volver a activarlo. Pero esto tiene dos problemas:
-
Sin parar zonas Solaris, es posible que no nos quepa todo el RAM.
-
SmartOS requiere un dataset de SWAP para poder arrancar. Si no lo encuentra, el arranque fallará. Podemos ver los detalles en el fichero /lib/svc/method/fs-joyent. Ahí se puede ver este código:
swap -a /dev/zvol/dsk/${SYS_ZPOOL}/swap || \ fatal "failed to configure swap device"
Por tanto, destruir zones/swap y volver a crearlo, abre una ventana de vulnerabilidad de unos pocos segundos, pero que preferiría evitar. La ley de Murphy, ya se sabe.
Así que los pasos que vamos a seguir son los siguientes:
-
Creamos un dataset para un segundo espacio de intercambio y lo añadimos al sistema. Tendrá el tamaño del espacio de intercambio original:
[root@X ~]# zfs create -V 8G zones/swap2 [root@X ~]# swap -a /dev/zvol/dsk/zones/swap2
-
Ahora desactivamos el espacio de intercambio original. Esto provocará que se mueva el contenido de ese SWAP al nuevo. Esto puede ser costoso para la máquina, dependiendo de cuánto espacio esté en uso. Puede ser conveniente parar algunos servicios de la máquina para aliviar el proceso. En mi caso me interesa el espacio de intercambio para tener una capacidad de direccionamiento más alta, más que como alivio de la RAM.
[root@X ~]# time swap -d /dev/zvol/dsk/zones/swap real 30m57.348s user 0m0.001s sys 0m10.711s
Durante el proceso de borrado, podemos ver como un SWAP se está marcado como "en proceso de borrado" y va liberando espacio, mientras que el otro se va ocupando. El proceso es muy lento, no obstante. Paciencia [2]:
[root@X ~]# swap -hl swapfile dev swaplo blocks free /dev/zvol/dsk/zones/swap 90,1 4K 7,97G 6,49G INDEL /dev/zvol/dsk/zones/swap2 90,3 4K 8,00G 7,89G
[2] Aparentemente lo que hace el kernel Illumos es volver a traer a memoria las páginas almacenadas en el espacio de intercambio y dejar que el Sistema Operativo (mover al SWAP las páginas que hace más tiempo que no se usan, cuando vamos justos de RAM) haga su trabajo. Este proceso es ineficiente. Sería mucho más rápido simplemente copiar el contenido de un SWAP a otro, pero el código actual funciona también cuando se elimina el SWAP por completo. Digamos que el código es más general.
-
Ahora que ya no estamos usando el viejo espacio de intercambio, podemos cambiar su tamaño. Esto puede hacerse sin destruir el dataset primero, y el cambio es transaccional. Es decir, aunque SmartOS falle en este momento, el sistema arrancará con normalidad, ya sea con el tamaño antiguo o el nuevo:
[root@X ~]# zfs set volsize=64G zones/swap
Este cambio de tamaño ajusta automáticamente refreservation.
[root@X ~]# zfs get all zones/swap NAME PROPERTY VALUE SOURCE zones/swap type volume - zones/swap creation vie. dic. 2 8:38 2022 - zones/swap used 66,0G - zones/swap available 605G - zones/swap referenced 3,71G - zones/swap compressratio 2.18x - zones/swap reservation none default zones/swap volsize 64G local zones/swap volblocksize 8K default zones/swap checksum on default zones/swap compression lz4 inherited from zones zones/swap readonly off default zones/swap createtxg 92 - zones/swap copies 1 default zones/swap refreservation 66,0G local zones/swap guid 1242262060458694733 - zones/swap primarycache all default zones/swap secondarycache all default zones/swap usedbysnapshots 0 - zones/swap usedbydataset 3,71G - zones/swap usedbychildren 0 - zones/swap usedbyrefreservation 62,3G - zones/swap logbias latency default zones/swap dedup off default zones/swap mlslabel none default zones/swap sync standard default zones/swap refcompressratio 2.18x - zones/swap written 3,71G - zones/swap logicalused 8,01G - zones/swap logicalreferenced 8,01G - zones/swap snapshot_limit none default zones/swap snapshot_count none default zones/swap redundant_metadata all default zones/swap encryption off default zones/swap keylocation none default zones/swap keyformat none default zones/swap pbkdf2iters 0 default
-
Ahora añadimos el SWAP primitivo, con el nuevo tamaño, y eliminamos el SWAP temporal que creamos al principio. Con suerte este proceso será rápido si teníamos RAM suficiente y aún no hemos mandado muchas páginas al SWAP:
[root@X ~]# swap -a /dev/zvol/dsk/zones/swap [root@X ~]# time swap -d /dev/zvol/dsk/zones/swap2 real 0m1.847s user 0m0.000s sys 0m0.381s [root@X ~]# swap -hl swapfile dev swaplo blocks free /dev/zvol/dsk/zones/swap 90,1 4K 64,00G 64,00G [root@X ~]# zfs destroy zones/swap2
-
Vemos que todo esté como debe:
[root@X ~]# swap -s total: 3935688k bytes allocated + 224224k reserved = 4159912k used, 67279576k available [root@X ~]# swap -lh swapfile dev swaplo blocks free /dev/zvol/dsk/zones/swap 90,1 4K 64,00G 63,96G
Uso de múltiples espacios de intercambio
En vez de cambiar el tamaño del espacio de intercambio, se podrían utilizar varios volúmenes de SWAP. Eso funcionaría con un kernel Illumos normal, a través del fichero /etc/vfstab, pero en SmartOS eso no funciona así. En SmartOS el fichero /etc/vfstab se crea de forma dinámica, no es persistente entre reinicios.
En SmartOS habría que añadir los espacios de intercambio adicionales a través de un servicio lanzado desde /opt/custom/smf/.