Tema representativo de entrevista

Entrevista técnica de backend de PostgreSQL: ¿Cómo realizar el failover de la replicación lógica sin perder datos?

BackendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Un nodo primario de PostgreSQL transmite cambios de órdenes a un almacén de datos (warehouse) y a un servicio de búsqueda mediante replicación lógica. El primario puede fallar mientras los consumidores están retrasados. Diseñe el failover planificado y no planificado, explique cómo verificar que los slots lógicos en el standby puedan tomar el control, cómo evitar rangos de LSN duplicados u omitidos, y cómo recuperarse cuando no se puede demostrar la continuidad del slot.

Prompt y roles aplicables

Un nodo primario de PostgreSQL transmite cambios de órdenes a un almacén de datos (warehouse) y a un servicio de búsqueda mediante replicación lógica. El primario puede fallar mientras los consumidores están retrasados. Diseñe el failover planificado y no planificado, explique cómo verificar que los slots lógicos en el standby puedan tomar el control, cómo evitar rangos de LSN duplicados u omitidos, y cómo recuperarse cuando no se puede demostrar la continuidad del slot.

Esto se adapta a entrevistas de backend, plataforma de bases de datos, infraestructura de datos y SRE. Distinga a los suscriptores de PostgreSQL de los consumidores que no son de PostgreSQL como Debezium: los primeros pueden usar configuraciones de failover integradas, mientras que los segundos aún necesitan evidencia independiente a través del estado del conector, los slots y la reconciliación. "El standby está sincronizado" no prueba que cada consumidor lógico pueda continuar sin problemas.

Qué evalúa el entrevistador

Una respuesta sólida establece invariantes verificables: el flujo lógico en el nuevo primario no debe retroceder; un consumidor se reanuda desde una posición confirmada, permitiendo duplicados pero prohibiendo brechas silenciosas; y el failover está condicionado a la sincronización de slots y el progreso de los consumidores. El candidato debe separar el failover planificado, donde las escrituras se pueden pausar y los consumidores se pueden vaciar (drain), de una falla no planificada, donde un respaldo, una instantánea (snapshot) completa y la reconciliación pueden ser la única reparación segura. Apuntar el DNS al standby no resuelve los slots, la retención de WAL o los consumidores que no son de PostgreSQL.

Preguntas a aclarar antes de responder

  • ¿Cuáles son los consumidores? Los suscriptores de PostgreSQL, Debezium, cargadores de almacenes de datos y decodificadores personalizados tienen diferentes interfaces de progreso y recuperación.
  • ¿Son aceptables los duplicados? La entrega at-least-once suele ser aceptable cuando los destinos deduplican por LSN, ID de transacción o una clave de idempotencia; un script no puede prometer exactly-once por mera afirmación.
  • ¿Es un failover planificado o por desastre? El cambio planificado puede pausar las escrituras y esperar al standby; tras una falla no planificada, es posible que no se conozca el último LSN comprometido (committed) y confirmado por el consumidor.
  • ¿Importan los límites de transacciones entre tablas? Si el sistema downstream requiere una vista atómica de la orden y las líneas de orden, propague los límites de transacciones en lugar de comparar LSNs fila por fila.
  • ¿Cuánto WAL se puede retener? Un slot retrasado bloquea la limpieza de WAL, arriesgando el agotamiento del disco en el primario; un slot invalidado puede crear una brecha irrecuperable.
  • ¿Se pueden reconstruir los consumidores a partir de un snapshot? Si la continuidad no se puede probar, prepare un snapshot completo, reconciliación de versiones y un plan de degradación o mantenimiento.

Marco de respuesta de 30 segundos

"Haría explícito el invariante: la posición del slot del nuevo primario cubre la última posición confirmada del consumidor, y el LSN de origen recuperado avanza monótonamente. Se pueden reproducir eventos duplicados, pero ningún rango se puede omitir silenciosamente. Para un failover planificado, pause o regule las escrituras, verifique que los failover slots estén sincronizados con el standby y que el standby esté por delante de los consumidores, detenga los conectores después de registrar LSNs seguros, promueva el standby y reanude los consumidores.

PostgreSQL 17 puede sincronizar asincrónicamente failover slots con un standby, pero el cambio debe verificar que cada slot exista, esté sincronizado, sea no temporal y no tenga motivo de invalidación. Debezium y otros consumidores no pertenecientes a PostgreSQL deben verificar de forma independiente su slot y LSN. Después de una falla no planificada, si se desconoce la continuidad, no cree un slot nuevo pretendiendo continuar; reconstruya a partir de un respaldo o snapshot confiable y reconcilie por clave, transacción y LSN."

Análisis detallado paso a paso

Paso 1: Modelar slots, LSNs y progreso del consumidor

