Tema representativo de entrevista

Entrevista de diseño de sistemas: Escalar controladores de Kubernetes con List y Watch particionados en el lado del servidor

Diseño de sistemasDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Una flota de controladores observa millones de Pods. Actualmente, cada réplica recibe el flujo completo de List y Watch, filtra localmente y sobrecarga el servidor de la API y la red. Diseñe una migración a List y Watch particionados en el lado del servidor de Kubernetes v1.36: ¿cómo asigna los rangos, demuestra la cobertura, maneja servidores no compatibles y el reparticionamiento (resharding), y verifica que ningún objeto se omita o se procese dos veces?

Problema y alcance

Esta es una pregunta de diseño de sistemas del plano de control para ingenieros de plataformas y Kubernetes. Kubernetes v1.36 introduce List y Watch particionados en el lado del servidor como una característica alfa detrás del gate ShardedListAndWatch. Considere la característica como opcional y diseñe un controlador que se mantenga correcto cuando el gate esté deshabilitado.

Qué evalúa el entrevistador

  • Un modelo de propiedad de fragmentos que cubra el espacio de claves exactamente una vez.
  • List inicial correcto, manejo de resource-version y comportamiento de reconexión de Watch.
  • Detección de un servidor de la API que ignoró el selector.
  • Reparticionamiento (resharding), rotación de réplicas y el balance de compensación entre solapamiento y brechas.
  • Razonamiento sobre capacidad de CPU del servidor de la API, red, memoria del informer y tormentas de recuperación.

¿Cuál es la clave de propiedad?

La implementación alfa admite object.metadata.uid y object.metadata.namespace. El hashing por UID ofrece una distribución estable; el hashing por namespace puede preservar la localidad de los inquilinos, pero puede presentar sesgos. La elección modifica el balanceo, los límites de seguridad y el costo de migración.

¿Cuál es el objetivo de corrección?

Pregunte si la reconciliación al menos una vez (at-least-once) es aceptable y si el procesamiento duplicado es idempotente. Si un efecto secundario de negocio no puede tolerar duplicados, añada una clave de trabajo duradera y fencing en lugar de depender únicamente de un flujo de eventos.

¿Pueden actualizarse juntos todos los servidores de la API y los clientes?

Asuma versiones mixtas a menos que el equipo de plataforma demuestre lo contrario. El controlador debe inspeccionar los metadatos de respuesta y recurrir al filtrado del lado del cliente sin asumir silenciosamente una reducción de carga.

Estructura de respuesta de 30 segundos

“Dividiría un espacio de hash determinista de 64 bits en rangos no solapados y asignaría cada rango a una réplica del controlador. Cada informer envía un selector de fragmento tanto en List como en Watch, y luego verifica que la respuesta contenga los metadatos de fragmento correspondientes. La falta de reconocimiento activa un fallback seguro al flujo completo o deshabilita la optimización. El reparticionamiento utiliza una generación y un protocolo de traspaso con solapamiento, reconciliación idempotente y métricas de cobertura, duplicados, retraso y tráfico de fallback.”

Diseño paso a paso

Partición y asignación

Represente la propiedad como rangos semiabiertos [start, end) sobre un anillo de 64 bits. Almacene una generación, propietario y lease para cada rango. Un despliegue de dos réplicas puede dividir el anillo por la mitad; más réplicas utilizan una tabla de rangos gestionada por el controlador. No derive la propiedad únicamente del ordinal de la réplica porque un reinicio podría generar brechas.

text
Replica A: [0000..., 8000...)
Replica B: [8000..., 1000...)

Hacer de List y Watch un solo protocolo

El List inicial y cada reconexión de Watch deben llevar el mismo selector y un resource version. El informer reemplaza su almacenamiento local solo después de que se completa el list inicial, y luego inicia el watch desde el resource version devuelto. Un error 410 Gone o una versión expirada provoca un list nuevo para ese fragmento, no una reproducción a ciegas de otro rango.

Verificar soporte del servidor

El blog de v1.36 describe un campo de respuesta shardInfo que refleja el selector aplicado. Si está ausente, asuma que el servidor devolvió la colección completa. El cliente puede filtrar localmente por corrección, pero debe emitir una métrica de fallback y aplicar contrapresión (backpressure) para que un servidor no compatible no multiplique el uso de memoria entre las réplicas.

