Recientemente cambiamos nuestro entorno de producción a Kubernetes. Me gustaría imponer límites de CPU en los contenedores. Estoy obteniendo métricas de CPU en conflicto que no encajan entre sí. Aquí está mi configuración:
- Agentes DataDog que se ejecutan como
Daemonset
- Aplicaciones existentes que se ejecutan sin límites de CPU
- Los contenedores en cuestión son aplicaciones de Ruby multiproceso
- Dos métricas:
kubernetes.cpu.usage.{avg,max}
ydocker.cpu.usage
c4.xlarge
nodos de clúster (4 vCPU o 4000 m en términos de Kubernetes)
kubernetes.cpu.usage.max
informa ~ 600m para los contenedores en cuestión. docker.cpu.usage
informes ~ 60%. De ello se deduce que un límite de CPU de 1000 m sería más que suficiente capacidad en condiciones normales de funcionamiento.
Puse el límite a 1000m. Luego docker.container.throttles
sube significativamente, mientras que kubernetes.cpu.usage.max
y docker.cpu.usage
siguen siendo los mismos. Todo el sistema cae de rodillas durante este tiempo. Esto no tiene sentido para mi.
Investigué las estadísticas de Docker. Parece que docker stats
(y la API subyacente) normalizan la carga según los núcleos de la CPU. Entonces, en mi caso, docker.cpu.usage
del 60% llega (4000m * 0.60) a 2400m en términos de Kubernetes. Sin embargo, esto no se correlaciona con ningún número de Kubernetes. Hice otro experimento para probar mi hipótesis de que los números de Kubernetes son incorrectos. Establecí el límite en 2600m (para un poco de espacio libre adicional). Esto no dio lugar a ninguna aceleración. Sin embargo, Kubernetes observó que el uso de la CPU no cambió. Esto me deja confundido.
Entonces mis preguntas son:
- ¿Esto se siente como un error en Kubernetes (o algo en la pila?)
- ¿Es correcto mi entendimiento?
Mi pregunta de seguimiento se refiere a cómo determinar adecuadamente la CPU para las aplicaciones de Ruby. Un contenedor usa Puma. Este es un servidor web multiproceso con una cantidad configurable de subprocesos. Las solicitudes HTTP son manejadas por uno de los hilos. La segunda aplicación es un servidor de segunda mano que utiliza el servidor roscado. Cada conexión TCP entrante es manejada por su propio hilo. El hilo sale cuando se cierra la conexión. Ruby como GIL (Global Interpreter Lock) para que solo un hilo pueda ejecutar código Ruby a la vez. Eso permite múltiples hilos ejecutando IO y cosas así.
Creo que el mejor enfoque es limitar el número de subprocesos que se ejecutan en cada aplicación y aproximar los límites de CPU de Kubernetes en función del número de subprocesos. Los procesos no se bifurcan, por lo que el uso total de la CPU es más difícil de predecir.
La pregunta aquí es: ¿cómo predecir adecuadamente el uso de la CPU y los límites para estas aplicaciones?