Un slot de replicación lógica representa un flujo de cambios que se puede reproducir en el orden de origen. restart_lsn es la posición de WAL más antigua que aún debe retenerse; el progreso confirmado del consumidor se representa comúnmente mediante confirmed_flush_lsn o un offset específico del conector. Responden a preguntas diferentes: el primero controla la liberación de WAL, mientras que el segundo indica hasta dónde ha procesado el consumidor.

Cada consumidor independiente debe tener un slot independiente o una capa de difusión explícita. Múltiples consumidores compitiendo por un solo slot pueden hacer que los consumidores que no recibieron un cambio queden incompletos de forma silenciosa. Monitoree el WAL retenido, la posición confirmada, el retraso de lectura, la transacción más antigua sin procesar y el espacio disponible en disco, no solo la cola de la aplicación.

Paso 2: Crear un punto seguro demostrable para el failover planificado

El failover planificado puede utilizar una breve ventana de solo lectura o de drenado. Registre el último offset seguro de cada consumidor, espere hasta que la reproducción física del standby cubra el estado de slot requerido y luego verifique que los failover slots sean utilizables en el standby. PostgreSQL requiere confirmación de que los slots están sincronizados; failover_ready significa que el slot está sincronizado, no es temporal y no tiene motivo de invalidación.

text
freeze_or_throttle_writes()
stop_consumers_after_recording_offsets()
wait_until(standby_replay_lsn >= required_slot_positions)
assert all(required_slots on standby are synced and valid)
promote(standby)
verify_slot_positions_are_monotonic()
restart_consumers_from_last_safe_offsets()
reconcile_sampled_rows_and_transactions()

Un suscriptor de PostgreSQL puede usar configuraciones de failover de suscripción o de slot. Un conector de Debezium debe preservar su offset, confirmar que el slot correspondiente existe en el nuevo primario y demostrar que puede continuar desde el mismo LSN. El código de éxito de un script no sustituye a esas comprobaciones de estado.

Paso 3: Manejar fallas no planificadas y entregas duplicadas

Cuando el primario desaparece, el standby puede contener una posición de WAL anterior y es posible que un consumidor haya recibido un evento sin registrar de forma duradera su offset. Permita un solapamiento acotado y deduplique downstream por LSN de origen, ID de transacción o una clave de idempotencia de dominio. El slot del nuevo primario debe provenir de un estado sincronizado; si se desconoce la continuidad, crear un slot en la posición actual de WAL no puede recuperar LSNs descartados.

Si el primario antiguo regresa, no permita que acepte escrituras junto con el nuevo primario. Aíslelo, establezca la línea de tiempo autoritativa y reconstruya la replicación física o lógica. Cualquier reconexión debe comenzar desde un snapshot consistente o una posición de log explícita y reconciliar transacciones, eliminaciones y límites entre tablas durante la ventana.

Paso 4: Contener la invalidación de slots y el crecimiento de WAL

Un slot que permanece rezagado retiene WAL y amenaza el disco del primario y la seguridad del ID de transacción. Proteja primero el primario, luego decida si el slot aún se puede recuperar: pause los consumidores no críticos, limite las escrituras o agregue almacenamiento temporal solo con un presupuesto explícito. Si el slot se eliminó, se invalidó o carece del LSN requerido, crear un slot con el mismo nombre no puede restaurar el historial.

Reconstruya el consumidor a partir del respaldo consistente o snapshot completo más reciente, registre la posición del snapshot y consuma los cambios posteriores a esa posición. Reconcilie por versión de clave, ID de transacción, tombstones de eliminación y recuentos esperados. Mantenga al consumidor degradado hasta que pase la reconciliación; "el consumidor se conectó" no significa completitud de datos.

Paso 5: Verificar el failover con simulacros y mediciones

Realice simulacros de conmutación planificada sin escrituras, un consumidor rezagado, sincronización de slots retrasada, pérdida repentina del primario, mensajes duplicados, regreso accidental del primario antiguo, invalidación de slots, cambios de esquema y una transacción grande. Registre las líneas de tiempo del primario y del standby, el estado del slot, restart_lsn, confirmed_flush_lsn, los offsets de los consumidores, los límites de las transacciones y los recuentos comerciales.

Las comprobaciones de aceptación incluyen LSNs monótonos, recuentos de eventos duplicados y faltantes, antigüedad de la transacción no procesada más antigua, WAL retenido, RTO/RPO de failover, tiempo de recuperación del consumidor y diferencias de versiones muestreadas entre la base de datos y downstream. La inconsistencia más pequeña encontrada tras la inyección de fallas debe poder reproducirse desde un respaldo guardado o una posición de log; eso demuestra una ruta de reparación real.

Respuesta de muestra de alta calidad

"Definiría la continuidad primero: el slot del nuevo primario cubre la última posición segura del consumidor y los LSNs de origen aumentan monótonamente. Los duplicados son aceptables, las brechas silenciosas no lo son. Cada consumidor no perteneciente a PostgreSQL obtiene su propio slot, y el offset del conector, el estado del slot y la reconciliación del negocio forman un único conjunto de evidencia.

