En las dos lecciones anteriores hemos contado el coste de un fallo de página en milisegundos y hemos visto un servidor caer en hiperpaginación por culpa del disco. Ahora toca mirar de frente ese componente que hemos estado tratando como una caja negra lenta. Porque no es una caja negra: un disco mecánico y un SSD NVMe tienen físicas completamente distintas, y las decisiones que el sistema operativo toma para uno son contraproducentes para el otro.

Un aviso sobre el alcance: esta lección trata el almacenamiento como recurso gestionado, no como sistema de archivos. Aquí verás la física del dispositivo, cuánto cuesta un acceso, cómo se ordenan las peticiones y cómo se combinan varios discos en un volumen fiable. Todo lo que tiene que ver con ficheros, directorios, inodos, particiones y montaje corresponde al módulo 4. La frontera es clara: aquí gestionamos bloques numerados; allí se les da significado.

Contenido

  1. La jerarquía de almacenamiento completa
  2. El disco duro mecánico por dentro
  3. Cálculo del tiempo de un acceso a disco
  4. SSD y memoria NAND: otra física, otras reglas
  5. Amplificación de escritura, recolección de basura y TRIM
  6. NVMe y por qué cambia las reglas
  7. LBA y la abstracción del dispositivo de bloques
  8. Planificación de peticiones de disco
  9. Los planificadores reales de Linux
  10. RAID: combinar discos para capacidad, velocidad o fiabilidad
  11. La decisión de Meteora para /var/lib/meteora
  12. Medición con lsblk e iostat -x

La jerarquía de almacenamiento completa

En 01-01 vimos la jerarquía de memoria hasta la RAM. Ahora la completamos hacia abajo, que es donde las diferencias se vuelven brutales:

Nivel Latencia típica Ancho de banda Capacidad Coste por GB Volátil
Registros 0,3 ns ~1 KB
Caché L1 1 ns 1 TB/s 64 KB
Caché L2 4 ns 500 GB/s 1 MB
Caché L3 15 ns 200 GB/s 32 MB
RAM (DDR4) 80-100 ns 20 GB/s 8 GB 4 €
SSD NVMe 20-100 µs 3.500 MB/s 1 TB 0,08 € No
SSD SATA 100-200 µs 550 MB/s 1 TB 0,06 € No
Disco duro 5-15 ms 150 MB/s 8 TB 0,02 € No
Cinta LTO-9 decenas de segundos 400 MB/s 18 TB 0,008 € No

Los saltos entre niveles adyacentes son de 2 a 5 veces, salvo uno:

RAM → SSD NVMe:  100 ns → 50 µs   = factor 500
RAM → disco:     100 ns → 8 ms    = factor 80.000

El abismo está entre la RAM y el almacenamiento persistente, y ese abismo es la razón de existir de la caché de páginas, del buffering que calculamos en 01-06 y de la paginación por demanda de la lección anterior. Todo el diseño de un sistema operativo en la parte de E/S consiste en evitar cruzarlo.

Una analogía en escala humana, escalando 1 ns a 1 segundo:

Operación Tiempo real En escala humana
Acceso a caché L1 1 ns 1 segundo
Acceso a RAM 100 ns 1 minuto y medio
Acceso a SSD NVMe 50 µs 14 horas
Acceso a disco duro 8 ms 3 meses
Reinicio del servidor 60 s 1.900 años

Cuando el agregador provoca un fallo mayor, desde el punto de vista de la CPU es como esperar tres meses por un dato.

El disco duro mecánico por dentro

Un HDD es el único componente con partes móviles en un servidor moderno, y su física gobierna todo su comportamiento.

Vista lateral:                    Vista superior de un plato:

   ┌─────────────────┐                 ╭─────────────╮
═══╪═══ plato 0 ═════╡ ← cabezal      │ ╭─────────╮ │  ← pista 0 (externa)
   │                 │                │ │ ╭─────╮ │ │  ← pista 1
═══╪═══ plato 1 ═════╡ ← cabezal      │ │ │  ·  │ │ │  ← eje
   │                 │                │ │ ╰─────╯ │ │
═══╪═══ plato 2 ═════╡ ← cabezal      │ ╰─────────╯ │
   └────────┬────────┘                ╰─────────────╯
        brazo actuador                 sector = arco de pista

El vocabulario, que hay que tener claro para los cálculos:

Término Qué es
Plato Disco magnético giratorio. Un HDD tiene entre 1 y 9
Cara Cada lado de un plato; cada una tiene su cabezal
Pista Circunferencia concéntrica en una cara
Cilindro Conjunto de pistas del mismo radio en todos los platos
Sector Unidad mínima de lectura/escritura: 512 bytes o 4 KB
Cabezal Lee y escribe; todos se mueven juntos en el brazo

El cilindro es un concepto clave: como todos los cabezales se mueven solidariamente, acceder a datos del mismo cilindro no requiere mover el brazo, aunque estén en platos distintos. Es prácticamente gratis.

Un acceso tiene tres componentes de tiempo:

Componente Qué ocurre Orden de magnitud ¿Depende de?
Tiempo de búsqueda (seek) Mover el brazo al cilindro correcto 3-12 ms La distancia recorrida
Latencia rotacional Esperar a que el sector pase bajo el cabezal 2-8 ms Las RPM del disco
Tiempo de transferencia Leer los datos mientras giran 0,01-0,1 ms El tamaño del bloque

La latencia rotacional media es exactamente media vuelta, porque en promedio el sector estará a mitad de camino:

RPM Vuelta completa Latencia rotacional media
5.400 11,1 ms 5,56 ms
7.200 8,33 ms 4,17 ms
10.000 6,0 ms 3,00 ms
15.000 4,0 ms 2,00 ms

Cálculo del tiempo de un acceso a disco

Vamos a calcularlo con los datos del disco de meteo-01:

Disco: 7.200 RPM
Tiempo de búsqueda medio: 8,5 ms
Tasa de transferencia sostenida: 150 MB/s
Sector: 4 KB

Caso 1: leer un bloque de 4 KB en una posición aleatoria.

Búsqueda:              8,50 ms
Latencia rotacional:   4,17 ms   (60.000 ms/min ÷ 7.200 RPM ÷ 2)
Transferencia:         4 KB / 150 MB/s = 0,027 ms
                     ──────────
Total:                12,70 ms

Observa la proporción, que es lo verdaderamente importante:

Búsqueda + latencia: 12,67 ms = 99,8 % del tiempo
Transferencia:        0,027 ms = 0,2 % del tiempo

El 99,8 % del tiempo se dedica a posicionarse, no a leer. Esta única cifra explica todo el diseño de los sistemas de almacenamiento sobre disco mecánico.

Caso 2: leer 1 MB contiguo.

Búsqueda:              8,50 ms
Latencia rotacional:   4,17 ms
Transferencia:         1 MB / 150 MB/s = 6,67 ms
                     ──────────
Total:                19,34 ms

Leer 256 veces más datos solo cuesta un 52 % más de tiempo.

Caso 3: leer ese mismo 1 MB en 256 bloques de 4 KB dispersos.

256 × 12,70 ms = 3.251 ms = 3,25 segundos

Comparación directa:

Patrón Tiempo MB/s efectivos
1 MB secuencial 19,3 ms 51,8 MB/s
1 MB en 256 bloques aleatorios 3.251 ms 0,31 MB/s
Factor de diferencia 168×

Un disco mecánico es 168 veces más lento con acceso aleatorio que secuencial. De ahí salen tres consecuencias que dominan el diseño de sistemas:

  1. Leer más de lo pedido casi sale gratis (lectura anticipada, readahead): ya que has pagado la búsqueda, aprovecha.
  2. Agrupar escrituras dispersas en una secuencial compensa enormemente, aunque implique escribir más bytes. Es el fundamento de los sistemas de archivos estructurados en registro y del journaling (04-05).
  3. Reordenar las peticiones para minimizar el movimiento del brazo tiene un impacto gigantesco. Es el tema del apartado 8.

