9 puntos por outsideris 2022-08-21 | 2 comentarios | Compartir por WhatsApp

Crossplane, creado por Upbound, ofrece un control plane de nube sobre Kubernetes. Por eso tiene cientos de CRD (Custom Resource Definition) para representar recursos de nube como AWS, Azure y GCP. En Crossplane se les llama MR (Managed Resource).

Incluso los usuarios avanzados de Kubernetes suelen operar una cantidad razonable de CR, de unas decenas, pero en Crossplane hay que usar cientos de MR, así que comenzaron a revisar cuál es el límite de Kubernetes para manejar grandes cantidades de CRD.

Esto puede dividirse en problemas del lado del cliente y del lado del servidor.

Problemas del lado del cliente

  • En el cliente, el problema está en el proceso de discovery.
  • Clientes como kubectl hacen discovery para averiguar qué APIs ofrece el servidor, y para eso tienen que recorrer todos los endpoints de API una vez.
  • Los CR se exponen como endpoints de API.
  • Para consultar un MR como https://example.org/apis/rds.aws.upbound.io/v1/instances/cool-db, primero hay que encontrar los grupos de API soportados en https://example.org/apis/, luego las versiones soportadas en https://example.org/apis/rds.aws.upbound.io, y después los CR soportados en https://example.org/apis/rds.aws.upbound.io/v1.
  • Los MR de Crossplane para proveedores de nube como AWS, Azure y GCP son alrededor de 2,000 y están divididos en 300 grupos y versiones de API.
  • El cliente termina enviando 300 solicitudes HTTP para discovery.
  • Con las condiciones actuales de red no es un gran problema, pero los problemas que encontraron fueron el rate limit y la caché.

Rate limit del cliente

  • Había un rate limit de 5 solicitudes por segundo en promedio (con bursts de hasta 100), y la caché de discovery se invalidaba cada 10 minutos.
  • Esto se puede resolver aumentando el rate limit; sigue siendo de 5 solicitudes por segundo por defecto, pero ahora puede elevarse hasta 300.
  • En kubectl v1.22 se abrió un issue para aumentar este límite, y la caché de discovery también se ajustó de 10 minutos a 5 horas, por lo que en Kubernetes v1.25 ya se puede aprovechar el límite ampliado del cliente.

Caché del cliente

  • Incluso desactivando el rate limit en las pruebas, consultar los 300 grupos de API tomaba casi 20 segundos.
  • Al principio parecía un problema de red, pero resultó que el problema aparecía al consultar los archivos de caché.
  • Se corrigió en Kubernetes 1.25, logrando una mejora de 25 veces en macOS y de 2 veces en Linux.

Mejoras futuras del cliente

  • Aplicar rate limit del lado del cliente es razonable, pero en realidad no protege correctamente al servidor.
  • API Priority and Fairness (AP&F), introducido en Kubernetes 1.20, protege al servidor al ofrecer colas y control del flujo de tráfico del lado del servidor.
  • Un único endpoint HTTP agregado para discovery fue aprobado en un KEP y se espera soporte alfa en 1.26.

Problemas del lado del servidor

Cálculo del esquema OpenAPI

  • Después de registrar cientos de CRD, detectaron que las solicitudes a la API se volvían lentas por casi una hora.
  • Mediante profiling encontraron que el problema estaba en la lógica que calcula el esquema OpenAPI v2.
  • Cuando se agrega o actualiza un CRD, el controlador de OpenAPI construye la especificación swagger del CR, la combina con el swagger de todos los demás CR para formar una sola especificación grande, y luego la serializa a JSON para exponerla en /openapi/v2.
  • Lo cambiaron para que /openapi/v2 se calcule de forma diferida y solo cuando se solicite el endpoint correspondiente al CR real.
  • Este cambio entró en v1.24.0 y fue backporteado a 1.20.13, 1.21.7 y 1.22.4.

Cliente de etcd

  • Este fue un nuevo cuello de botella que encontraron después de resolver el problema de OpenAPI.
  • Descubrieron que el servidor API usaba 4 MiB de memoria por cada CRD.
  • Esto es aún más problemático en Kubernetes administrados como GKE y EKS, porque el CPU y la memoria del servidor API están limitados. Si se necesitan más recursos, el servidor API se escala automáticamente, pero lamentablemente agregar CRD no es un factor que determine ese escalado. Por eso no se escala a menos que el servidor API entre repetidamente en OOM killed.
  • En pruebas sobre GKE, AKE y EKS, hubo autohealing, pero el servidor API quedó inutilizable entre 5 segundos y 1 hora. El clúster no se detenía por completo, pero toda la reconciliación se detenía.
  • Mediante profiling descubrieron que Zap, la librería de logging, consumía el 20% de la memoria.
  • El servidor API crea un cliente de etcd por cada versión de CR, y cada cliente de etcd crea un logger de Zap.
  • Como resultado, no solo aumentó el uso de memoria por loggers duplicados, sino que también se generaron conexiones TCP innecesarias entre el servidor API y etcd.
  • Los maintainers estuvieron de acuerdo en que lo correcto sería usar un solo cliente de etcd para todos los endpoints de CR, pero como el lanzamiento de Kubernetes 1.25 estaba muy cerca, era difícil corregirlo por completo, así que hicieron un cambio más pequeño para que todos los clientes de etcd compartieran un solo logger.
    -Esto se incluirá en 1.25 y será backporteado a 1.22, 1.23 y 1.24. Reducirá el uso de memoria en un 20%.

Mejoras futuras del lado del servidor

  • Planean cambiar el diseño para que, en vez de crear un cliente de etcd por cada versión de CR, se cree uno por transporte (uno por clúster de etcd).
  • También están colaborando con los equipos de ingeniería de GKE, EKS y AKE para manejar instalaciones con muchas CRD de Crossplane.

2 comentarios

 
roxie 2022-08-21

Gratuito -> inválido

 
roxie 2022-08-21

clalyingente -> cliente