Para el failover planificado, pauso o limito las escrituras, registro cada offset de consumidor, espero a que la reproducción física del standby cubra el estado del slot y verifico que cada failover slot esté sincronizado, no sea temporal y sea válido. Detengo los conectores, promuevo el standby, verifico posiciones monótonas y reanudo desde el último offset seguro. Los suscriptores de PostgreSQL pueden usar configuraciones de failover integradas; los consumidores de Debezium deben verificar independientemente el nuevo slot y LSN.

Para una falla no planificada, permito un solapamiento acotado y hago que los destinos sean idempotentes por LSN o ID de transacción. Si la continuidad del slot no es demostrable, no creo un nuevo slot pretendiendo continuar. Reconstruyo a partir de un respaldo consistente o snapshot completo, consumo los cambios siguientes y reconcilio claves, eliminaciones y límites de transacciones. Los simulacros inyectan retraso en la sincronización de slots, duplicados, regreso del primario antiguo y transacciones grandes mientras miden el WAL retenido, el RPO de failover, duplicados o brechas y diferencias de versiones downstream."

Errores comunes

  • Solo cambiar el DNS o una cadena de conexión → los slots lógicos y los offsets de los consumidores no se vuelven continuos automáticamente → condicione el failover al estado de los slots, LSN y consumidores.
  • Tratar la sincronización del standby físico como preparación del slot lógico → la sincronización de slots es asincrónica y puede retrasarse respecto a los consumidores → verifique el estado sincronizado, válido y de reproducción de cada slot.
  • Compartir un slot entre consumidores → la entrega a un solo consumidor deja silenciosamente a los demás incompletos → use un slot por consumidor independiente o una capa de difusión.
  • Crear un slot nuevo en el nuevo primario → un rango de LSN ya perdido no se puede recuperar → reconstruya a partir de un snapshot cuando no se conozca la continuidad.
  • Tratar confirmed_flush_lsn como restart_lsn uno es el progreso del consumidor y el otro controla la retención de WAL → monitórelos y explíquelos por separado.
  • Prometer exactly-once como propiedad del failover → las ventanas de caída aún generan duplicados → use at-least-once más efectos secundarios idempotentes y mida los duplicados.
  • Reconectar el primario antiguo de inmediato → los escritores duales crean líneas de tiempo y LSNs divergentes → aíslelo, elija la autoridad y reconstruya en la nueva línea de tiempo.
  • Simular únicamente la disponibilidad de la base de datos → la invalidación de slots, las transacciones largas y el crecimiento de WAL exponen riesgos en los datos → inyecte retraso de consumidores, acumulación de slots y transacciones grandes.
  • Declarar la recuperación cuando el consumidor se conecta → el éxito de la conexión no prueba que las filas o las eliminaciones se hayan completado → reconcilie claves, límites de transacciones y recuentos comerciales.

Preguntas de seguimiento y respuestas

Pregunta de seguimiento 1: ¿Debe el failover planificado detener las escrituras?

No siempre, pero continuar con las escrituras amplía la ventana de prueba. Si la base de datos y el mecanismo de sincronización de slots demuestran que el standby cubre cada posición requerida, la ventana de solo lectura puede ser corta. De lo contrario, limitar brevemente las escrituras es más seguro que reemplazar una validación de LSN con un "suele ser rápido". Espere a que terminen las transacciones confirmadas y registre el límite.

Pregunta de seguimiento 2: ¿Cómo sabe un consumidor no perteneciente a PostgreSQL que el nuevo slot es continuo?

Preserve el offset del conector y el LSN de origen. Antes de conmutar, confirme que el slot del standby esté sincronizado en o más allá de esa posición; tras conmutar, lea el inicio del nuevo slot y verifique la monotonicidad. Si el offset contiene solo la marca de tiempo del mensaje y no el LSN, la continuidad no está probada; reconstruya o agregue metadatos de posición de origen.

Pregunta de seguimiento 3: ¿Qué ocurre con una transacción grande durante el failover?

Distinga entre estados comprometidos, no comprometidos y parcialmente decodificados. Si downstream necesita atomicidad de transacciones, propague los límites BEGIN/COMMIT y descarte fragmentos incompletos tras la recuperación. Si la consistencia eventual a nivel de fila es suficiente, establezca las reglas de visibilidad intermedia y reproducción. El orden de llegada de filas individuales no demuestra una transacción completa.

Pregunta de seguimiento 4: ¿Se puede eliminar un slot cuando WAL llena el disco?

Solo después de confirmar que el consumidor ya no necesita el historial y que la reconstrucción por snapshot está lista. Eliminar el slot libera espacio pero abandona permanentemente los cambios no leídos. Guarde primero la posición, el respaldo y el plan de reconciliación; tras la reconstrucción, demuestre que no hay brechas desde el nuevo snapshot hasta la posición de origen actual.

Fuentes públicas

Preguntas relacionadas