Aplicado a Meteora, con los 17 MB diarios de /var/lib/meteora/lecturas/:

Lectura secuencial del día:     17 MB / 150 MB/s + 12,7 ms ≈ 126 ms
Lectura en 4.250 bloques de 4 KB: 4.250 × 12,7 ms ≈ 54 segundos

El mismo dato, 428 veces más lento. Por eso el agregador debe recorrer el fichero en orden, y por eso madvise(MADV_SEQUENTIAL) de la lección anterior tiene sentido.

SSD y memoria NAND: otra física, otras reglas

Un SSD no tiene partes móviles. Almacena bits como carga eléctrica atrapada en celdas de memoria flash NAND. Esto elimina búsqueda y latencia rotacional, pero introduce restricciones nuevas y muy peculiares.

La estructura interna:

SSD
 └── Canales (4-8, en paralelo)
      └── Chips NAND
           └── Bloques de borrado (256 KB - 4 MB)
                └── Páginas (4-16 KB)  ← unidad de LECTURA y ESCRITURA

Y aquí está la asimetría que lo explica todo:

Operación Unidad Tiempo típico Restricción
Leer Página (4-16 KB) 25-100 µs Ninguna
Escribir Página (4-16 KB) 200-900 µs Solo en páginas ya borradas
Borrar Bloque (256 KB-4 MB) 2-10 ms Afecta a todo el bloque

No se puede sobrescribir una página de flash. Hay que borrarla antes, y el borrado solo funciona sobre bloques enteros que son cientos de veces más grandes que la página.

Esta restricción, que parece un detalle técnico menor, tiene consecuencias en cascada sobre todo el comportamiento del dispositivo.

El problema de la escritura desalineada

Supón que quieres modificar 4 KB dentro de un bloque de 2 MB que está lleno de datos. La secuencia ingenua sería:

1. Leer los 2 MB del bloque a un búfer interno    → 2 MB de lectura
2. Modificar los 4 KB en el búfer
3. Borrar el bloque de 2 MB                        → 5 ms de borrado
4. Reescribir los 2 MB                             → 2 MB de escritura

Has escrito 2 MB en la flash para modificar 4 KB. El factor de amplificación es de 512.

Ningún SSD real hace esto, precisamente porque sería inaceptable. En su lugar, el controlador escribe los 4 KB nuevos en una página ya borrada de otro sitio, y actualiza una tabla interna que traduce direcciones lógicas a físicas. La página antigua queda marcada como inválida, pendiente de reciclaje.

Esa tabla se llama FTL (Flash Translation Layer) y es, conceptualmente, una tabla de páginas dentro del SSD: el mismo mecanismo de indirección que estudiamos en la lección anterior, aplicado al almacenamiento. Ni el sistema operativo ni tú veis nunca las direcciones físicas de la flash.

Amplificación de escritura, recolección de basura y TRIM

Como las páginas inválidas se acumulan, el SSD necesita reciclarlas. Ese proceso es la recolección de basura (garbage collection):

Bloque A (2 MB) antes:
[válida][inválida][válida][inválida][inválida][válida][libre][libre]

Proceso:
1. Copiar las 3 páginas válidas a un bloque nuevo
2. Borrar el bloque A entero
3. El bloque A queda disponible

Bloque A después: [libre][libre][libre][libre][libre][libre][libre][libre]

El coste: para liberar espacio ha habido que copiar datos que ya estaban escritos. Eso es amplificación de escritura (write amplification):

WA = bytes escritos en la flash / bytes escritos por el sistema operativo
Escenario WA típica Por qué
Escritura secuencial, SSD vacío 1,0-1,1 Los bloques se llenan y se reciclan enteros
Escritura aleatoria, SSD al 50 % 2-3 Hay que reubicar páginas válidas
Escritura aleatoria, SSD al 95 % 5-10 Apenas quedan bloques libres para reciclar
Escritura aleatoria, sin TRIM 10-20 El SSD no sabe qué datos están obsoletos

Un SSD casi lleno se comporta mucho peor que uno con espacio libre. Y no es solo cuestión de rendimiento: la flash tiene un número limitado de ciclos de borrado por celda.

Tipo de NAND Bits por celda Ciclos de borrado Uso
SLC 1 50.000-100.000 Industrial, caché
MLC 2 3.000-10.000 Empresa
TLC 3 1.000-3.000 Consumo y servidor
QLC 4 300-1.000 Archivo, lectura intensiva

Con esto se puede calcular la vida útil del SSD de meteo-01:

SSD TLC de 1 TB, 1.500 ciclos de borrado
Escritura total soportada = 1 TB × 1.500 = 1.500 TBW (terabytes escritos)

Escritura diaria de Meteora:
  Lecturas: 17 MB/día
  Registros: ~200 MB/día
  Backups y temporales: ~500 MB/día
  Total: ~720 MB/día

Con amplificación de escritura de 3:
  720 MB × 3 = 2,16 GB/día en la flash

Vida útil = 1.500 TB / 2,16 GB/día = 694.444 días = 1.902 años

La carga de Meteora no desgastará el SSD nunca. Pero cambia el escenario: un servidor de base de datos que escriba 500 GB/día con WA de 5 gastaría 2,5 TB/día, y esos mismos 1.500 TBW durarían 600 días. Por eso el TBW es una especificación que hay que mirar al comprar SSD para servidores de escritura intensiva.

Nivelado de desgaste

Si el controlador escribiera siempre en los mismos bloques, esos se agotarían mientras el resto queda intacto. El nivelado de desgaste (wear leveling) reparte las escrituras uniformemente, e incluso mueve datos estáticos que llevan mucho tiempo sin cambiar para liberar sus bloques poco desgastados.

Es otra de las razones por las que el SSD necesita indirección: la relación entre dirección lógica y ubicación física cambia constantemente.

TRIM

Cuando borras un fichero, el sistema de archivos marca sus bloques como libres en sus propias estructuras, pero el SSD no se entera: para él, esos datos siguen siendo válidos y los seguirá copiando durante la recolección de basura.

La orden TRIM (discard en NVMe) le comunica al SSD qué bloques ya no contienen datos útiles:

$ sudo fstrim -av
/var/lib/meteora: 128,4 GiB (137886920704 bytes) trimmed on /dev/nvme0n1p2
/: 12,1 GiB (12992958464 bytes) trimmed on /dev/nvme0n1p1

$ systemctl status fstrim.timer
● fstrim.timer - Discard unused blocks once a week
     Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled)
     Active: active (waiting) since Mon 2026-08-24 00:00:12 CEST
    Trigger: Mon 2026-09-07 00:00:00 CEST; 6 days left

Sin TRIM, el SSD acaba creyendo que está lleno aunque el sistema de archivos vea espacio libre, y la amplificación de escritura se dispara. Las distribuciones modernas activan fstrim.timer semanalmente, que es la opción recomendada frente a discard en las opciones de montaje (esta última emite un TRIM por cada borrado y puede penalizar el rendimiento).

Comparativa HDD frente a SSD

Característica HDD 7.200 RPM SSD SATA SSD NVMe
Latencia de lectura 12,7 ms 150 µs 50 µs
IOPS aleatorias 4K ~120 ~90.000 ~600.000
Ancho de banda secuencial 150 MB/s 550 MB/s 3.500 MB/s
Aleatorio frente a secuencial 168× peor 1,2× peor ~1× igual
Consumo 6-10 W 2-3 W 5-8 W
Coste por GB 0,02 € 0,06 € 0,08 €
Modo de fallo Progresivo, con avisos Súbito al agotar ciclos Súbito

