Planteamiento y contexto
Esta pregunta evalúa si usted puede transformar un síntoma intermitente en una cadena de evidencia repetible. Un error de concurrencia puede involucrar una carrera de datos (data race), el orden de los bloqueos, el entrelazado de mensajes, tiempos de espera (timeouts) o entradas externas; un registro aislado por lo general registra el resultado sin preservar el orden que lo provocó. Record/replay puede preservar eventos no deterministas de una ejecución y reproducirlos, pero está limitado por el soporte de la plataforma, las llamadas al sistema, la sobrecarga y el estado externo no registrado. Cubra el muestreo seguro, el diagnóstico por capas, los límites de la reproducción y la falsación tras la corrección.
Lo que evalúa el entrevistador
- Si define invariantes, impacto y una reproducción mínima antes de habilitar un rastreo completo.
- Si distingue entre carreras de datos, carreras lógicas, bloqueos mutuos (deadlocks), bloqueos activos (livelocks) y entregas externas duplicadas.
- Si puede precisar lo que un detector de carreras, los registros ordinarios, una línea de tiempo y record/replay realmente pueden demostrar.
- Si puede diseñar una verificación progresiva bajo restricciones de privacidad, sobrecarga y riesgo en producción.
Preguntas de clarificación que conviene hacer primero
Aclare qué significa “perdido”, las solicitudes afectadas, la ventana de tiempo, la versión, la arquitectura de la máquina y si intervienen múltiples procesos o servicios. ¿Es posible obtener IDs de solicitud, IDs de subprocesos o goroutines, métricas de bloqueos y métricas de colas? ¿El síntoma parece memoria compartida no sincronizada, una máquina de estados defectuosa o mensajes duplicados y fuera de orden? ¿El éxito se define por la ausencia de reportes de carreras, la preservación de invariantes o una tasa de pérdida de negocio inferior a un umbral determinado?
Estructura de respuesta en 30 segundos
Primero preservaría la evidencia y definiría los invariantes de datos; luego usaría registros y métricas de bajo costo para acotar el desencadenante. En una prueba controlada, ejecutaría un detector de carreras, comprobaciones de subprocesos, pruebas de estrés y perturbación del planificador (scheduler). Si la falla sigue siendo difícil de reproducir y la plataforma lo admite, registraría una falla y la reproduciría repetidamente mientras inspecciono bloqueos, operaciones atómicas y el orden de los mensajes para hallar el primer invariante roto. Repararía la propiedad de los datos, la sincronización o la máquina de estados en lugar de agregar pausas (sleep). Reproduciría la falla original, ampliaría las pruebas de entrelazado y verificaría con conciliación de negocio e inyección de fallas. Censuraría, limitaría y eliminaría las grabaciones; la reproducción es evidencia dentro de un límite definido, no una prueba absoluta para cualquier plataforma y dependencia.
Análisis detallado paso a paso
1. Escribir invariantes y límites de evidencia
Reescriba “se perdió un registro” como aserciones, tales como números de secuencia únicos, conservación del saldo de la cuenta o que un mensaje permanezca reintentable hasta su confirmación (acknowledgement). Identifique el estado compartido, el propietario, el protocolo de bloqueo o atómico, los efectos secundarios externos y la ruta de recuperación. Separe los hechos observados, las hipótesis plausibles y las ramas pendientes de verificar para que un solo registro de error no se convierta en una causa raíz injustificada.
2. Acotar el desencadenante con señales de bajo costo
Agregue IDs de correlación a solicitudes, tareas, subprocesos o goroutines y registre las transiciones de estado y longitudes clave de colas en lugar de cada instrucción. Use carga, inyección de latencia, perturbación del planificador y ejecuciones repetidas para amplificar los entrelazados. Documente qué rutas de código cubre el detector de carreras y cuáles no puede observar; una ejecución limpia no prueba que la lógica de negocio esté libre de condiciones de carrera.
3. Decidir cuándo usar record/replay
Utilice record/replay únicamente cuando una ejecución fallida pueda capturarse dentro de la misma plataforma y límite de entrada, y los registros ordinarios no puedan preservar el orden determinante. Las herramientas pueden registrar resultados de llamadas al sistema, planificación de subprocesos u otras entradas no deterministas para que un depurador pueda avanzar, retroceder e inspeccionar el estado. Confirme las arquitecturas compatibles, el modelo de procesos, las restricciones de sandbox, la capacidad de almacenamiento y la sobrecarga antes de habilitarlo en el tráfico principal de producción.
4. Rastrear hacia atrás desde el primer invariante roto
Durante la reproducción, establezca puntos de interrupción o puntos de observación (watchpoints) y compare variables compartidas, propietarios de bloqueos, secuencias de mensajes y resultados de confirmación entre una ejecución correcta y una fallida. Encuentre la primera divergencia en lugar de adivinar hacia atrás desde el registro faltante final. Para cada entrelazado candidato, escriba la relación happens-before: qué escritura debe preceder a una lectura y qué confirmación debe seguir a la persistencia. Si un servicio externo no se puede reproducir, proporcione simulaciones (mocks) deterministas o entradas grabadas y especifique con exactitud qué excluye esa evidencia.
5. Reparar el diseño, no solo la planificación
Prefiera cambiar la propiedad, el alcance de los bloqueos, las transiciones de estado atómicas o el protocolo de confirmación para que la corrección responda a un invariante explícito en lugar de una pausa (sleep) o un cambio de prioridad de subprocesos. La reparación puede requerir claves de idempotencia, un único escritor, un límite de transacción, propagación de cancelaciones o marcadores de secuencia. Vuelva a verificar excepciones, tiempos de espera, reintentos, caídas de procesos y rutas de recuperación para asegurarse de que el defecto no se traslade a otra rama.
6. Concluir con una verificación por capas
Reproduzca la falla original y confirme que el invariante se cumple. Luego ejecute detección de carreras, pruebas de estrés y de perturbación del planificador en diversas entradas y configuraciones de máquinas. Agregue conciliación de negocio, envío duplicado, inyección de fallas y simulacros de reversión (rollback); mida pérdidas, duplicaciones, latencia y sobrecarga de recursos. Conserve la traza censurada más pequeña posible junto con la versión de la herramienta, las opciones de compilación y las conclusiones durante un período limitado. Si no se puede demostrar la cobertura externa, limite la afirmación a “no reproducido dentro de este límite”.
Respuesta modelo de alta calidad
Definiría invariantes como la conservación del saldo, números de secuencia únicos y el orden de las confirmaciones; luego protegería y censuraría las muestras. Acotaría el desencadenante con IDs de correlación, transiciones de estado, métricas de colas, carga y perturbación del planificador antes de ejecutar un detector de carreras en un entorno controlado. Dicho detector cubre las carreras que realmente se ejecutan, no todos los entrelazados lógicos. Si la plataforma lo admite y la reproducción sigue siendo difícil, grabaría una falla y usaría record/replay para moverme hacia atrás y hacia adelante en un depurador hasta que se rompa el primer invariante y su relación happens-before sea evidente. Repararía la propiedad, el bloqueo o la máquina de estados en lugar de agregar pausas (sleep), y revisaría reintentos, tiempos de espera, caídas y recuperación. Finalmente reproduciría la traza fallida, ejecutaría pruebas de estrés de carreras y de entrelazado, y verificaría con conciliación e inyección de fallas. Registraría la plataforma, las dependencias, la sobrecarga y el límite de evidencia, y eliminaría las trazas después de un período de retención definido.
Errores comunes
- Adivinar a partir del error final sin definir un invariante.
- Tratar una ejecución limpia del detector de carreras como prueba de que toda la lógica de concurrencia es correcta.
- Habilitar la grabación completa en producción sin considerar los riesgos de privacidad, disco, CPU y almacenamiento de trazas.
- Registrar marcas de tiempo pero no el estado o la entrada necesarios para distinguir los entrelazados.
- Ocultar una condición de carrera con pausas (sleep), más reintentos o cambios de prioridad de subprocesos.
- Reproducir solo el camino feliz e ignorar caídas, tiempos de espera, cancelaciones y límites externos.
- Omitir la conciliación de negocio, las pruebas de estrés, la inyección de fallas y un registro de regresión reproducible tras la reparación.
Preguntas de seguimiento y respuestas
¿Puede record/replay demostrar que no existe ningún error de concurrencia?
No. Demuestra que una grabación puede reproducirse en un entorno y límite de entrada compatibles, y ayuda a localizar un problema en esa ejecución específica. Otras planificaciones, plataformas, servicios externos y rutas aún requieren detección de carreras, pruebas de estrés e inyección de fallas.
¿Qué sucede si la reproducción altera los tiempos?
La grabación puede añadir sobrecarga o admitir solo eventos seleccionados. Compare las condiciones del desencadenante y las métricas clave antes y después de la grabación; luego coteje con múltiples trazas, perturbación del planificador y pruebas de estrés independientes. Si no se puede mantener la representatividad, trate la reproducción como una pista y no como prueba única.
¿Cómo deben manejarse las trazas de fallas con datos confidenciales?
Utilice listas de permitidos de campos, censura (redaction) o tokenización durante la recolección, restrinja el alcance de acceso y de inquilinos, y aplique controles de cifrado, retención y eliminación. Reproduzca la entrada más pequeña posible en un entorno aislado y nunca copie credenciales sin procesar ni datos de clientes en la infraestructura de depuración.
¿Cuándo debe convertirse el problema en una reparación arquitectónica?
Escale a un cambio arquitectónico cuando múltiples subprocesos o servicios mantengan el mismo invariante o cuando los parches de bloqueos y reintentos no logren establecer una propiedad clara. Migre hacia un único escritor, una máquina de estados explícita, un límite de transacción o un protocolo de mensajes verificable, acompañados de planes de migración, compatibilidad y reversión. Reemplazar únicamente el depurador no constituye una solución arquitectónica.