Cerramos la lección anterior con una pregunta abierta: hay diez procesos en estado R y cuatro núcleos, ¿a cuál se le da la CPU y durante cuánto tiempo? Esa decisión se toma en meteo-01 varios miles de veces por segundo, y de ella depende que una consulta a meteo-api responda en 8 ms o en 400 ms, que el ingestor no pierda lecturas y que el agregador termine sus medias horarias antes de la hora siguiente.
En esta lección vas a entender por qué hace falta planificar, qué criterios entran en conflicto (porque no se pueden optimizar todos a la vez), cómo funcionan los algoritmos clásicos —calculándolos tú mismo sobre papel, que es la única forma de entenderlos de verdad— y qué hace realmente el planificador de Linux cuando ejecutas renice. Al terminar sabrás decidir con criterio qué prioridad merece cada proceso de Meteora y por qué.
Contenido
- Por qué hace falta planificar: el ciclo de ráfagas
- Procesos limitados por CPU y por E/S
- Los tres planificadores y el despachador
- Criterios de evaluación y sus compromisos
- Planificación apropiativa frente a cooperativa
- FCFS: primero en llegar, primero en servirse
- SJF y SRTF: el trabajo más corto primero
- Planificación por prioridades, inanición y envejecimiento
- Round Robin y el efecto del quantum
- Colas multinivel y colas con realimentación
- El planificador real de Linux: CFS, EEVDF y
nice - Políticas de tiempo real:
SCHED_FIFO,SCHED_RR,SCHED_DEADLINE - Multiprocesador: afinidad y balanceo de carga
Por qué hace falta planificar: el ciclo de ráfagas
Ningún proceso usa la CPU de forma continua. Si observas lo que hace el ingestor, verás un patrón que se repite:
espera datos ── calcula ── escribe ── espera datos ── calcula ── escribe ── (E/S) (CPU) (E/S) (E/S) (CPU) (E/S) 40 ms 0,3 ms 0,8 ms 40 ms 0,3 ms 0,8 ms
Cada tramo de cálculo es una ráfaga de CPU y cada espera es una ráfaga de E/S. Todo proceso alterna entre ambas hasta que termina. Esta observación, que parece trivial, es la base de toda la planificación:
- Si un proceso solo usara la CPU, bastaría con ejecutarlo hasta el final. No haría falta planificar nada.
- Como se bloquea constantemente esperando E/S, deja la CPU libre, y sería un desperdicio no dársela a otro mientras tanto.
La distribución de las ráfagas de CPU en sistemas reales es muy característica: muchísimas ráfagas cortas y poquísimas largas. En una carga típica, el 70-80 % de las ráfagas dura menos de 8 ms. Esto tiene una consecuencia enorme que veremos al hablar de Round Robin: si eliges bien el quantum, la mayoría de procesos terminan su ráfaga antes de agotarlo y se bloquean solos, sin que haya que apropiarles la CPU.
Procesos limitados por CPU y por E/S
Los procesos se clasifican según qué tipo de ráfaga domina en ellos:
| Limitado por E/S (I/O-bound) | Limitado por CPU (CPU-bound) | |
|---|---|---|
| Ráfagas de CPU | Muchas y muy cortas | Pocas y largas |
| Tiempo dominante | Esperando dispositivos | Calculando |
| Ejemplo en Meteora | ingestor, meteo-api |
agregador |
| Cambios de contexto | Muchos voluntarios | Muchos involuntarios |
| Qué necesita | Baja latencia de respuesta | Mucho tiempo de CPU seguido |
| Si se le retrasa | Se pierden datos o la respuesta tarda | Solo termina más tarde |
Esta clasificación no es académica: es la que dicta la decisión operativa. Volvamos a los datos reales que vimos en 02-01:
$ for p in 1842 1877 1901; do
echo -n "PID $p: "
grep -E 'ctxt_switches' /proc/$p/status | tr '\n' ' '
echo
done
PID 1842: voluntary_ctxt_switches: 94013 nonvoluntary_ctxt_switches: 118
PID 1877: voluntary_ctxt_switches: 18422 nonvoluntary_ctxt_switches: 291
PID 1901: voluntary_ctxt_switches: 210884 nonvoluntary_ctxt_switches: 44La lectura es directa:
ingestor(1842): 94.013 bloqueos voluntarios frente a 118 apropiaciones. Ratio de 796 a 1. Fuertemente limitado por E/S: casi siempre está esperando paquetes de las estaciones.meteo-api(1901): ratio de 4.792 a 1. Todavía más extremo. Espera peticiones HTTP.agregador(1877): ratio de 63 a 1. Sigue habiendo E/S (lee ficheros de/var/lib/meteora/lecturas/), pero pasa mucho más tiempo calculando.
Un buen planificador favorece a los procesos limitados por E/S. Puede sonar contraintuitivo —¿por qué priorizar al que menos CPU usa?—, pero la lógica es sólida: si le das la CPU al ingestor en cuanto llegan datos, la usa 0,3 ms y se vuelve a bloquear, liberándola casi de inmediato. El coste de atenderlo pronto es mínimo y el beneficio es que el dispositivo de red vuelve a estar ocupado. Si en cambio le das la CPU al agregador, la retiene milisegundos enteros mientras el ingestor acumula lecturas sin procesar y los búferes de red se llenan.
La regla general: priorizar lo corto mantiene todos los recursos ocupados en paralelo.
Los tres planificadores y el despachador
Un sistema operativo completo no toma una sola decisión de planificación, sino tres, en escalas de tiempo muy distintas:
| Planificador | Qué decide | Frecuencia | ¿Lo tiene Linux? |
|---|---|---|---|
| Largo plazo (admisión) | Qué trabajos entran en el sistema | Segundos o minutos | No como tal |
| Medio plazo (intercambio) | Qué procesos se expulsan a swap | Segundos | Sí, ligado a memoria |
| Corto plazo (CPU) | Qué proceso listo pasa a la CPU | Milisegundos | Sí, es el planificador |
- El de largo plazo viene de los sistemas por lotes de los años 60 (los vimos en 01-02): con memoria escasísima, había que decidir cuántos trabajos admitir simultáneamente. En un Linux moderno no existe: cualquiera puede lanzar un proceso hasta agotar recursos. Lo más parecido son los límites de cgroups (módulo 6) y los sistemas de colas tipo Slurm en supercomputación.
- El de medio plazo sí existe: cuando falta memoria, el núcleo expulsa páginas de procesos inactivos a swap. Lo veremos en Memoria Virtual y Paginación.
- El de corto plazo es del que habla esta lección. Actúa cada pocos milisegundos, y por eso su propio código debe ser extremadamente rápido: si tardara 1 ms en decidir, se comería el 25 % de un quantum de 4 ms.
El despachador (dispatcher) es el componente que ejecuta la decisión: hace el cambio de contexto que estudiamos en 02-01, cambia a modo usuario y salta a la instrucción donde el proceso elegido se quedó. Su tiempo de trabajo se llama latencia de despacho, y en Linux está en el orden de 1-3 µs.
stateDiagram-v2
direction LR
[*] --> ColaListos: nuevo proceso
ColaListos --> CPU: planificador de corto plazo elige
CPU --> ColaListos: fin de quantum
CPU --> ColaEspera: petición de E/S
ColaEspera --> ColaListos: E/S completada
ColaListos --> Suspendido: planificador de medio plazo (swap out)
Suspendido --> ColaListos: swap in
CPU --> [*]: exit()
Criterios de evaluación y sus compromisos
Para comparar algoritmos hacen falta métricas. Estas son las cinco clásicas:
| Criterio | Definición | Se quiere | Interesa sobre todo a |
|---|---|---|---|
| Uso de CPU | % de tiempo que la CPU no está ociosa | Maximizar | El administrador |
| Productividad (throughput) | Procesos completados por unidad de tiempo | Maximizar | Sistemas por lotes |
| Tiempo de retorno (turnaround) | Desde que llega hasta que termina | Minimizar | El usuario final |
| Tiempo de espera | Tiempo total en la cola de listos | Minimizar | Métrica para comparar algoritmos |
| Tiempo de respuesta | Desde que llega hasta la primera reacción | Minimizar | Sistemas interactivos |
Las relaciones entre ellos:
Tiempo de retorno = Tiempo de espera + Tiempo de CPU + Tiempo de E/S Tiempo de espera = Tiempo de retorno − Tiempo de servicio
El tiempo de espera es la métrica que se usa para comparar algoritmos porque es la única parte que el planificador puede influir: el tiempo de CPU y el de E/S los fija el propio trabajo, no la planificación.
Y aquí está lo importante: estos criterios se contradicen entre sí. No existe un algoritmo que los optimice todos.
| Conflicto | Explicación |
|---|---|
| Productividad ↔ Tiempo de respuesta | Cambiar de proceso a menudo mejora la respuesta pero gasta CPU en cambios de contexto |
| Tiempo medio ↔ Varianza | Un algoritmo puede dar buena media siendo terrible para algunos procesos concretos |
| Justicia ↔ Eficiencia | Repartir por igual perjudica al que más lo necesita |
| Prioridad ↔ Inanición | Favorecer a unos condena a otros |
En Meteora esto es una decisión de negocio, no técnica: si optimizas la productividad total, el agregador acabará antes pero meteo-api responderá con picos de latencia. Si optimizas el tiempo de respuesta, la API va fina y el agregador tarda más en cerrar la hora. Hay que elegir, y elegir requiere saber qué duele más si falla.
Planificación apropiativa frente a cooperativa
Ya introdujimos ambas en 01-03. Ahora podemos precisar cuándo el planificador puede actuar. Hay cuatro momentos:
- El proceso pasa de Ejecutando a Bloqueado (pide E/S).
- El proceso pasa de Ejecutando a Listo (se agota el quantum, llega una interrupción).
- El proceso pasa de Bloqueado a Listo (termina su E/S).
- El proceso termina.
Si el planificador solo actúa en los casos 1 y 4 —cuando el proceso suelta la CPU por voluntad propia—, es cooperativo (o no apropiativo). Si también actúa en 2 y 3, es apropiativo.
| Cooperativa | Apropiativa | |
|---|---|---|
| Quién suelta la CPU | El propio proceso | El núcleo puede quitársela |
| Requiere hardware | Nada especial | Temporizador programable |
| Un bucle infinito | Cuelga el sistema | No afecta a los demás |
| Coste | Mínimo | Cambios de contexto frecuentes |
| Datos compartidos | Seguros por construcción | Necesitan sincronización |
| Sistemas | Windows 3.1, Mac OS 9, corrutinas | Todos los SO modernos |
La apropiación es lo que hace posible que en meteo-01 un agregador con un bucle mal escrito no bloquee toda la máquina. El precio a pagar es que los datos compartidos entre procesos pueden quedar en estados inconsistentes si se les interrumpe a medias, y ese precio es exactamente lo que estudiaremos en el módulo 3.
FCFS: primero en llegar, primero en servirse
El más simple: una cola FIFO. El primero que llega, el primero que se ejecuta, y hasta que no acaba su ráfaga no entra otro. Es no apropiativo.
Trabajemos con este conjunto de procesos, que reutilizaremos en todos los algoritmos:
| Proceso | Llegada | Ráfaga de CPU |
|---|---|---|
P1 (agregador) |
0 | 24 ms |
P2 (ingestor) |
1 | 3 ms |
P3 (meteo-api) |
2 | 3 ms |
Diagrama de Gantt con FCFS:
Cálculo paso a paso:
| Proceso | Llegada | Inicio | Fin | Retorno (Fin−Llegada) | Espera (Retorno−Ráfaga) |
|---|---|---|---|---|---|
| P1 | 0 | 0 | 24 | 24 | 0 |
| P2 | 1 | 24 | 27 | 26 | 23 |
| P3 | 2 | 27 | 30 | 28 | 25 |
Tiempo medio de espera = (0 + 23 + 25) / 3 = 16,00 ms Tiempo medio de retorno = (24 + 26 + 28) / 3 = 26,00 ms
Ahora invirtamos el orden de llegada: que lleguen primero P2 y P3, y P1 al final.
| Proceso | Espera |
|---|---|
| P2 | 0 |
| P3 | 2 |
| P1 | 4 |
De 16 ms a 2 ms sin cambiar el algoritmo, solo el orden de llegada. Esa sensibilidad extrema es el gran defecto de FCFS.
El efecto convoy
El fenómeno tiene nombre: efecto convoy. Un proceso largo limitado por CPU ocupa el procesador, y detrás se acumula una fila de procesos cortos limitados por E/S que solo necesitarían unos microsegundos. Mientras esperan, los dispositivos de E/S están ociosos, porque los procesos que los usarían están en la cola.
En términos de Meteora: si el agregador arranca su cálculo horario de 24 ms y detrás se ponen en cola 40 peticiones a meteo-api de 0,5 ms cada una, la última espera 24 ms para hacer un trabajo de medio milisegundo. Y durante esos 24 ms, la tarjeta de red no tiene nada que enviar.
La imagen mental es exacta: un camión lento en una carretera de un solo carril con 40 coches detrás.
SJF y SRTF: el trabajo más corto primero
Si el problema es que los largos bloquean a los cortos, la solución obvia es ejecutar primero el más corto. Eso es SJF (Shortest Job First).
Con nuestros procesos y suponiendo que todos han llegado en t=0:
Media de espera: 2,00 ms. Y esto no es casualidad:
SJF es demostrablemente óptimo: ningún algoritmo puede dar un tiempo medio de espera menor para un conjunto dado de procesos.
La intuición de la demostración: si un proceso largo va antes que uno corto, intercambiarlos reduce la espera del corto en mucho y aumenta la del largo en poco. Repitiendo el intercambio se llega al orden ascendente.
SRTF: la versión apropiativa
SRTF (Shortest Remaining Time First) añade apropiación: si llega un proceso cuya ráfaga es menor que lo que le queda al actual, se le quita la CPU.
Un ejemplo con llegadas escalonadas:
| Proceso | Llegada | Ráfaga |
|---|---|---|
| A | 0 | 8 |
| B | 1 | 4 |
| C | 2 | 9 |
| D | 3 | 5 |
Simulación instante a instante:
- t=0: solo A. Ejecuta A (le quedan 8).
- t=1: llega B con 4 < 7 restantes de A. Apropiación: entra B.
- t=2: llega C con 9 > 3 restantes de B. Sigue B.
- t=3: llega D con 5 > 2 restantes de B. Sigue B.
- t=5: B termina. Candidatos: A (7), C (9), D (5). Entra D.
- t=10: D termina. Candidatos: A (7), C (9). Entra A.
- t=17: A termina. Entra C.
- t=26: C termina.
| Proceso | Llegada | Fin | Retorno | Ráfaga | Espera |
|---|---|---|---|---|---|
| A | 0 | 17 | 17 | 8 | 9 |
| B | 1 | 5 | 4 | 4 | 0 |
| C | 2 | 26 | 24 | 9 | 15 |
| D | 3 | 10 | 7 | 5 | 2 |
Comparado con FCFS sobre el mismo conjunto (que daría 7,75 ms) es mejor, y SRTF es óptimo entre los apropiativos.
El problema insalvable de SJF
Requiere conocer la duración de la próxima ráfaga, que es el futuro. No hay forma de saberla.
La solución práctica es estimarla a partir del historial, con una media exponencial:
donde t(n) es la duración real de la última ráfaga, τ(n) la estimación anterior y α un peso entre 0 y 1 (típicamente 0,5).
Ejemplo numérico con α = 0,5 y estimación inicial τ = 10:
Ráfaga real t |
Cálculo | Nueva estimación τ |
|---|---|---|
| 6 | 0,5·6 + 0,5·10 | 8,0 |
| 4 | 0,5·4 + 0,5·8 | 6,0 |
| 6 | 0,5·6 + 0,5·6 | 6,0 |
| 4 | 0,5·4 + 0,5·6 | 5,0 |
| 13 | 0,5·13 + 0,5·5 | 9,0 |
Observa el comportamiento: la estimación converge suavemente y reacciona ante el cambio brusco de la última ráfaga sin dispararse del todo. Con α = 1 solo contaría la última ráfaga (muy reactivo, muy inestable); con α = 0 nunca cambiaría.
Segundo problema de SJF: inanición. Un proceso largo puede no ejecutarse nunca si no dejan de llegar procesos cortos. En un sistema con meteo-api recibiendo peticiones constantes, el agregador podría no arrancar jamás.
Planificación por prioridades, inanición y envejecimiento
Se asigna un número de prioridad a cada proceso y se elige el de mayor prioridad. SJF es en realidad un caso particular: la prioridad es la inversa de la duración de la ráfaga.
Con este conjunto (menor número = mayor prioridad, convención habitual):
| Proceso | Ráfaga | Prioridad |
|---|---|---|
| P1 | 10 | 3 |
| P2 | 1 | 1 |
| P3 | 2 | 4 |
| P4 | 1 | 5 |
| P5 | 5 | 2 |
| Proceso | Espera |
|---|---|
| P2 | 0 |
| P5 | 1 |
| P1 | 6 |
| P3 | 16 |
| P4 | 18 |
Las prioridades pueden asignarse por criterios internos (tamaño de memoria, ratio de E/S, tiempo consumido) o externos (importancia del usuario, dinero pagado, criticidad del servicio).
Inanición y envejecimiento
El problema es el mismo que en SJF: un proceso de prioridad baja puede esperar indefinidamente. La anécdota clásica —quizá apócrifa, pero muy ilustrativa— cuenta que al apagar el IBM 7094 del MIT en 1973 encontraron un trabajo de prioridad baja enviado en 1967 que nunca llegó a ejecutarse.
La solución es el envejecimiento (aging): incrementar gradualmente la prioridad de los procesos que llevan mucho tiempo esperando.
Prioridad inicial del agregador: 15 (baja) Regla: +1 de prioridad por cada segundo esperando t=0 s: prioridad 15 — no se ejecuta t=5 s: prioridad 10 — sigue sin ejecutarse t=10 s: prioridad 5 — empieza a competir t=14 s: prioridad 1 — se ejecuta seguro
Con esta regla, ningún proceso espera más de 14 segundos por muy baja que sea su prioridad. El envejecimiento convierte una garantía imposible ("todos se ejecutan") en una acotada ("nadie espera más de X"), que es la clase de garantía con la que sí se puede trabajar.
Round Robin y el efecto del quantum
Round Robin es FCFS con apropiación por tiempo: cada proceso recibe un quantum fijo; si no termina, vuelve al final de la cola.
Con nuestros tres procesos originales (P1=24, P2=3, P3=3) y quantum = 4 ms:
| Proceso | Fin | Retorno | Ráfaga | Espera |
|---|---|---|---|---|
| P1 | 30 | 30 | 24 | 6 |
| P2 | 7 | 6 | 3 | 3 |
| P3 | 10 | 8 | 3 | 5 |
Peor que SJF (2,00 ms), pero muchísimo mejor que FCFS (16,00 ms). Y, sobre todo, con una propiedad que los otros no tienen: el tiempo de respuesta está acotado. Con n procesos y quantum q, ninguno espera más de (n−1)·q para su primer turno. Con 10 procesos y q=4 ms, la peor espera es 36 ms. Eso es una garantía útil para un sistema interactivo.
El efecto del quantum
Elegir q es un compromiso directo:
| Quantum | Comportamiento | Sobrecoste de cambios | Se parece a |
|---|---|---|---|
| Muy grande (∞) | Cada proceso corre hasta bloquearse | Nulo | FCFS |
| Grande (100 ms) | Respuesta lenta | Bajo | FCFS suavizado |
| Medio (4-10 ms) | Equilibrado | Aceptable | Round Robin útil |
| Pequeño (1 ms) | Muy reactivo | Notable | — |
| Minúsculo (10 µs) | La CPU se dedica a cambiar de proceso | Ruinoso | Nada útil |
Con el coste de cambio de contexto de 5 µs que calculamos en 02-01:
| Quantum | Sobrecoste | Trabajo útil |
|---|---|---|
| 100 µs | 5/105 = 4,8 % | 95,2 % |
| 1 ms | 5/1005 = 0,50 % | 99,5 % |
| 4 ms | 5/4005 = 0,12 % | 99,88 % |
| 100 ms | 5/100005 = 0,005 % | 99,995 % |
La regla práctica: el quantum debe ser lo bastante grande para que el 80 % de las ráfagas de CPU terminen dentro de él. Como la mayoría de ráfagas duran menos de 8 ms, un quantum de esa magnitud consigue que la mayoría de procesos se bloqueen solos y la apropiación sea la excepción, no la norma.
Un matiz importante: el tiempo de retorno no mejora monótonamente al reducir el quantum. Puede empeorar, porque un proceso que necesitaría 7 ms seguidos con q=7 termina de una vez, y con q=2 necesita cuatro turnos repartidos.
Colas multinivel y colas con realimentación
Los algoritmos anteriores tratan a todos los procesos igual. En la realidad no lo son: un proceso interactivo y un proceso por lotes necesitan políticas distintas.
En las colas multinivel, la cola de listos se divide en varias colas, cada una con su propio algoritmo:
Prioridad 0 (máxima) │ Procesos de sistema │ Round Robin q=1ms Prioridad 1 │ Procesos interactivos │ Round Robin q=4ms Prioridad 2 │ Procesos de edición │ Round Robin q=8ms Prioridad 3 (mínima) │ Procesos por lotes │ FCFS
Entre colas se planifica normalmente por prioridad absoluta: nada de la cola 2 se ejecuta si hay algo en la 0 o la 1. Esto es rápido pero causa inanición. La alternativa es repartir porcentajes de CPU: 60 % a la cola 0, 25 % a la 1, 10 % a la 2 y 5 % a la 3.
El problema de las colas multinivel puras: un proceso queda fijado a su cola para siempre, y su naturaleza puede cambiar. El agregador es limitado por CPU mientras calcula, pero limitado por E/S mientras lee ficheros.
Las colas multinivel con realimentación (multilevel feedback queue) resuelven eso permitiendo que los procesos suban y bajen de cola según su comportamiento observado:
flowchart TD
N[Proceso nuevo] --> Q0
Q0["Cola 0 — RR, quantum 8 ms"] -->|agota el quantum| Q1
Q0 -->|se bloquea por E/S| B0[Sale a espera]
Q1["Cola 1 — RR, quantum 16 ms"] -->|agota el quantum| Q2
Q1 -->|se bloquea por E/S| B1[Sale a espera y sube a Cola 0]
Q2["Cola 2 — FCFS"] -->|envejecimiento| Q1
B0 --> Q0
B1 --> Q0
La lógica es elegante:
- Todo proceso empieza arriba, con la máxima prioridad y el quantum más corto.
- Si agota su quantum sin bloquearse, es señal de que está limitado por CPU: baja una cola, donde tendrá menos prioridad pero un quantum más largo (que es lo que le conviene).
- Si se bloquea por E/S antes de agotarlo, es interactivo: se mantiene o sube.
- El envejecimiento sube los procesos que llevan mucho esperando abajo, evitando la inanición.
Este esquema deduce del comportamiento lo que no puede saber de antemano: aproxima SJF sin necesidad de adivinar el futuro. Fue el diseño de los planificadores de UNIX tradicionales, de Windows NT y del planificador O(1) de Linux hasta 2007.
El planificador real de Linux: CFS, EEVDF y nice
Linux abandonó el enfoque de colas con realimentación en la versión 2.6.23 (2007) por el CFS (Completely Fair Scheduler), y desde la 6.6 (2023) por EEVDF (Earliest Eligible Virtual Deadline First), que refina la misma idea.
El punto de partida del CFS es distinto y muy potente: en lugar de quanta fijos y colas, modela cuánta CPU le correspondería a cada proceso en una máquina ideal y corrige la desviación.
- Si hay n procesos ejecutables, cada uno debería tener 1/n de la CPU.
- CFS lleva la cuenta del tiempo virtual de ejecución (
vruntime) de cada proceso: el tiempo de CPU que ha consumido, ponderado por su prioridad. - Siempre elige el proceso con menor
vruntime, es decir, el que va más rezagado respecto a su parte justa. - Los procesos se almacenan en un árbol rojo-negro ordenado por
vruntime, así que elegir el siguiente es coger el nodo más a la izquierda: O(1) en la práctica, O(log n) al insertar.
La consecuencia bonita: un proceso que se bloquea por E/S no acumula vruntime mientras espera, así que cuando despierta tiene el vruntime más bajo de todos y se ejecuta inmediatamente. Los procesos interactivos obtienen buena respuesta sin ninguna heurística especial: sale gratis del modelo.
nice y la ponderación
El valor nice va de −20 (máxima prioridad) a +19 (mínima), con 0 por defecto. El nombre viene de "cuán amable eres con los demás": un nice alto significa que cedes el paso.
En CFS, nice no da turnos extra: modifica el ritmo al que avanza el vruntime.
Cada unidad de nice cambia el peso en un factor de aproximadamente 1,25, lo que se traduce en una regla muy fácil de recordar:
Cada punto de
nicecambia la cuota de CPU en torno a un 10 %.
nice |
Peso interno | Cuota con otro proceso a nice 0 |
|---|---|---|
| −20 | 88.761 | 98,8 % |
| −10 | 9.548 | 90,3 % |
| −5 | 3.121 | 75,3 % |
| 0 | 1.024 | 50 % |
| +5 | 335 | 24,7 % |
| +10 | 110 | 9,7 % |
| +19 | 15 | 1,4 % |
Aplicado a Meteora:
$ ps -eo pid,ni,pri,comm -u meteora
PID NI PRI COMMAND
1842 -5 24 ingestor
1877 5 14 agregador
1901 0 19 meteo-api
$ sudo renice -n 10 -p 1877
1877 (proceso ID) prioridad antigua 5, prioridad nueva 10
$ nice -n 15 /opt/meteora/bin/reproceso-historico --desde 2026-01-01Qué hace cada orden:
renice -n 10 -p 1877rebaja elagregadoranice10. Ahora, compitiendo conmeteo-api(nice 0), recibirá aproximadamente un 9,7 % de la CPU cuando ambos quieran ejecutarse. Cuandometeo-apiesté bloqueado esperando peticiones —que es casi siempre—, elagregadorusará el 100 %. Esta es la clave que mucha gente no capta:niceno limita el consumo, solo decide quién cede en caso de conflicto. Para limitar de verdad hacen falta cgroups (06-02).nice -n 15 ...lanza el reproceso histórico con prioridad mínima. Es la orden correcta para trabajos pesados que no deben molestar: consumirá toda la CPU sobrante y se apartará al instante en cuanto llegue una petición.- Bajar el
nice(valores negativos) requiere privilegios de root, porque de lo contrario cualquier usuario podría monopolizar el sistema.
Un aviso importante sobre nice que casi siempre pilla desprevenido: solo afecta a la CPU. Si el agregador satura el disco leyendo /var/lib/meteora/lecturas/, renice no arreglará nada. Para eso existe ionice, que veremos en Gestión de Almacenamiento.
Políticas de tiempo real: SCHED_FIFO, SCHED_RR, SCHED_DEADLINE
Linux implementa varias políticas de planificación que conviven. nice solo aplica a la primera:
| Política | Tipo | Prioridad | Comportamiento |
|---|---|---|---|
SCHED_OTHER |
Normal | nice −20..+19 |
CFS/EEVDF, reparto justo |
SCHED_BATCH |
Normal | nice |
Como OTHER pero se asume no interactivo |
SCHED_IDLE |
Normal | Mínima absoluta | Solo con CPU totalmente ociosa |
SCHED_FIFO |
Tiempo real | 1..99 | Ejecuta hasta bloquearse o ceder. Sin quantum |
SCHED_RR |
Tiempo real | 1..99 | Como FIFO pero con quantum entre iguales |
SCHED_DEADLINE |
Tiempo real | Por encima de todo | Se declaran plazo, periodo y tiempo de cómputo |
Regla de oro: cualquier proceso de tiempo real desplaza a todos los normales. Un SCHED_FIFO de prioridad 1 se ejecuta antes que un SCHED_OTHER de nice −20.
$ chrt -p 1842 pid 1842's current scheduling policy: SCHED_OTHER pid 1842's current scheduling priority: 0 $ sudo chrt -f -p 10 1842 $ chrt -p 1842 pid 1842's current scheduling policy: SCHED_FIFO pid 1842's current scheduling priority: 10
Con esto el ingestor pasa a SCHED_FIFO con prioridad 10: en cuanto tenga un paquete que procesar, desplaza a agregador y meteo-api inmediatamente.
¿Es buena idea? Con matices. SCHED_FIFO es adecuado aquí porque el ingestor está limitado por E/S: usa la CPU 0,3 ms y se bloquea. Pero conlleva un peligro real: un SCHED_FIFO que entre en un bucle infinito bloquea su núcleo por completo, y no podrás ni abrir una shell para matarlo. Linux se protege parcialmente con:
Los procesos de tiempo real pueden usar como máximo 950.000 µs de cada 1.000.000 µs, es decir el 95 %. El 5 % restante queda reservado para que el sistema siga siendo administrable. Es una red de seguridad diseñada exactamente para el escenario del bucle infinito.
SCHED_DEADLINE es más moderno y más seguro: en lugar de una prioridad, declaras "necesito 2 ms de cómputo cada 10 ms, con plazo a los 8 ms" y el núcleo rechaza la petición si no puede garantizarlo. El detalle de estas garantías corresponde a Sistemas Operativos Móviles y de Tiempo Real.
Multiprocesador: afinidad y balanceo de carga
meteo-01 tiene 4 núcleos, así que en realidad hay que decidir qué proceso y en qué núcleo.
Linux mantiene una cola de ejecución por núcleo, no una global. Es una decisión deliberada: una cola global necesitaría un cerrojo compartido por todos los núcleos, y ese cerrojo se convertiría en el cuello de botella del sistema con 64 o 128 núcleos.
Dos conceptos gobiernan el reparto:
Afinidad de procesador. Cuando un proceso lleva un rato en el núcleo 2, las cachés L1 y L2 de ese núcleo están llenas de sus datos. Migrarlo al núcleo 3 significa empezar en frío: cientos de fallos de caché a ~100 ns cada uno. Por eso el planificador prefiere mantener cada proceso donde estaba (afinidad blanda), y solo migra cuando el desequilibrio lo justifica.
La afinidad dura se fija a mano:
$ taskset -cp 1877 pid 1877's current affinity list: 0-3 $ sudo taskset -cp 2,3 1877 pid 1877's new affinity list: 2,3 $ sudo taskset -c 0,1 /opt/meteora/bin/ingestor --puerto 9010
Con esto has particionado la máquina: el agregador solo puede usar los núcleos 2 y 3, y el ingestor los 0 y 1. Ni siquiera compiten. Es una técnica válida cuando conoces bien la carga, y se usa mucho en sistemas de baja latencia, pero tiene un coste: si el ingestor está ocioso, sus dos núcleos se desperdician porque el agregador no puede tocarlos. La afinidad dura cambia flexibilidad por previsibilidad.
Balanceo de carga. Periódicamente, el núcleo comprueba si unas colas están mucho más cargadas que otras y migra procesos. Lo hace teniendo en cuenta la topología: migrar entre dos núcleos que comparten caché L3 es barato; migrar entre dos sockets NUMA distintos es caro, porque además de la caché fría, el proceso quedaría accediendo a memoria de otro socket.
$ nproc 4 $ mpstat -P ALL 1 1 CPU %usr %nice %sys %iowait %idle all 23,1 4,2 6,3 1,8 64,6 0 31,2 0,0 8,1 3,0 57,7 1 28,9 0,0 7,2 2,1 61,8 2 16,4 16,8 4,9 0,9 61,0 3 15,9 0,0 5,0 1,2 77,9
Interpretación: la columna %nice mide el tiempo consumido por procesos con nice positivo. Ese 16,8 % en el núcleo 2 es exactamente el agregador con su nice 10, y confirma que la afinidad está haciendo lo que le pedimos. El %iowait bajo indica que el disco no es el cuello de botella hoy.
Errores Comunes y Consejos
Creer que nice limita el consumo de CPU. No lo hace. Un proceso con nice 19 usará el 100 % de la CPU si nadie más la quiere. nice solo decide quién cede en caso de conflicto. Para poner un techo real necesitas cgroups (CPUQuota en systemd), tema de 06-02.
Poner procesos en SCHED_FIFO "por si acaso". Es la forma más rápida de dejar una máquina inaccesible. Solo tiene sentido para procesos que se bloquean con frecuencia y de forma demostrada. Y antes de hacerlo, prueba con nice -20: casi siempre es suficiente.
Confundir prioridad PRI con NI. NI es lo que tú pides; PRI es lo que el núcleo calcula a partir de ello. Además, ps muestra PRI con una escala invertida respecto a la interna del núcleo, lo que despista mucho. Para saber lo que pasa, mira NI y la política (chrt -p).
Aplicar el diagrama de Gantt del examen a la realidad. Los ejercicios asumen una ráfaga por proceso y ninguna E/S. En la realidad cada proceso alterna decenas de ráfagas, entran y salen procesos nuevos y hay varios núcleos. Los cálculos sirven para entender los algoritmos, no para predecir tiempos reales.
Buscar el algoritmo óptimo. No existe. SJF minimiza la espera media pero causa inanición y necesita adivinar el futuro. Round Robin acota la respuesta pero empeora la media. La pregunta correcta nunca es "cuál es mejor", sino "qué me duele más si va mal: la latencia de meteo-api o el retraso del agregador".
Olvidar que un proceso bloqueado no compite. Es el error de razonamiento más frecuente al analizar carga real. Si meteo-api está el 99 % del tiempo esperando peticiones, darle nice -10 casi no cambia nada, porque cuando quiere CPU normalmente está libre.
Consejo práctico: antes de tocar prioridades, comprueba que la CPU es de verdad el problema. Mira %iowait en mpstat y la columna b de vmstat: si hay procesos bloqueados y %iowait alto, el cuello de botella es el disco y ninguna prioridad de CPU lo arreglará.
Ejercicios
Ejercicio 1: comparar cuatro algoritmos numéricamente
Sobre meteo-01 llegan estos cuatro trabajos:
| Proceso | Llegada | Ráfaga (ms) |
|---|---|---|
P1 (agregador) |
0 | 10 |
P2 (meteo-api) |
1 | 2 |
P3 (ingestor) |
2 | 4 |
P4 (limpieza) |
3 | 6 |
Calcula el diagrama de Gantt y el tiempo medio de espera para: (a) FCFS, (b) SJF no apropiativo, (c) SRTF, (d) Round Robin con quantum 3 ms. Después indica qué algoritmo elegirías para Meteora y por qué.
Ejercicio 2: decidir prioridades reales
En meteo-01 (4 núcleos) tienes esta situación durante el pico de las 8:00, cuando las estaciones envían su ráfaga matinal:
ingestor: recibe 800 lecturas/segundo. Si su búfer de socket se llena, se pierden lecturas irrecuperablemente.meteo-api: 40 peticiones/segundo, con un objetivo de servicio de 200 ms en el percentil 99.agregador: calcula las medias de la hora anterior. Debe terminar antes de las 9:00.backup-diario: comprime/var/lib/meteora/lecturas/hacia otro servidor. Tarda 25 minutos y no tiene plazo estricto.
Decide política y prioridad para cada uno, escribe las órdenes concretas y justifica cada decisión. Indica también qué riesgo introduce tu configuración.
Ejercicio 3: calcular el impacto del quantum
Un sistema tiene 12 procesos ejecutables. El coste del cambio de contexto es de 6 µs. El 75 % de las ráfagas de CPU dura menos de 5 ms.
- Calcula el sobrecoste porcentual y el tiempo máximo de respuesta con quantum de 500 µs, 5 ms y 50 ms.
- ¿Cuál elegirías para un servidor donde
meteo-apidebe responder por debajo de 200 ms? - Si la máquina pasara a tener 200 procesos ejecutables, ¿cambiaría tu respuesta?
Soluciones
Solución 1
(a) FCFS — por orden de llegada: P1, P2, P3, P4.
| Proceso | Llegada | Inicio | Fin | Espera (Inicio−Llegada) |
|---|---|---|---|---|
| P1 | 0 | 0 | 10 | 0 |
| P2 | 1 | 10 | 12 | 9 |
| P3 | 2 | 12 | 16 | 10 |
| P4 | 3 | 16 | 22 | 13 |
(b) SJF no apropiativo — al elegir, se toma el más corto de los que ya han llegado.
- t=0: solo P1. Ejecuta P1 hasta t=10 (no apropiativo).
- t=10: han llegado P2 (2), P3 (4), P4 (6). El más corto es P2 → hasta t=12.
- t=12: P3 (4) frente a P4 (6). Entra P3 → hasta t=16.
- t=16: P4 → hasta t=22.
Coincide con FCFS por casualidad, porque P1 acaparó el principio:
Este resultado es instructivo: SJF no apropiativo no ayuda si el trabajo largo llega primero. Su ventaja solo aparece cuando hay elección real.
(c) SRTF (apropiativo):
- t=0: P1 (10). Ejecuta P1.
- t=1: llega P2 (2) < 9 restantes de P1. Apropiación → P2.
- t=2: llega P3 (4) > 1 restante de P2. Sigue P2.
- t=3: P2 termina. Candidatos: P1 (9), P3 (4), P4 (6). Entra P3.
- t=7: P3 termina. Candidatos: P1 (9), P4 (6). Entra P4.
- t=13: P4 termina. Entra P1.
- t=22: P1 termina.
| Proceso | Llegada | Fin | Retorno | Ráfaga | Espera |
|---|---|---|---|---|---|
| P1 | 0 | 22 | 22 | 10 | 12 |
| P2 | 1 | 3 | 2 | 2 | 0 |
| P3 | 2 | 7 | 5 | 4 | 1 |
| P4 | 3 | 13 | 10 | 6 | 4 |
(d) Round Robin, q=3 ms. Cola inicial: P1. Se van incorporando al final conforme llegan.
- t=0-3: P1 (le quedan 7). Al terminar el turno ya han llegado P2, P3, P4 → cola: P2, P3, P4, P1.
- t=3-5: P2 (necesita 2, termina antes del quantum). Cola: P3, P4, P1.
- t=5-8: P3 (le queda 1). Cola: P4, P1, P3.
- t=8-11: P4 (le quedan 3). Cola: P1, P3, P4.
- t=11-14: P1 (le quedan 4). Cola: P3, P4, P1.
- t=14-15: P3 termina.
- t=15-18: P4 termina.
- t=18-22: P1 termina.
| Proceso | Llegada | Fin | Retorno | Ráfaga | Espera |
|---|---|---|---|---|---|
| P1 | 0 | 22 | 22 | 10 | 12 |
| P2 | 1 | 5 | 4 | 2 | 2 |
| P3 | 2 | 15 | 13 | 4 | 9 |
| P4 | 3 | 18 | 15 | 6 | 9 |
Comparación final:
| Algoritmo | Espera media | Peor espera individual |
|---|---|---|
| FCFS | 8,00 ms | 13 ms (P4) |
| SJF | 8,00 ms | 13 ms (P4) |
| SRTF | 4,25 ms | 12 ms (P1) |
| Round Robin q=3 | 8,00 ms | 12 ms (P1) |
Qué elegiría para Meteora: ninguno de los cuatro puros, sino Round Robin con prioridades, que es esencialmente lo que hace CFS. El razonamiento:
- SRTF gana en la media, pero es inaplicable: no se conoce la duración de las ráfagas y, sobre todo, condenaría al
agregadora la inanición cuandometeo-apirecibiera peticiones continuas. - FCFS provocaría el efecto convoy: los 10 ms del
agregadorbloquearían todas las peticiones a la API. - Round Robin puro trata igual a los cuatro, cuando
ingestoryagregadortienen necesidades opuestas.
La configuración práctica sería Round Robin con nice diferenciado: ingestor en −5, meteo-api en 0, agregador en 10 y limpieza en 19. Nótese además que estos cálculos suponen un solo núcleo; con los 4 de meteo-01 los cuatro procesos correrían casi en paralelo y la espera media caería drásticamente en todos los algoritmos.
Solución 2
Análisis previo. Lo primero es clasificar por coste del retraso, no por importancia percibida:
| Proceso | Tipo | Coste de retrasarlo |
|---|---|---|
ingestor |
E/S, ráfagas mínimas | Irreversible: datos perdidos |
meteo-api |
E/S, ráfagas cortas | Contractual: incumplir el objetivo de 200 ms |
agregador |
CPU, ráfagas largas | Recuperable: basta con acabar antes de las 9:00 |
backup-diario |
CPU + disco | Ninguno: puede correr cuando sobre tiempo |
Configuración propuesta:
# 1. ingestor: máxima prioridad normal. Perder lecturas es irreversible. $ sudo renice -n -10 -p $(pgrep -f ingestor) # 2. meteo-api: prioridad ligeramente elevada. $ sudo renice -n -3 -p $(pgrep -f meteo-api) # 3. agregador: prioridad baja, confinado a 2 de los 4 núcleos. $ sudo renice -n 10 -p $(pgrep -f agregador) $ sudo taskset -cp 2,3 $(pgrep -f agregador) # 4. backup: prioridad mínima de CPU y de disco. $ sudo renice -n 19 -p $(pgrep -f backup-diario) $ sudo ionice -c 3 -p $(pgrep -f backup-diario)
Justificación de cada decisión:
-
ingestoranice −10, no aSCHED_FIFO. Connice −10obtiene un 90 % de la CPU frente a un proceso normal en caso de conflicto, más que suficiente para un proceso que solo usa 0,3 ms por lectura.SCHED_FIFOdaría una garantía más fuerte pero introduciría el riesgo de bloquear un núcleo entero si elingestortuviera un fallo. La regla es no usar tiempo real sinicebasta, y aquí basta con holgura. -
meteo-apianice −3. Necesita responder rápido, pero está limitado por E/S: pasa casi todo el tiempo bloqueado, y cuando despierta CFS ya le da preferencia por tener elvruntimemás bajo. Un empujón moderado es suficiente y evita que compita con elingestor. -
agregadoranice 10y confinado a 2 núcleos. Es el único limitado por CPU y el que puede dañar a los demás. Connice 10recibe un ~10 % en conflicto y el 100 % cuando los otros duermen, que es casi siempre. Confinarlo a los núcleos 2 y 3 garantiza que los núcleos 0 y 1 estén siempre disponibles para el pico de las 8:00. Como debe terminar en una hora y su cálculo real dura minutos, tiene margen de sobra. -
backup-diarioanice 19yionice -c 3. Aquí está la clave que se olvida siempre: el backup comprime y transfiere, así que compite por CPU y por disco.renicesolo resuelve lo primero.ionice -c 3(clase idle) hace que solo use el disco cuando nadie más lo pide, y eso protege las lecturas de/var/lib/meteora/lecturas/delagregador.
Riesgos que introduce esta configuración:
- La afinidad dura desperdicia capacidad. Si
ingestorymeteo-apiestán ociosos a las 3 de la madrugada, los núcleos 0 y 1 quedan sin usar mientras elagregadorse limita a dos. Sería mejor aplicar la afinidad solo en la franja de pico, con un temporizador, o eliminarla si elagregadorempieza a apurar el plazo. ionice -c 3puede provocar inanición del backup en un servidor con actividad de disco continua. Si el backup deja de completarse, hay que subirlo a-c 2 -n 7(mejor esfuerzo, prioridad mínima), que sí garantiza progreso.- Nada de esto limita la memoria. Si el
agregadorconsume toda la RAM, el OOM killer podría matar ameteo-apicon independencia de las prioridades de CPU. Ese frente se cubre con cgroups, en 06-02.
Solución 3
1. Cálculos. Con 12 procesos, cambio de contexto de 6 µs, la peor espera para el primer turno es (n−1)·(q + coste) = 11·(q + 6 µs).
| Quantum | Sobrecoste = 6/(q+6) | Peor tiempo de respuesta | Ráfagas de 5 ms completadas |
|---|---|---|---|
| 500 µs | 6/506 = 1,19 % | 11 × 506 µs = 5,57 ms | No (necesita 10 turnos) |
| 5 ms | 6/5006 = 0,12 % | 11 × 5,006 ms = 55,1 ms | Sí, justo |
| 50 ms | 6/50006 = 0,012 % | 11 × 50,006 ms = 550 ms | Sí, con holgura |
2. Elección para meteo-api con objetivo de 200 ms: quantum de 5 ms.
- 500 µs se descarta aunque su tiempo de respuesta sea excelente, porque el 75 % de las ráfagas duran menos de 5 ms y con q=500 µs una ráfaga típica necesitaría hasta 10 turnos. Cada turno intercalado significa reentrar con las cachés contaminadas por los otros 11 procesos: el sobrecoste real es mucho mayor que el 1,19 % nominal, que solo cuenta el cambio de contexto y no los fallos de caché.
- 50 ms se descarta directamente: 550 ms de peor caso supera con creces el objetivo de 200 ms. Bastaría un pico de carga para incumplirlo.
- 5 ms es el punto correcto: sobrecoste despreciable (0,12 %), 55 ms de peor respuesta —con un margen de 3,6× sobre el objetivo— y coincide con el umbral en que el 75 % de las ráfagas terminan solas, que es justo la regla práctica del apartado del quantum.
3. Con 200 procesos ejecutables: sí, cambiaría, y de forma drástica.
Casi cinco veces el objetivo de 200 ms. Para volver a cumplirlo:
Habría que bajar el quantum a 1 ms, aceptando cinco veces más sobrecoste de cambios de contexto.
Y aquí está la observación más valiosa del ejercicio: esta es exactamente la razón por la que CFS no usa un quantum fijo. Linux define una latencia objetivo (sched_latency_ns, 6 ms por defecto) que es el periodo en el que todo proceso ejecutable debe recibir CPU al menos una vez, y calcula el quantum dividiéndola entre el número de procesos ejecutables. Con un suelo de granularidad mínima (sched_min_granularity_ns, ~0,75 ms) para que no degenere:
$ cat /proc/sys/kernel/sched_latency_ns 2>/dev/null || echo "(EEVDF: sustituido por sched_base_slice_ns)"
6000000
12 procesos: 6 ms / 12 = 0,5 ms → por debajo del suelo, se usa 0,75 ms
200 procesos: 6 ms / 200 = 0,03 ms → se usa el suelo de 0,75 ms
y la latencia real se estira a 200 × 0,75 = 150 msEs decir: el planificador mantiene la latencia objetivo mientras puede, y cuando hay demasiados procesos prefiere estirarla antes que arruinar el rendimiento con quanta minúsculos. Esa degradación controlada es una decisión de diseño consciente, y explica por qué un servidor con 2.000 procesos ejecutables se siente lento aunque la CPU no esté al 100 %: no le falta CPU, le falta turno.
Conclusión
Planificar hace falta porque los procesos alternan ráfagas de CPU y de E/S, y cuando uno se bloquea la CPU quedaría desperdiciada. La distinción entre procesos limitados por CPU y limitados por E/S es la que guía toda decisión práctica, y se lee directamente en la proporción de cambios de contexto voluntarios frente a involuntarios de /proc/<pid>/status. Favorecer a los cortos no es caridad: es lo que mantiene todos los recursos ocupados a la vez.
Los criterios se contradicen: no hay un algoritmo que optimice a la vez productividad, tiempo de retorno y tiempo de respuesta. FCFS es trivial pero sufre el efecto convoy; SJF/SRTF son óptimos en espera media pero requieren adivinar el futuro y causan inanición; las prioridades necesitan envejecimiento para no condenar a nadie; Round Robin sacrifica la media a cambio de acotar la respuesta, con el quantum como perilla central; y las colas con realimentación deducen del comportamiento lo que no pueden saber de antemano.
Linux resuelve todo esto con CFS/EEVDF, que sustituye colas y quanta por un tiempo virtual y elige siempre al más rezagado respecto a su parte justa. Ahí encaja nice: no reparte turnos, sino que cambia el ritmo del reloj virtual, con la regla de un ~10 % de cuota por punto. Y nice solo actúa en caso de conflicto y solo sobre la CPU, dos límites que hay que tener siempre presentes. Por encima quedan las políticas de tiempo real, potentes y peligrosas a partes iguales, y por debajo el reparto entre núcleos con afinidad y balanceo.
Hasta aquí hemos repartido la CPU dando por hecho que cada proceso tiene su memoria y no pisa la de los demás. Es hora de preguntarse cómo se consigue eso: cómo varios procesos comparten una memoria física limitada sin invadirse, qué convierte la dirección 0x400000 de ingestor y la 0x400000 de agregador en dos sitios físicos distintos, y qué hace exactamente el hardware para impedir que uno lea los datos del otro. Es lo que veremos en Gestión de Memoria.
Fundamentos de Sistemas Operativos
Módulo 1: Introducción a los Sistemas Operativos
- Conceptos Básicos de Sistemas Operativos
- Historia y Evolución de los Sistemas Operativos
- Tipos de Sistemas Operativos
- Funciones Principales de un Sistema Operativo
- Arquitectura del Núcleo: Monolítico, Microkernel e Híbrido
- Modo Usuario, Modo Núcleo y Llamadas al Sistema
Módulo 2: Gestión de Recursos
- Gestión de Procesos
- Planificación de la CPU
- Gestión de Memoria
- Memoria Virtual y Paginación
- Gestión de Almacenamiento
- Gestión de Dispositivos
- Controladores, Interrupciones y Operaciones de E/S
Módulo 3: Concurrencia
- Conceptos de Concurrencia
- Hilos y Procesos
- Comunicación entre Procesos (IPC)
- Sincronización y Exclusión Mutua
- Problemas Clásicos de Concurrencia
- Interbloqueos: Prevención, Detección y Recuperación
Módulo 4: Estructuras de Archivos
- Sistemas de Archivos
- Estructuras de Directorios
- Particiones, Montaje y Sistema de Archivos Virtual
- Gestión de Archivos
- Asignación de Espacio, Journaling e Integridad
- Seguridad y Permisos de Archivos
Módulo 5: Protección y Seguridad del Sistema
- Principios de Protección y Control de Acceso
- Usuarios, Autenticación y Escalada de Privilegios
- Amenazas Comunes y Endurecimiento del Sistema
- Auditoría, Registros y Respuesta a Incidentes
Módulo 6: Virtualización y Contenedores
- Virtualización: Hipervisores y Máquinas Virtuales
- Contenedores: Namespaces y cgroups
- El Sistema Operativo en la Nube
- Sistemas Operativos Móviles y de Tiempo Real