La fila más importante es la cuarta: en un SSD, el acceso aleatorio cuesta prácticamente lo mismo que el secuencial. Esa única diferencia invalida décadas de optimizaciones diseñadas para discos mecánicos, incluidos casi todos los algoritmos de planificación que veremos a continuación.

NVMe y por qué cambia las reglas

Los primeros SSD se conectaban por SATA con el protocolo AHCI, diseñado en 2004 para discos mecánicos. Sus supuestos ya no valían:

AHCI (SATA) NVMe
Colas de comandos 1 65.535
Comandos por cola 32 65.536
Interfaz física SATA 6 Gb/s PCIe (4 GB/s por carril ×4)
Instrucciones por E/S ~4 registros MMIO 2
Interrupciones Una línea compartida MSI-X, una por cola y núcleo
Latencia del protocolo ~6 µs ~2,8 µs

La diferencia estructural es la paralelización. Con AHCI, una única cola significa que todos los núcleos compiten por ella con un cerrojo compartido. NVMe da una cola por núcleo, eliminando la contención por completo: cada CPU envía sus peticiones a su propia cola sin sincronizarse con nadie.

Y aquí conecta con lo que sabemos: un SSD tiene 4-8 canales internos trabajando en paralelo. Para saturarlo hacen falta muchas peticiones simultáneas en vuelo. Con una sola cola de 32 comandos es imposible; con 65.535 colas, trivial.

$ lsblk -d -o NAME,ROTA,SIZE,MODEL
NAME    ROTA   SIZE MODEL
nvme0n1    0 931,5G Samsung SSD 980 PRO 1TB
sda        1   7,3T ST8000NM0055-1RM112

La columna ROTA (rotacional) es la que hay que mirar: 1 es un disco mecánico, 0 un SSD. El núcleo la usa para decidir la lectura anticipada, el planificador por defecto y otras políticas. Comprobarla es siempre el primer paso al diagnosticar rendimiento de disco.

LBA y la abstracción del dispositivo de bloques

Todo lo anterior —cilindros, cabezales, canales NAND, FTL— está oculto. El sistema operativo ve una abstracción uniforme: el dispositivo de bloques.

Dispositivo de bloques = array lineal de N bloques de tamaño fijo
                         numerados de 0 a N−1

Ese numerado es el LBA (Logical Block Addressing). Antes de 1990 se usaba direccionamiento CHS (cilindro-cabezal-sector), que exponía la geometría física y limitaba la capacidad a 8 GB. LBA lo sustituyó por un número secuencial y el firmware del disco hace la traducción.

$ sudo blockdev --getsize64 /dev/nvme0n1
1000204886016
$ sudo blockdev --getbsz /dev/nvme0n1
4096
$ cat /sys/block/nvme0n1/queue/logical_block_size
512
$ cat /sys/block/nvme0n1/queue/physical_block_size
512

La abstracción da al sistema operativo exactamente cuatro operaciones:

Operación Qué hace
read(lba, n) Lee n bloques desde el LBA indicado
write(lba, n, datos) Escribe n bloques
flush() Fuerza el volcado de la caché interna del dispositivo
discard(lba, n) TRIM: estos bloques ya no contienen datos útiles

Esta uniformidad es lo que permite que el mismo código del núcleo funcione sobre un disquete, un SSD NVMe, un volumen RAID o un disco de red. Es la misma idea de máquina extendida que vimos en 01-01, aplicada al almacenamiento. La operación flush() es especialmente importante y volverá en Asignación de Espacio, Journaling e Integridad, porque un fsync() que no llegue hasta el plato físico no garantiza nada.

Planificación de peticiones de disco

Con un disco mecánico, el orden en que se sirven las peticiones determina cuánto se mueve el brazo, y ya sabemos que ahí está el 99,8 % del coste. Es un problema de planificación análogo al de la CPU, pero con una métrica distinta: el desplazamiento total del cabezal.

Trabajaremos todos los algoritmos sobre la misma cola:

Cola de peticiones (cilindros): 98, 183, 37, 122, 14, 124, 65, 67
Posición inicial del cabezal: 53
Rango del disco: 0 a 199

FCFS

Se sirven en el orden de llegada.

53 → 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67
Movimiento Distancia
53 → 98 45
98 → 183 85
183 → 37 146
37 → 122 85
122 → 14 108
14 → 124 110
124 → 65 59
65 → 67 2
Total 640

El brazo cruza el disco de un extremo a otro varias veces. Es justo y simple, pero pésimo.

SSTF (el más cercano primero)

Se elige siempre la petición más próxima a la posición actual.

53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183
Movimiento Distancia
53 → 65 12
65 → 67 2
67 → 37 30
37 → 14 23
14 → 98 84
98 → 122 24
122 → 124 2
124 → 183 59
Total 236

Una reducción del 63 % frente a FCFS. Pero SSTF es el equivalente en disco de SJF, y comparte su defecto: inanición. Si llegan continuamente peticiones cerca del cilindro 60, la del cilindro 183 puede no servirse nunca.

SCAN (el algoritmo del ascensor)

El cabezal se mueve en una dirección sirviendo todo lo que encuentra, llega al extremo y vuelve. Como un ascensor.

Supongamos que se mueve hacia cilindros menores:

53 → 37 → 14 → 0 → 65 → 67 → 98 → 122 → 124 → 183
Movimiento Distancia
53 → 0 53
0 → 183 183
Total 236

Mismo total que SSTF aquí, pero sin inanición: toda petición se sirve como mucho en dos recorridos completos. Esa garantía es lo que lo hace utilizable.

Su defecto: las peticiones justo detrás del cabezal esperan un recorrido entero, mientras que las de justo delante se sirven de inmediato. El tiempo de espera no es uniforme.

C-SCAN (SCAN circular)

Solo sirve peticiones en una dirección; al llegar al extremo, vuelve al principio sin servir nada en el retorno.

53 → 65 → 67 → 98 → 122 → 124 → 183 → 199 → 0 → 14 → 37
Movimiento Distancia
53 → 199 146
199 → 0 (retorno rápido) 199
0 → 37 37
Total 382

Recorre más, pero a cambio ofrece un tiempo de espera mucho más uniforme: el disco se comporta como una lista circular y ninguna zona está sistemáticamente favorecida. Es el compromiso que suelen preferir los sistemas donde la previsibilidad importa más que el rendimiento medio.

LOOK y C-LOOK

Optimización obvia de SCAN y C-SCAN: no ir hasta el extremo físico si no hay peticiones allí.

LOOK:

53 → 37 → 14 → 65 → 67 → 98 → 122 → 124 → 183
Movimiento Distancia
53 → 14 39
14 → 183 169
Total 208

C-LOOK:

53 → 65 → 67 → 98 → 122 → 124 → 183 → 14 → 37
Movimiento Distancia
53 → 183 130
183 → 14 (retorno) 169
14 → 37 23
Total 322

Comparación completa

Algoritmo Desplazamiento Frente a FCFS Inanición Espera uniforme
FCFS 640 No
SSTF 236 −63 % No
SCAN 236 −63 % No No
C-SCAN 382 −40 % No
LOOK 208 −67,5 % No No
C-LOOK 322 −50 % No

LOOK gana en desplazamiento total y es el que históricamente han usado los sistemas UNIX. C-SCAN y C-LOOK son preferibles cuando la varianza de la latencia importa más que la media.

Y ahora la observación que hay que tener siempre presente: todo este apartado presupone un cabezal que se mueve. En un SSD, la "distancia" entre el LBA 14 y el 183 es cero: ambos accesos cuestan lo mismo. Reordenar peticiones para un SSD no solo no ayuda, sino que añade latencia y consume CPU sin beneficio alguno. Es exactamente lo que motivó el planificador none de Linux.

