Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Autoescalado con métricas personalizadas en Kubernetes: casi excelente

By Christopher McGrathNov 10, 20235 min read

Esta página también está disponible en English, Deutsch, Français, Italiano, 日本語 y Português.

Las métricas personalizadas suelen ser más precisas y útiles que el autoescalado basado en CPU y RAM, aunque escalar a partir de métricas personalizadas y externas sigue siendo un terreno poco explorado en el que hay margen de mejora.

Kubernetes es una plataforma en constante evolución. Por eso, cada cierto tiempo me gusta volver a revisar funcionalidades con las que no he trabajado en un par de años. Hace poco hice ese ejercicio con los Horizontal Pod Autoscalers (HPAs) y me topé con varias características interesantes y limitaciones que conviene conocer, pero que no están bien documentadas ni resultan obvias.

Vale la pena señalar un detalle: el apiVersion: autoscaling/v2 del HPA da a entender que se trata de una API madura. En la práctica, escalar a partir de métricas personalizadas y externas sigue siendo un terreno poco explorado en el que hay margen de mejora. Es una pena, porque las métricas personalizadas suelen ser más precisas y útiles que el autoescalado basado en CPU y RAM.

Veamos algunos casos de uso en los que las métricas personalizadas mejoran la escalabilidad, junto con las herramientas para llevarlo a la práctica.

Casos de uso

  • Una vez configuradas las métricas personalizadas y expuestas en un formato compatible con HPA, los HPAs pueden escalar a partir de varias métricas. La documentación de Kubernetes incluye un ejemplo parcial, en el que un HPA se configura para escalar según el uso de CPU, paquetes por segundo y solicitudes por segundo. La idea es que cada métrica puede sugerir un número distinto de réplicas deseadas, por ejemplo 3, 5 y 8. Después, el HPA escala al número más alto sugerido.

  • Las solicitudes entrantes por segundo y la duración o latencia de las solicitudes son métricas sólidas para escalar servicios web.

    • Traefik, Linkerd e Istio se usan habitualmente como ingress, gateway y service mesh. Cada uno cuenta con proxies de capa 7 que aportan numerosas métricas personalizadas muy útiles para optimizar el autoescalado.
  • En arquitecturas con colas o buckets de almacenamiento donde se cargan objetos para ser procesados, se puede autoescalar los servicios que procesan esos objetos según la cantidad de elementos detectados.

    • Kubernetes Event Driven Autoscaling (KEDA) cuenta con scalers que se integran con varias colas ( como Pub/Sub) y con buckets de almacenamiento de objetos. También permite ejecutar consultas contra bases de datos de métricas, logs, SQL y NoSQL para generar métricas.
  • Las réplicas mínimas variables ayudan a equilibrar la capacidad de absorber picos de tráfico con el control de costos. Si alguna vez te ha tocado mantener una app cuyas réplicas tardan en arrancar o que sufre picos de tráfico enormes, seguramente has tenido que subir el mínimo de réplicas para preservar la calidad del servicio.

    • Por ejemplo: si una réplica soporta 100 req/s, podrías configurarla para autoescalar a 50 req/s y así evitar errores o latencia por encima de 100 req/s. Un mínimo de 10 réplicas absorbería los picos de tráfico mucho mejor que un mínimo de dos.
    • El único inconveniente de esta técnica es que los costos suben, pero es razonable pensar que una app puede tener picos de tráfico semipredecibles. Quizá un mínimo de dos funcione fuera del horario laboral, un mínimo de 10 en las horas con picos frecuentes y un mínimo de cinco en el resto del día.
    • KEDA incorporó hace poco una opción para combinar varias métricas en una fórmula personalizada por el usuario y crear métricas compuestas a partir de fórmulas matemáticas. Así, conteo deseado = métrica de autoescalado + conteo deseado basado en cron permite simular un mínimo variable de réplicas.
  • Plataformas serverless y de funciones como servicio alojadas en Kubernetes, como las siguientes:

    • keda.sh
    • knative.dev
    • openfaas.com

Limitaciones y consecuencias

Todo lo anterior suena bien y existen herramientas para llevarlo a la práctica. Entonces, ¿cuál es esa limitación que impide que los HPAs sean realmente excelentes?

La siguiente limitación tiene consecuencias importantes en la UX (experiencia de usuario): https://github.com/kubernetes-sigs/custom-metrics-apiserver/issues/70

Resumida, la limitación es: "Solo puede haber un servidor de métricas personalizadas". Si instalas el popular kube-prometheus-stack con la configuración por defecto, obtendrás Prometheus Adapter. Pero no podrás usar al mismo tiempo el keda-operator-metrics-apiserver de KEDA, el Knative Pod Autoscaler de Knative, el autoscaler de OpenFaaS Pro, el de Datadog ni ningún otro, porque todos funcionan alojando un servidor de métricas personalizadas. Creo que por eso KEDA tiene tantos scalers que parece querer convertirse en el ejemplo emblemático del feature creep. KEDA cuenta con más de 60 scalers, incluidos algunos para Prometheus y Datadog. Esto no tiene mucho sentido hasta que descubres que parte del motivo es justamente sortear esta limitación.

Entonces, ¿por qué esta limitación deteriora la UX? Empecemos por un ejemplo de cómo luce una buena UX.

El stack de Kube Prometheus y Helm son populares por algo. Ofrecen una excelente UX y parte de su receta secreta es seguir el principio de "convención sobre configuración". Aportan valores por defecto razonables y una configuración predeterminada en la que cientos o miles de objetos YAML quedan precableados según convenciones, logrando una UX llave en mano en la que muchas cosas funcionan de fábrica.

Un requisito para que esa UX casi mágica suceda es poder ser dueño de un namespace que no entre en conflicto con otras cosas, ya que así se pueden establecer convenciones dentro de ese namespace y precablear todo sin necesidad de configuración hecha a mano.

Se han hecho varias pruebas de concepto (PoCs) para este problema común, e incluso se creó una propuesta de mejora de Kubernetes para resolverlo, pero terminó por diluirse. Espero que este artículo ponga el foco en el problema y despierte un interés renovado en las APIs de escalado por métricas personalizadas.