Reparticionar sin brechas

Cree una nueva generación de rangos. Durante el traspaso, el propietario anterior continúa reconciliando mientras el nuevo propietario precarga un list y espera un watch en un resource version conocido. Confirme el cambio de propiedad solo después de que ambas partes reporten preparación; los eventos duplicados son aceptables cuando la reconciliación es idempotente. Si la preparación falla, expire el lease y mantenga al propietario anterior.

Capacidad y rutas de fallo

El filtrado en el lado del servidor reduce los bytes y la deserialización de los objetos descartados, pero ahora el servidor de la API realiza el hashing y la evaluación de selectores. Protéjalo con un feature gate, límites de concurrencia por controlador y canaries de despliegue. En caso de sobrecarga del servidor de la API, limite las reconexiones y use retroceso exponencial (exponential backoff); nunca permita que todas las réplicas hagan relist al mismo tiempo.

Ejemplo de respuesta de alta calidad

“Utilizaría una tabla de rangos con marca de generación sobre un hash determinista de UID. Los informers incluyen ese selector en List y Watch y requieren shardInfo antes de considerar activa la optimización. La falta de este campo recurre al filtrado local con un presupuesto de concurrencia global. El reparticionamiento crea una nueva generación, precarga al propietario entrante a partir de un resource version y cambia los leases solo tras la preparación; la reconciliación es idempotente, por lo que el solapamiento es seguro. Haría un despliegue canary del feature gate y compararía CPU de la API, bytes, latencia de list, reconexiones de watch, cobertura de fragmentos, duplicados y tasa de fallback.”

Errores comunes

  • Asignar fragmentos por índice de réplica → Los reinicios cambian la propiedad y crean brechas → persista una tabla de rangos con marca de generación.
  • Aplicar el selector únicamente a Watch → El List inicial sigue sobrecargando el servidor y puede discrepar con el flujo → utilice el mismo selector y las mismas reglas de resource-version para ambos.
  • Confiar en un servidor no compatible → Cada réplica recibe el flujo completo → requiera shardInfo y exponga el tráfico de fallback.
  • Mover un rango instantáneamente → Se pueden perder eventos durante el traspaso → solape propietarios, proteja con generaciones mediante fencing y haga que la reconciliación sea idempotente.
  • Medir solo la CPU del controlador → El hashing del servidor de la API o las tormentas de reconexión permanecen invisibles → monitoree las métricas del plano de control y del cliente en conjunto.

Rúbrica de evaluación y autoevaluación

Califique la corrección de la partición, la semántica de list-watch, el fallback, el reparticionamiento, la capacidad y la observabilidad. Una respuesta sólida enuncia el invariante: cada objeto pertenece a una generación de rango activa y cada traspaso tiene un límite de resource-version. También explica por qué los duplicados son más seguros que las brechas cuando la reconciliación es idempotente.

Preguntas de seguimiento y extensiones

¿Qué pasa si un namespace es mucho más grande que otros?

Prefiera el hashing por UID para lograr balance, o divida los namespaces con alta carga en múltiples rangos de UID. Mida la carga del rango en lugar de asumir recuentos de objetos iguales.

¿Cómo se detecta una brecha silenciosa?

Compare los recuentos globales de objetos muestreados con la unión de los recuentos de fragmentos, registre las generaciones de selectores y ejecute objetos sintéticos periódicos a través de cada rango. Genere alertas sobre retrasos (lag) o desviaciones de cobertura.

¿Qué sucede durante una actualización del servidor de la API?

Mantenga el feature gate deshabilitado hasta que los canaries observen shardInfo en cada endpoint en servicio. Las respuestas mixtas activan el fallback y una tasa de reconexión acotada.

¿Puede un controlador procesar el mismo objeto dos veces?

Sí, durante el solapamiento o la reconexión. Utilice la versión del objeto y una clave de trabajo duradera para hacer que los efectos secundarios sean idempotentes; nunca intercambie reconciliación duplicada por un riesgo ilimitado de perder estado.

Fuentes públicas

Preguntas relacionadas

Herramienta de entrevista relacionada

Usa Resolver para una respuesta de diseño de sistemas

Aclara primero los requisitos y luego avanza a través de la escala, la arquitectura, la elección de componentes y las compensaciones (trade-offs).

Ver la herramienta