Los planificadores reales de Linux

Linux permite elegir el planificador de E/S por dispositivo:

$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq

$ cat /sys/block/sda/queue/scheduler
none [mq-deadline] kyber bfq

Los corchetes indican el activo. Fíjate en la decisión que ha tomado el núcleo por sí solo: none para el NVMe, mq-deadline para el disco mecánico.

Planificador Estrategia Adecuado para Sobrecoste
none (noop) FIFO, sin reordenar NVMe, SSD rápidos Mínimo
mq-deadline Ordena por LBA con plazos máximos HDD, SSD SATA Bajo
kyber Limita las colas según latencia objetivo NVMe multi-cola con carga mixta Bajo
bfq Reparto justo por proceso, con pesos Escritorio, cargas interactivas Alto

none no hace nada: pasa las peticiones al dispositivo en el orden de llegada. Suena a rendición, pero es la opción correcta para NVMe: el dispositivo tiene sus propias colas paralelas y su propio planificador interno, y sabe más que el núcleo sobre su geometría. Cualquier reordenación del sistema operativo sería una suposición equivocada.

mq-deadline mantiene dos colas ordenadas por LBA (una de lectura, otra de escritura) más dos colas FIFO por plazo. Sirve en orden de LBA —lo que da un comportamiento tipo LOOK— salvo cuando una petición está a punto de agotar su plazo, momento en el que salta a servirla. Los plazos por defecto son reveladores:

$ cat /sys/block/sda/queue/iosched/read_expire
500
$ cat /sys/block/sda/queue/iosched/write_expire
5000

500 ms para lecturas y 5.000 ms para escrituras. Las lecturas tienen diez veces más prioridad, y la razón es sólida: una lectura es casi siempre síncrona (hay un proceso bloqueado esperándola, en estado D), mientras que una escritura suele ser asíncrona (el proceso ya continuó, y el núcleo la volcará cuando pueda). Retrasar una lectura bloquea a alguien; retrasar una escritura no.

bfq (Budget Fair Queueing) da a cada proceso un presupuesto de sectores y reparte el ancho de banda de forma justa, con pesos configurables mediante ionice. Es lo que permitía la solución del backup en la lección 02-02:

$ sudo ionice -c 3 -p $(pgrep -f backup-diario)
$ ionice -p 1877
best-effort: prio 4
Clase de ionice Nombre Comportamiento
1 Tiempo real Acceso prioritario garantizado
2 Mejor esfuerzo Prioridad 0-7, por defecto 4
3 Idle Solo cuando nadie más pide disco

Cambiar el planificador es inmediato y no requiere reiniciar:

$ echo bfq | sudo tee /sys/block/sda/queue/scheduler
$ cat /sys/block/sda/queue/scheduler
none mq-deadline kyber [bfq]

Para hacerlo persistente se usa una regla de udev, mecanismo que veremos en la próxima lección.

Regla práctica de elección:

Dispositivo y carga Elección
NVMe, servidor none
SSD SATA, servidor mq-deadline
HDD, servidor mq-deadline
Cualquiera, escritorio bfq
NVMe con cargas de latencia mixta kyber

RAID: combinar discos para capacidad, velocidad o fiabilidad

Un disco falla. La probabilidad anual de fallo de un disco de servidor ronda el 1-2 %, lo que parece poco hasta que tienes 100 discos: entonces esperas uno o dos fallos al año con certeza práctica.

RAID (Redundant Array of Independent Disks) combina varios discos en un volumen lógico. Los niveles se distinguen por cómo reparten datos y redundancia.

RAID 0 (división, striping)

Los datos se reparten en franjas entre todos los discos. Sin redundancia.

Bloque:  0    1    2    3    4    5
Disco A: [0]      [2]      [4]
Disco B:      [1]      [3]      [5]
  • Capacidad: 100 % de la suma.
  • Rendimiento: multiplica por N en lectura y escritura.
  • Tolerancia a fallos: ninguna. Si falla un disco, se pierde todo el volumen.

Y la trampa estadística: RAID 0 es menos fiable que un disco solo. Con 4 discos al 2 % de fallo anual:

P(que sobrevivan los 4) = 0,98^4 = 0,922
P(fallo del volumen) = 7,8 % anual, frente al 2 % de un disco suelto

Multiplicas el riesgo por cuatro. Solo tiene sentido para datos reproducibles: cachés, ficheros temporales, resultados intermedios.

RAID 1 (espejo)

Cada dato se escribe idéntico en todos los discos.

Disco A: [0][1][2][3]
Disco B: [0][1][2][3]
  • Capacidad: 50 % con dos discos.
  • Lectura: se puede repartir entre ambos, hasta 2× más rápida.
  • Escritura: la de un disco (hay que escribir en los dos).
  • Tolera el fallo de un disco sin perder nada ni degradar apenas.

RAID 5 (paridad distribuida)

Los datos se dividen entre N discos y se añade un bloque de paridad calculado con XOR, rotando qué disco lo guarda.

Disco A: [D0]  [D3]  [P2]  [D8]
Disco B: [D1]  [P1]  [D6]  [D9]
Disco C: [P0]  [D4]  [D7]  [P3]
Disco D: [D2]  [D5]  [P?]  [D10]

P0 = D0 XOR D1 XOR D2

La magia del XOR: si se pierde D1, se recupera como D1 = D0 XOR D2 XOR P0. La misma operación sirve para calcular y para reconstruir.

  • Capacidad: (N−1)/N. Con 4 discos, el 75 %.
  • Tolera un fallo.
  • Penalización de escritura: modificar un bloque exige leer el dato antiguo, leer la paridad antigua, calcular la nueva y escribir dos bloques. Cuatro operaciones de E/S por escritura.

El riesgo serio de RAID 5 con discos grandes es la reconstrucción. Al sustituir un disco de 8 TB hay que leer los otros tres enteros:

Datos a leer: 3 × 8 TB = 24 TB
A 150 MB/s: 24.000.000 MB / 150 MB/s = 160.000 s ≈ 44 horas

Casi dos días con el array degradado y sin redundancia, sometiendo a los discos supervivientes —de la misma edad y el mismo lote— a una carga intensa de lectura. Es exactamente cuando más probable es un segundo fallo, y un segundo fallo en RAID 5 significa pérdida total. Por eso RAID 5 está desaconsejado con discos de más de 2 TB.

RAID 6 (doble paridad)

Como RAID 5 pero con dos bloques de paridad independientes.

  • Capacidad: (N−2)/N. Con 6 discos, el 66,7 %.
  • Tolera dos fallos simultáneos.
  • Penalización de escritura: seis operaciones por escritura.

Es la respuesta al problema de reconstrucción de RAID 5: durante las 44 horas de reconstrucción todavía queda un nivel de redundancia.

RAID 10 (espejo + división)

Espejos de dos discos, unidos por división.

Franja 1: Espejo(A, B)
Franja 2: Espejo(C, D)
  • Capacidad: 50 %.
  • Sin penalización de paridad: dos operaciones por escritura.
  • Tolera un fallo por espejo; con suerte, hasta la mitad de los discos.
  • Reconstrucción rapidísima: solo hay que copiar el disco espejo, no leer todo el array.

Con discos de 8 TB, reconstruir es copiar 8 TB: unas 15 horas, y sin poner en riesgo al resto del array.

Tabla comparativa

Con 4 discos de 8 TB cada uno:

Nivel Capacidad útil Fallos tolerados E/S por escritura Lectura Reconstrucción
RAID 0 32 TB (100 %) 0 1 Imposible
RAID 1 (2+2) 16 TB (50 %) 1 por espejo 2 Copia: rápida
RAID 5 24 TB (75 %) 1 4 Lenta y arriesgada
RAID 6 16 TB (50 %) 2 6 Lenta pero segura
RAID 10 16 TB (50 %) 1-2 2 Copia: rápida

Y la advertencia imprescindible:

RAID no es una copia de seguridad. Protege del fallo de hardware, y de nada más. No te salva de un rm -rf accidental, de ransomware, de un fallo del sistema de archivos, de un error del controlador RAID ni de un incendio. Una copia de seguridad es una copia separada en el tiempo y en el espacio.

La decisión de Meteora para /var/lib/meteora

Apliquemos todo a un caso concreto. Requisitos:

Requisito Valor
Volumen de datos 17 MB/día = 6,2 GB/año
Retención 10 años = 62 GB, más margen: 500 GB
Patrón de escritura Secuencial, un fichero por día, append continuo
Patrón de lectura Secuencial (agregador), aleatorio ligero (meteo-api)
Criticidad Alta: las lecturas perdidas no se recuperan
Presupuesto Moderado

Análisis de opciones:

Opción Capacidad Valoración
Un solo SSD 1 TB Descartada: un fallo pierde 10 años de datos
RAID 0 (2 SSD) 2 TB Descartada: duplica el riesgo sin necesitar la velocidad
RAID 5 (4 HDD 8 TB) 24 TB Descartada: 24 TB para 500 GB, y reconstrucción de 44 h
RAID 6 (6 discos) Descartada: exceso de coste y de penalización de escritura
RAID 1 (2 SSD 1 TB) 1 TB Elegida

Justificación de RAID 1 con dos SSD:

  1. El volumen es pequeño. 500 GB proyectados a 10 años caben de sobra en 1 TB. Optimizar capacidad no aporta nada aquí, y ese es precisamente el argumento de RAID 5 y 6.
  2. La escritura es continua y en append. RAID 5 penaliza con 4 operaciones de E/S por escritura; RAID 1 solo con 2. Con el ingestor escribiendo constantemente, esa diferencia importa más que la capacidad.
  3. La reconstrucción es una simple copia. Sustituir un SSD implica copiar como mucho 500 GB, unas 15 minutos a 550 MB/s, sin exponer los datos como haría RAID 5.
  4. La lectura mejora: agregador y meteo-api pueden leer de ambos discos en paralelo.
  5. Simplicidad. RAID 1 es el nivel más fácil de entender, montar y recuperar. En una emergencia a las tres de la madrugada, eso vale más que un 25 % de capacidad extra.

Configuración:

# Crear el array
$ sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 \
    /dev/nvme0n1p2 /dev/nvme1n1p2

# Comprobar el estado
$ cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 nvme1n1p2[1] nvme0n1p2[0]
      976630464 blocks super 1.2 [2/2] [UU]

# Planificador: none, porque son NVMe
$ echo none | sudo tee /sys/block/nvme0n1/queue/scheduler
$ echo none | sudo tee /sys/block/nvme1n1/queue/scheduler

La línea [2/2] [UU] es la que hay que vigilar: dos discos de dos activos, ambos U (up). Si viera [2/1] [U_], el array estaría degradado y habría que sustituir un disco con urgencia.

Y la parte que RAID no cubre: una copia diaria a otro servidor, en otra ubicación física. RAID 1 protege del fallo de un SSD; solo la copia protege de un rm accidental o de un incendio en el rack.

Medición con lsblk e iostat -x

$ lsblk -o NAME,ROTA,SIZE,TYPE,MOUNTPOINT,SCHED
NAME        ROTA   SIZE TYPE  MOUNTPOINT          SCHED
nvme0n1        0 931,5G disk                      none
├─nvme0n1p1    0   512M part  /boot/efi           none
└─nvme0n1p2    0   931G part                      none
  └─md0        0   931G raid1 /var/lib/meteora
nvme1n1        0 931,5G disk                      none
└─nvme1n1p2    0   931G part                      none
  └─md0        0   931G raid1 /var/lib/meteora
sda            1   7,3T disk                      mq-deadline
└─sda1         1   7,3T part  /backup             mq-deadline

De un vistazo tienes la topología completa: dos NVMe formando md0 montado en /var/lib/meteora, un disco mecánico de 7,3 TB para /backup, y el planificador correcto en cada uno.

iostat -x es la herramienta de diagnóstico principal:

$ iostat -x 2 2
Device  r/s     w/s     rkB/s    wkB/s   rrqm/s wrqm/s  r_await w_await aqu-sz  %util
nvme0n1 142,50  388,00  4104,00  9820,00   0,00  12,50    0,08    0,12   0,04   3,20
nvme1n1 138,00  388,00  4020,00  9820,00   0,00  12,50    0,09    0,12   0,04   3,15
md0     280,50  388,00  8124,00  9820,00   0,00   0,00    0,00    0,00   0,00   0,00
sda       2,00  118,50    64,00 18204,00   0,00  84,00   11,20   28,40   3,44  92,10

Columna a columna, con lo que significa cada una:

Columna Qué mide Cuándo preocupa
r/s, w/s Operaciones por segundo (IOPS) Comparar con el máximo del dispositivo
rkB/s, wkB/s Ancho de banda Comparar con el máximo
rrqm/s, wrqm/s Peticiones fusionadas por el núcleo Alto = acceso secuencial (bueno)
r_await, w_await Latencia media en ms, incluida la cola La métrica clave
aqu-sz Longitud media de la cola > 1 sostenido = saturación
%util % de tiempo con al menos una petición en curso Engañosa en NVMe

Lectura de estos datos concretos:

  • nvme0n1 y nvme1n1 tienen cifras casi idénticas, como debe ser en RAID 1: mismas escrituras en ambos, lecturas repartidas.
  • md0 suma las lecturas (280,5 = 142,5 + 138) pero no duplica las escrituras (388), que es exactamente el comportamiento esperado del espejo.
  • r_await de 0,08 ms en los NVMe. Excelente, dentro de lo esperable.
  • sda es el problema: w_await de 28,4 ms, aqu-sz de 3,44 y %util del 92,1 %. El disco de backup está saturado escribiendo 18 MB/s. Como es un disco mecánico con escritura intensiva, es su comportamiento normal, pero conviene que el backup no compita con nada crítico (de ahí el ionice -c 3).
  • wrqm/s de 84 en sda: el núcleo está fusionando muchas peticiones contiguas antes de enviarlas, señal de escritura secuencial. Es lo que se quiere en un disco mecánico.

Un aviso importante sobre %util: en discos mecánicos es fiable (solo pueden servir una petición a la vez, así que el 100 % significa saturación). En NVMe es engañosa: el dispositivo sirve decenas de peticiones en paralelo, así que puede marcar el 100 % estando al 5 % de su capacidad real. En SSD, la métrica de referencia es await, no %util.

$ iostat -x 1 | awk '/^(nvme|sd|md)/ {printf "%-8s await_r=%6.2f await_w=%6.2f cola=%5.2f\n", $1, $10, $11, $21}'

Y para medir la capacidad real del dispositivo antes de poner nada en producción:

$ sudo fio --name=aleatorio4k --filename=/var/lib/meteora/prueba \
    --rw=randread --bs=4k --iodepth=32 --numjobs=4 \
    --size=1G --runtime=30 --group_reporting

read: IOPS=487k, BW=1903MiB/s (1995MB/s)
     lat (usec): min=8, avg=64.21, max=1842

487.000 IOPS aleatorias de 4 KB con 64 µs de latencia media. Compáralo con las ~120 IOPS de un disco mecánico: un factor de 4.000.

Errores Comunes y Consejos

Aplicar la intuición del disco mecánico al SSD. Desfragmentar un SSD no sirve de nada y consume ciclos de escritura. Reordenar peticiones tampoco: en flash no hay distancia. Lo primero al analizar rendimiento es mirar lsblk -o NAME,ROTA y saber con qué estás tratando.

Confiar en %util para SSD. Un NVMe al 100 % de %util puede estar completamente ocioso en términos reales. Usa await y aqu-sz.

Llenar un SSD al máximo. Por encima del 90 % de ocupación, la recolección de basura pierde eficacia y la amplificación de escritura se dispara de 2 a 10. Deja siempre un 10-20 % libre; muchos SSD de servidor lo reservan de fábrica (over-provisioning).

Usar RAID 5 con discos grandes. Con discos de 8 TB, una reconstrucción de 44 horas sin redundancia es un riesgo real de perderlo todo. Para discos de más de 2 TB, RAID 6 o RAID 10.

Confundir RAID con copia de seguridad. RAID protege del fallo de un disco. No protege de borrados accidentales, corrupción lógica, ransomware ni desastres físicos. Son problemas distintos con soluciones distintas.

Olvidar el TRIM. Sin fstrim.timer activo, un SSD acaba con el rendimiento de escritura degradado sin causa aparente. Compruébalo con systemctl status fstrim.timer.

Cambiar el planificador de E/S sin medir. El valor por defecto que elige el núcleo suele ser correcto. Si vas a cambiarlo, mide antes y después con fio o con la carga real; muchos cambios "de optimización" empeoran las cosas.

Consejo de diagnóstico: ante una sospecha de problema de disco, este es el orden que funciona: lsblk -o NAME,ROTA,SCHED (qué tienes), iostat -x 2 (mirar await y aqu-sz), iotop -o (qué proceso está haciendo E/S) y cat /proc/mdstat si hay RAID (¿está degradado?). Y recuerda mirar también la columna b de vmstat: si hay procesos en estado D, ya sabes de la lección 02-01 que están atascados esperando exactamente esto.

Ejercicios

Ejercicio 1: calcular tiempos de acceso a disco

meteo-01 tiene un disco de backup con estas características:

Velocidad: 7.200 RPM
Tiempo de búsqueda medio: 9,0 ms
Tasa de transferencia: 160 MB/s
Sector: 4 KB
  1. Calcula el tiempo de leer un bloque de 4 KB aleatorio.
  2. Calcula el tiempo de leer los 17 MB de 2026-08-31.dat de forma secuencial.
  3. Calcula el tiempo de leer esos mismos 17 MB en bloques de 4 KB dispersos por el disco.
  4. ¿Cuántas IOPS aleatorias de 4 KB ofrece este disco? Compáralo con los 487.000 del NVMe.
  5. Si el agregador tarda 90 segundos en procesar el día leyendo el fichero secuencialmente, ¿qué proporción del tiempo es CPU y qué proporción es disco?

Ejercicio 2: planificación de peticiones de disco

Un disco de 0 a 4.999 cilindros tiene el cabezal en el 2.150 y esta cola de peticiones:

2069, 1212, 2296, 2800, 544, 1618, 356, 1523, 4965, 3681
  1. Calcula el desplazamiento total del cabezal con FCFS, SSTF, SCAN (hacia arriba), C-SCAN (hacia arriba), LOOK (hacia arriba) y C-LOOK (hacia arriba).
  2. Ordénalos de mejor a peor.
  3. ¿Cuál elegirías si el requisito fuera que ninguna petición espere más de 2 recorridos completos? ¿Y si fuera minimizar el tiempo total?
  4. Si este dispositivo fuera un SSD NVMe, ¿cuál sería tu respuesta y por qué?

Ejercicio 3: decidir una configuración RAID

Meteora quiere ampliar el almacenamiento. Tienes 6 discos de 4 TB y estos requisitos:

  • Datos de lecturas (/var/lib/meteora): 500 GB, críticos, escritura secuencial continua, lectura intensiva.
  • Registros y temporales (/var/log, /tmp): 200 GB, reproducibles, escritura intensiva.
  • Archivo histórico (/archivo): 8 TB, se escribe una vez y se lee raramente, importante pero no crítico.
  1. Propón una configuración RAID para cada uno de los tres usos, indicando cuántos discos asignas.
  2. Calcula la capacidad útil de cada volumen.
  3. Justifica cada elección con los criterios de la lección.
  4. Calcula el tiempo de reconstrucción de cada volumen si falla un disco (asume 180 MB/s).
  5. ¿Qué queda sin cubrir por RAID y qué harías al respecto?

Soluciones

Solución 1

1. Bloque de 4 KB aleatorio.

Tiempo de búsqueda:      9,000 ms
Latencia rotacional:     (60.000 ms/min ÷ 7.200 RPM) ÷ 2 = 8,33 ÷ 2 = 4,167 ms
Transferencia:           4 KB ÷ 160 MB/s = 0,0244 ms
                       ─────────
Total:                  13,191 ms

Reparto del tiempo:

Posicionamiento: 13,167 ms = 99,8 %
Transferencia:    0,024 ms =  0,2 %

2. Los 17 MB secuencialmente.

Búsqueda inicial:        9,000 ms
Latencia rotacional:     4,167 ms
Transferencia:           17 MB ÷ 160 MB/s = 106,25 ms
                       ─────────
Total:                  119,42 ms

En la práctica un fichero de 17 MB no está perfectamente contiguo, así que habría alguna búsqueda adicional, pero el orden de magnitud es correcto: unos 120 ms.

3. Los mismos 17 MB en bloques dispersos.

Número de bloques: 17.000.000 ÷ 4.096 = 4.150 bloques
Tiempo: 4.150 × 13,191 ms = 54.743 ms = 54,7 segundos
Patrón Tiempo MB/s efectivos Factor
Secuencial 0,119 s 143 MB/s
Aleatorio 54,7 s 0,31 MB/s 459× peor

El mismo dato, 459 veces más lento. Es la diferencia entre que el agregador termine antes de tomar un café o tarde casi un minuto solo en leer.

4. IOPS aleatorias.

IOPS = 1.000 ms/s ÷ 13,191 ms = 75,8 IOPS

Comparación:

Dispositivo IOPS 4K aleatorias Factor
HDD 7.200 RPM 76
SSD SATA ~90.000 1.184×
SSD NVMe 487.000 6.408×

Ese factor de 6.408 es una de las cifras más importantes de la informática de la última década. Explica por qué bases de datos que eran inviables pasaron a ser triviales, y por qué muchas optimizaciones de software diseñadas para minimizar E/S aleatoria dejaron de tener sentido.

Una lectura complementaria del dato: 76 IOPS significa que ese disco no puede servir ni 76 peticiones aleatorias por segundo. Si meteo-api recibe 40 peticiones/segundo y cada una provoca 2 lecturas aleatorias, ese disco ya está al límite.

5. Reparto CPU/disco en los 90 segundos.

Tiempo de disco (lectura secuencial): 0,119 s
Tiempo total:                        90,000 s
Proporción de disco: 0,119 / 90 = 0,13 %
Proporción de CPU:   99,87 %

El agregador está limitado por CPU, no por disco. Esto confirma cuantitativamente lo que dedujimos en 02-02 a partir de sus cambios de contexto (ratio de 63 a 1 entre voluntarios e involuntarios, muy inferior al de los otros procesos).

La consecuencia práctica es importante: cambiar el disco de backup por un NVMe no aceleraría el agregador en absoluto. Ahorrarías 0,1 segundos de 90. Para acelerarlo hay que optimizar el cálculo, paralelizarlo o darle más CPU. Es el tipo de conclusión que evita gastar dinero en el componente equivocado, y por eso se mide antes de comprar.

Nota: este cálculo cambiaría por completo si el agregador leyera de forma aleatoria. En ese caso serían 54,7 s de disco frente a 90 s totales, un 61 % de disco, y la conclusión se invertiría.

Solución 2

Cola: 2069, 1212, 2296, 2800, 544, 1618, 356, 1523, 4965, 3681. Cabezal en 2150. Disco de 0 a 4999.

Ordenadas: 356, 544, 1212, 1523, 1618, 2069, | 2150 | , 2296, 2800, 3681, 4965

FCFS:

Movimiento Distancia
2150 → 2069 81
2069 → 1212 857
1212 → 2296 1084
2296 → 2800 504
2800 → 544 2256
544 → 1618 1074
1618 → 356 1262
356 → 1523 1167
1523 → 4965 3442
4965 → 3681 1284
Total 13.011

SSTF:

Paso Desde Más cercana Distancia
1 2150 2069 (81) frente a 2296 (146) 81
2 2069 2296 (227) frente a 1618 (451) 227
3 2296 2800 (504) frente a 1618 (678) 504
4 2800 3681 (881) frente a 1618 (1182) 881
5 3681 4965 (1284) frente a 1618 (2063) 1284
6 4965 1618 3347
7 1618 1523 95
8 1523 1212 311
9 1212 544 668
10 544 356 188
Total 7.586

SCAN (hacia arriba, hasta 4999):

2150 → 2296 → 2800 → 3681 → 4965 → 4999 → 2069 → 1618 → 1523 → 1212 → 544 → 356
Tramo Distancia
2150 → 4999 2849
4999 → 356 4643
Total 7.492

C-SCAN (hacia arriba, salto de 4999 a 0):

2150 → ... → 4965 → 4999 → [salto a 0] → 356 → ... → 2069
Tramo Distancia
2150 → 4999 2849
4999 → 0 (retorno) 4999
0 → 2069 2069
Total 9.917

LOOK (hacia arriba, sin llegar al extremo):

2150 → 2296 → 2800 → 3681 → 4965 → 2069 → 1618 → 1523 → 1212 → 544 → 356
Tramo Distancia
2150 → 4965 2815
4965 → 356 4609
Total 7.424

C-LOOK:

2150 → ... → 4965 → [salto a 356] → 356 → ... → 2069
Tramo Distancia
2150 → 4965 2815
4965 → 356 (retorno) 4609
356 → 2069 1713
Total 9.137

2. Ranking:

Puesto Algoritmo Desplazamiento Frente a FCFS
1 LOOK 7.424 −43 %
2 SCAN 7.492 −42 %
3 SSTF 7.586 −42 %
4 C-LOOK 9.137 −30 %
5 C-SCAN 9.917 −24 %
6 FCFS 13.011

3. Elección según el requisito.

Si ninguna petición debe esperar más de dos recorridos completos: SCAN, C-SCAN, LOOK o C-LOOK, todos válidos. Lo determinante es descartar SSTF, que no ofrece esa garantía: si llegaran continuamente peticiones cerca del 2150, la del 4965 podría no servirse nunca. Que en este caso concreto SSTF dé buen resultado no cambia nada; la garantía es sobre el peor caso, no sobre un ejemplo. Entre los cuatro válidos, C-LOOK es la mejor opción si además se quiere que la espera sea uniforme, porque no favorece sistemáticamente ninguna zona del disco.

Si el objetivo es minimizar el tiempo total: LOOK, con 7.424 cilindros. Gana porque no desperdicia movimiento yendo a extremos vacíos (34 cilindros de más en SCAN) ni haciendo el retorno improductivo de las variantes circulares.

Nota metodológica: la diferencia entre LOOK (7.424) y SSTF (7.586) es solo del 2,1 %. Con otra cola SSTF podría ganar. La ventaja sólida de LOOK no es el 2 %, sino la garantía de no inanición al mismo precio.

4. Si fuera un SSD NVMe: none, y ninguno de estos algoritmos.

El razonamiento completo:

  • La métrica pierde el sentido. "Desplazamiento total del cabezal" mide movimiento físico de un brazo. En flash no hay brazo. Acceder al LBA 356 y al 4965 cuesta exactamente lo mismo: unos 50 µs.
  • Reordenar es contraproducente. Ordenar peticiones consume CPU y añade latencia en la cola del núcleo, a cambio de un beneficio que es cero. Estás pagando para no obtener nada.
  • El dispositivo sabe más. El SSD tiene su propia FTL, sus 4-8 canales paralelos y su propio planificador interno, que conoce la ubicación física real —invisible para el núcleo por el nivelado de desgaste—. Cualquier orden que imponga el sistema operativo se basa en una geometría que no existe.
  • NVMe quiere paralelismo, no orden. Con 65.535 colas, lo óptimo es enviar las 10 peticiones a la vez y dejar que el dispositivo las sirva en paralelo por sus distintos canales. Serializarlas en un orden "óptimo" destruye precisamente la ventaja del NVMe.
$ echo none | sudo tee /sys/block/nvme0n1/queue/scheduler

Estimación del resultado: las 10 peticiones, enviadas en paralelo con una latencia de ~50 µs cada una y suficiente paralelismo interno, se completarían en aproximadamente 50-100 µs en total. Con el disco mecánico y LOOK, 7.424 cilindros de desplazamiento suponen del orden de 150-200 ms. Un factor de unas 2.000 veces, obtenido no por planificar mejor sino por dejar de planificar.

Solución 3

1 y 2. Configuración propuesta.

Uso Discos Nivel RAID Capacidad útil Necesita
/var/lib/meteora 2 × 4 TB RAID 1 4 TB 500 GB
/var/log, /tmp (compartido con el anterior) 200 GB
/archivo 4 × 4 TB RAID 5 12 TB 8 TB

Detalle de los cálculos:

RAID 1 con 2 discos:  4 TB × 1 = 4 TB útiles (50 % de 8 TB)
RAID 5 con 4 discos:  4 TB × (4−1) = 12 TB útiles (75 % de 16 TB)
Total útil: 16 TB de 24 TB brutos (66,7 %)

Los datos críticos (500 GB) y los reproducibles (200 GB) caben juntos en el RAID 1 de 4 TB con margen de sobra, en subvolúmenes o particiones lógicas distintas. Dedicar discos aparte a /var/log sería desperdiciar dos discos de 4 TB para 200 GB.

3. Justificación de cada elección.

/var/lib/meteora en RAID 1:

  • Criticidad máxima. Las lecturas perdidas son irrecuperables, así que la redundancia es innegociable.
  • Escritura secuencial continua. RAID 1 cuesta 2 operaciones de E/S por escritura; RAID 5 cuesta 4 (leer dato, leer paridad, escribir dato, escribir paridad). Con el ingestor escribiendo sin parar, esa diferencia se paga cada segundo.
  • Lectura intensiva. RAID 1 permite servir lecturas desde ambos discos en paralelo, lo que beneficia directamente al agregador y a meteo-api.
  • La capacidad sobra. 500 GB de necesidad frente a 4 TB disponibles: no hay ningún argumento para sacrificar rendimiento o simplicidad a cambio de más espacio.

/var/log y /tmp en el mismo RAID 1:

  • Son reproducibles, así que técnicamente RAID 0 bastaría. Pero dedicarles discos propios sería malgastar 8 TB brutos para 200 GB.
  • Convivir con los datos críticos les da redundancia gratis, lo cual es un extra bienvenido: perder los registros justo cuando estás diagnosticando un fallo de disco es exactamente el peor momento posible.
  • Precaución necesaria: /var/log creciendo sin control podría llenar el volumen y bloquear la escritura de lecturas. Hay que ponerle límite con logrotate y journald (SystemMaxUse=), o aislarlo en un subvolumen con cuota.

/archivo en RAID 5:

  • Aquí sí manda la capacidad: 8 TB necesarios de 12 TB útiles. RAID 10 con los mismos 4 discos daría solo 8 TB, justo al límite y sin margen de crecimiento.
  • Se escribe una vez y se lee raramente. La penalización de escritura de RAID 5 es irrelevante en una carga que casi no escribe: es precisamente el escenario para el que RAID 5 fue diseñado.
  • Es importante pero no crítico: si se perdiera, sería recuperable desde los backups y desde el reproceso de los datos originales.
  • Los discos son de 4 TB, no de 8, lo que sitúa la reconstrucción en un rango aceptable, como veremos en el punto siguiente.

4. Tiempos de reconstrucción a 180 MB/s.

RAID 1 (4 TB):

Datos a copiar: 4 TB = 4.000.000 MB
Tiempo = 4.000.000 / 180 = 22.222 s = 6,2 horas

Y con solo 700 GB de datos reales, muchas implementaciones (mdadm con bitmap, o ZFS/btrfs) copian únicamente los bloques usados:

700.000 MB / 180 MB/s = 3.889 s = 1,1 horas

Durante la reconstrucción, el disco superviviente sigue sirviendo peticiones normalmente.

RAID 5 (4 discos de 4 TB):

Hay que leer los 3 discos supervivientes enteros: 3 × 4 TB = 12 TB
Tiempo = 12.000.000 MB / 180 MB/s = 66.667 s = 18,5 horas

Comparación y riesgo:

Volumen Reconstrucción Redundancia durante ella Riesgo
RAID 1 1,1 - 6,2 h Ninguna (queda 1 disco) Bajo: ventana corta
RAID 5 18,5 h Ninguna (tolera 0 fallos más) Moderado: ventana larga con 3 discos bajo carga intensa

Las 18,5 horas de RAID 5 son aceptables —muy lejos de las 44 horas del caso de 8 TB que veíamos en la lección— pero merecen dos precauciones concretas:

# 1. Limitar la velocidad de reconstrucción para no saturar el array
$ echo 100000 | sudo tee /proc/sys/dev/raid/speed_limit_min

# 2. Comprobación semanal de integridad para detectar sectores
#    ilegibles ANTES de que hagan falta en una reconstrucción
$ sudo systemctl enable --now mdcheck_start.timer

# 3. Vigilancia SMART para anticipar fallos
$ sudo smartctl -a /dev/sda | grep -E 'Reallocated|Pending|Uncorrectable'

La comprobación periódica es la más importante de las tres: el escenario que mata a RAID 5 es descubrir un sector ilegible en el disco B justo durante la reconstrucción del disco A. Leer todo el array cada semana detecta esos sectores mientras aún hay redundancia para repararlos.

5. Lo que RAID no cubre.

RAID protege exclusivamente del fallo físico de un disco. Queda fuera:

Amenaza ¿RAID protege? Qué hace falta
Fallo de un disco RAID 1 / 5
rm -rf accidental No Copia con historial
Ransomware No Copia inmutable o desconectada
Corrupción del sistema de archivos No Copia + suma de verificación
Fallo del controlador RAID No Copia en otro sistema
Incendio, robo, inundación No Copia fuera de la ubicación
Bug en el ingestor que escribe basura No Copia con historial

La regla de referencia es 3-2-1: tres copias de los datos, en dos medios distintos, con una fuera del emplazamiento.

Copia 1: RAID 1 en meteo-01                     (producción)
Copia 2: /archivo en el RAID 5, con instantáneas diarias  (mismo edificio, otro volumen)
Copia 3: sincronización nocturna a almacenamiento remoto  (otra ubicación)
# Copia diaria incremental con historial y verificación
$ rsync -avz --link-dest=/backup/anterior \
    /var/lib/meteora/lecturas/ backup@remoto:/backup/meteora/$(date +%F)/

--link-dest crea enlaces duros hacia la copia anterior, de modo que cada día ocupa solo lo que ha cambiado pero se ve como una copia completa e independiente. Con 17 MB diarios, un año de historial diario ocupa unos 6,2 GB en lugar de 6,2 TB.

Y una última pieza que se olvida siempre: una copia de seguridad que no se ha restaurado nunca no es una copia de seguridad, es una esperanza. Hay que programar una restauración de prueba periódica y verificar que los datos recuperados son legibles y correctos.

Conclusión

El almacenamiento es el nivel de la jerarquía donde aparece el abismo: de la RAM al SSD hay un factor de 500, y al disco mecánico de 80.000. Todo el diseño del subsistema de E/S consiste en evitar cruzarlo.

Un disco mecánico gasta el 99,8 % del tiempo posicionándose —búsqueda más latencia rotacional— y solo el 0,2 % transfiriendo, lo que lo hace 168 veces más lento en acceso aleatorio que secuencial. De ahí salen la lectura anticipada, la agrupación de escrituras y toda la planificación de peticiones. Un SSD invierte las reglas: sin partes móviles, el acceso aleatorio cuesta lo mismo que el secuencial, pero introduce restricciones propias —no se puede sobrescribir sin borrar el bloque entero— que obligan a una FTL, a la recolección de basura, al nivelado de desgaste y a TRIM, y que hacen que un SSD casi lleno se comporte mucho peor que uno con espacio. NVMe no es solo un conector más rápido: sustituye una cola por 65.535 y elimina la contención entre núcleos.

Sobre esa física, el sistema operativo levanta la abstracción del dispositivo de bloques direccionado por LBA, con solo cuatro operaciones, que es lo que permite que el mismo código sirva para un disquete y para un array RAID. La planificación de peticiones —FCFS, SSTF, SCAN, C-SCAN, LOOK, C-LOOK— reduce el desplazamiento hasta un 67 %, pero solo tiene sentido si hay un cabezal que mover: en NVMe la elección correcta es none, es decir, no planificar. Los planificadores reales de Linux reflejan exactamente eso, y mq-deadline incorpora además una asimetría muy razonada: las lecturas tienen un plazo diez veces más corto que las escrituras, porque detrás de una lectura casi siempre hay un proceso bloqueado en estado D.

RAID combina discos para capacidad, velocidad o fiabilidad, y la elección depende del patrón: RAID 1 para datos críticos con escritura continua y volumen pequeño —el caso de /var/lib/meteora—, RAID 5 solo con discos moderados y escritura escasa, RAID 6 o 10 cuando la reconstrucción sería larga. Y la advertencia que nunca sobra: RAID no es una copia de seguridad. Finalmente, lsblk te dice qué tienes e iostat -x cómo se comporta, con await como métrica de referencia y %util como trampa en SSD.

Hasta aquí hemos tratado el disco como el dispositivo. Pero un servidor tiene tarjetas de red, terminales, relojes, sensores y controladores de todo tipo, y el sistema operativo tiene que ofrecer una interfaz coherente para todos ellos sin conocer los detalles de ninguno. Cómo lo consigue —la clasificación en dispositivos de bloque, carácter y red, el principio de que todo es un fichero, /dev y udev, y las tres formas que tiene la CPU de hablar con un dispositivo— es lo que veremos en Gestión de Dispositivos.

Fundamentos de Sistemas Operativos

Módulo 1: Introducción a los Sistemas Operativos

Módulo 2: Gestión de Recursos

Módulo 3: Concurrencia

Módulo 4: Estructuras de Archivos

Módulo 5: Protección y Seguridad del Sistema

Módulo 6: Virtualización y Contenedores

Módulo 7: Administración y Diagnóstico en la Práctica

© Copyright 2026. Todos los derechos reservados