En pocas palabras, ¿deberíamos diseñar la muerte en nuestros programas, procesos e hilos a un nivel bajo, por el bien del sistema en general?
Las fallas suceden. Los procesos mueren. Planificamos el desastre y ocasionalmente nos recuperamos de él. Pero rara vez diseñamos e implementamos programas impredecibles de muerte. Esperamos que los tiempos de actividad de nuestros servicios sean siempre que nos interese mantenerlos en funcionamiento.
Un macroejemplo de este concepto es Chaos Monkey de Netflix , que termina aleatoriamente las instancias de AWS en algunos escenarios. Afirman que esto les ha ayudado a descubrir problemas y construir sistemas más redundantes.
De lo que estoy hablando es de nivel inferior. La idea es que los procesos tradicionalmente de larga duración salgan aleatoriamente. Esto debería forzar la redundancia en el diseño y, en última instancia, producir sistemas más resistentes.
¿Este concepto ya tiene un nombre? ¿Ya se está utilizando en la industria?
EDITAR
Según los comentarios y las respuestas, me temo que no fui claro en mi pregunta. Para mayor claridad:
- Sí, quiero decir al azar,
- Sí, quiero decir en producción, y
- no, no solo para probar.
Para explicar, me gustaría dibujar una analogía con los organismos multicelulares.
En la naturaleza, los organismos consisten en muchas células. Las células se bifurcan para crear redundancia, y finalmente mueren. Pero siempre debe haber suficientes células del tipo correcto para que el organismo funcione. Este sistema altamente redundante también facilita la curación cuando se lesiona. Las células mueren para que el organismo viva.
La incorporación de la muerte aleatoria en un programa obligaría al gran sistema a adoptar estrategias de redundancia para seguir siendo viable. ¿Estas mismas estrategias ayudarían al sistema a mantenerse estable frente a otros tipos de fallas impredecibles?
Y, si alguien ha intentado esto, ¿cómo se llama? Me gustaría leer más al respecto si ya existe.
Respuestas:
No.
Deberíamos diseñar un manejo adecuado de rutas incorrectas y diseñar casos de prueba (y otras mejoras de procesos) para validar que los programas manejan bien estas condiciones excepcionales. Cosas como Chaos Monkey pueden ser parte de eso, pero tan pronto como se haga "debe bloquearse aleatoriamente" un requisito, los bloqueos aleatorios reales se convierten en cosas que los probadores no pueden presentar como errores.
fuente
El proceso de introducir defectos en el software o en el hardware para probar los mecanismos de tolerancia a fallas se llama inyección de fallas .
De Wikipedia:
fuente
Si. No, quizás.
La terminación periódica es una espada de dos filos. Te golpearán con un borde u otro, y el menor de los dos males depende de tu situación.
Una ventaja es la confiabilidad: si obliga al programa a finalizar de forma aleatoria (o previsible) y de manera ordenada, puede estar preparado para ese evento y lidiar con él. Puede garantizar que el proceso saldrá cuando no esté ocupado haciendo algo útil. Esto también garantiza que los errores que se manifiesten más allá del tiempo de ejecución sancionado no criarán sus cabezas feas en la producción, lo cual es algo bueno. Apache HTTPD tiene una configuración que le permitirá ajustar cuántas solicitudes servirá un proceso secundario (o hilo en versiones más recientes) antes de finalizar.
La otra ventaja también es la fiabilidad: si no permite que el programa se ejecute por mucho tiempo, nunca encontrará errores que se manifiesten con el tiempo. Cuando finalmente te encuentras con uno de esos errores, es mucho más probable que el programa devuelva una respuesta incorrecta o no la devuelva. Peor aún, si ejecuta muchos subprocesos del mismo trabajo, un error inducido por el tiempo o el recuento podría afectar un gran número de tareas a la vez y dar como resultado un viaje de las 3 a.m. a la oficina.
En una configuración en la que ejecuta muchos de los mismos hilos (por ejemplo, en un servidor web), la solución práctica es adoptar un enfoque mixto que dé como resultado una tasa de fallas aceptable. Si ejecuta 100 subprocesos, ejecutar una relación de corto a largo de 99: 1 significa que solo uno exhibirá errores a largo plazo mientras que los demás continúan haciendo lo que hacen sin fallar. Compare eso con la ejecución del 100%, donde corre un riesgo mucho mayor de que todos los hilos fallen al mismo tiempo.
Cuando tenga un solo subproceso, probablemente sea mejor dejarlo funcionar y fallar, porque el tiempo muerto durante un reinicio puede dar como resultado una latencia no deseada cuando hay trabajo real que hacer para completar con éxito.
En cualquier caso, es importante que haya algo que supervise los procesos para que puedan reiniciarse de inmediato. Además, no hay una ley que diga que sus decisiones iniciales sobre cuánto tiempo debe ejecutarse un proceso deben ser inamovibles. La recopilación de datos operativos lo ayudará a ajustar su sistema para mantener las fallas a un nivel aceptable.
Recomendaría no hacer una terminación aleatoria, porque eso hace que sea más difícil detectar errores relacionados con el tiempo. Chaos Monkey lo hace para asegurarse de que el software de supervisión funcione, lo cual es un problema ligeramente diferente.
fuente
¿Realmente quieres decir al azar? Hacer que su software se mate al azar suena como una idea terrible. ¿Qué punto serviría eso?
Supongo que lo que realmente quiere decir es que deberíamos ser realistas sobre los procesos / subprocesos de larga ejecución y aceptar que cuanto más tiempo se ejecuten, más probable es que hayan encontrado algún tipo de error oculto y se hayan convertido en un problema no funcional estado. Por lo tanto, como medida puramente pragmática, la vida útil de los procesos y subprocesos debe ser limitada.
Creo que a finales de los 90 el servidor web Apache usaba algo como esto. Tenían un grupo de procesos de trabajo (no subprocesos) y cada proceso de trabajo se eliminaría después de una vida útil fija. Esto evitó que el servidor estuviera monopolizado por procesos de trabajo que se habían atascado en algún estado patológico.
No he trabajado en el área por algún tiempo, así que no sé si este sigue siendo el caso.
fuente
El problema que veo es que si tal programa muere, solo diremos "Oh, es solo otra terminación aleatoria, no hay nada de qué preocuparse". Pero, ¿qué pasa si hay un problema real que necesita solución? Será ignorado.
Los programas ya fallan "al azar" debido a que los desarrolladores crean mystaykes, los errores que entran en los sistemas de producción, fallas de hardware, etc. Cuando esto ocurre, queremos saberlo para poder solucionarlo. Diseñar la muerte en programas solo aumenta la probabilidad de fracaso y solo nos obligaría a aumentar la redundancia, lo que cuesta dinero.
No veo nada de malo en matar procesos al azar en un entorno de prueba cuando se prueba un sistema redundante (esto debería estar sucediendo más de lo que es) pero no en un entorno de producción. ¿Sacaríamos un par de discos duros de un sistema de producción en vivo cada pocos días, o desactivaríamos una de las computadoras en una aeronave cuando está volando llena de pasajeros? En un escenario de prueba, bien. En un escenario de producción en vivo, prefiero no hacerlo.
fuente
Agregar código de salida aleatorio a la aplicación no debería ser necesario. Los probadores pueden escribir scripts que eliminan aleatoriamente los procesos de la aplicación.
En las redes, es necesario simular una red poco confiable para probar la implementación de un protocolo. Esto no se integra en el protocolo; se puede simular a nivel del controlador del dispositivo o con algún hardware externo.
No agregue código de prueba al programa para situaciones que se pueden lograr externamente.
Si esto está destinado a la producción, ¡no puedo creer que sea serio!
En primer lugar, a menos que los procesos salgan abruptamente de modo que se pierdan las transacciones en curso y los datos volátiles, entonces no es una implementación honesta del concepto. Las salidas planificadas y elegantes, incluso si se sincronizan aleatoriamente, no ayudan adecuadamente a preparar la arquitectura para lidiar con accidentes reales, que no son elegantes.
Si se incorporan disfunciones reales o realistas en la aplicación, podrían provocar daños económicos, al igual que las disfunciones reales, y el daño económico intencional es básicamente un acto criminal casi por definición.
Es posible que pueda salirse con la suya en las cláusulas del acuerdo de licencia que exime la responsabilidad civil de los daños derivados del funcionamiento del software, pero si esos daños son por diseño, es posible que no pueda renunciar a la responsabilidad penal.
Ni siquiera piense en acrobacias como esta: haga que funcione de la manera más confiable posible y coloque escenarios de fallas falsas solo en configuraciones o configuraciones especiales.
fuente
Es posible que desee buscar " recuperación proactiva " y " rejuvenecimiento " en el contexto de sistemas distribuidos tolerantes a fallas, para tratar fallas arbitrarias (es decir, no solo procesos bloqueados, sino también datos corruptos y comportamiento potencialmente malicioso). Se ha investigado mucho con qué frecuencia y en qué condiciones debe reiniciarse un proceso (en sentido abstracto, en realidad puede ser una VM o un host). Intuitivamente, puede comprender las ventajas del enfoque como preferir lidiar con un proceso muerto que con un proceso traidor ...
fuente
Esto realmente no es diferente a las pruebas. Si está diseñando una solución de conmutación por error siempre disponible (como Netflix), entonces sí, debe probarla. Sin embargo, no sé si las salidas aleatorias esparcidas por la base del código son una forma adecuada de probar eso. A menos que esté realmente decidido a probar que su diseño es resistente a dispararse en el pie, parecería más apropiado probarlo manipulando el entorno alrededor del código y verificando que se comporta adecuadamente.
Si no está diseñando sistemas redundantes, entonces no, no debe agregar esa función porque agregó algunas salidas aleatorias. Simplemente debe eliminar las salidas aleatorias, y luego no tendrá ese problema. Su entorno aún puede fallar en usted, momento en el que lo identificará como no compatible / no solucionará o endurecerá su código contra esa falla y agregará una prueba para ello. Hágalo con la frecuencia suficiente y se dará cuenta de que en realidad está diseñando un sistema redundante; consulte el escenario n. ° 1.
En algún momento, puede determinar que ya no está seguro de qué fallas se manejan o no. Ahora puede comenzar a sacar la alfombra al azar para detectar los puntos de falla.
Lo único interesante del ejemplo de Netflix es que ejecutan estas pruebas en producción. Eso tiene cierto sentido: algunos errores realmente son solo cosas de producción que son muy difíciles o imposibles de simular en un entorno aislado. Sin embargo, sospecho que Netflix pasó mucho tiempo en entornos de prueba antes de que se sintieran lo suficientemente cómodos como para hacerlo en producción. Y realmente todo lo que están haciendo es tratar de que se produzcan bloqueos durante el horario comercial, lo que tiene cierto sentido para su mercado, pero no para muchos otros.
fuente
El término que estás buscando ha sido recientemente acuñado por Nassim Nicholas Taleb: Antifragility. Su libro Antifragile es definitivamente recomendable. Apenas menciona TI, pero los paralelos tácitos y obvios son muy inspiradores. Su idea es extender la escala de frágil <-> robusto a frágil <-> robusto <-> antifrágil. Rompe frágiles con eventos aleatorios, gestiones robustas con eventos aleatorios y ganancias antifrágiles con eventos aleatorios.
fuente
Depende. Me di cuenta de que los programadores tienden a generalizar en exceso las técnicas que se aplican a su dominio específico, ignorando todas las demás. Por ejemplo, hacer que el programa se libere al costo de corregir todos los errores puede ser bueno ... a menos que programe el controlador de la aeronave, el reactor nuclear, etc. "No optimice: el costo del programador es mayor que el costo de ejecutar el programa" no es necesario válido para HPC ya que un programa relativamente simple puede ocupar clúster durante meses, etc. (o incluso un programa popular que es utilizado por una gran cantidad de usuarios). Por lo tanto, incluso si la empresa X está haciendo Y por una muy buena razón, no es necesario que siga sus pasos, ya que su situación podría ser diferente.
Por lo general, las rutinas de manejo de errores son la parte peor probada del código, aunque parece simple, es difícil simular que no hay suficiente memoria o que no hay algún archivo importante. Por esa razón, leí textos que proponían que el núcleo de Unix fallara aleatoriamente algunas llamadas al sistema. Sin embargo, haría que los programas simples fueran más difíciles de escribir (si necesito conectar 3 bibliotecas C ++ para ejecutar un programa en 2 archivos una vez que no quiera molestarme con el manejo de errores). Incluso con excepciones, GC debe asegurarse de dejar un estado coherente (imagine una excepción en medio de agregar un nodo a la lista vinculada).
Cuantos más servicios distribuidos tenga, más fallas es la cuestión de "qué tan frecuente" y luego "si" o "cuándo". En los centros de datos, el reemplazo de discos en RAID es parte de las operaciones de rutina por lo que sé, no por fallas inesperadas. Si opera a gran escala, debe tenerlo en cuenta, ya que incluso si la probabilidad de falla de un componente es pequeña, es probable que algo falle.
No sé qué estás haciendo exactamente, pero para saber si vale la pena, debes pensar si la falla es algo que debes tener en cuenta (ya que ignorarlo cuesta) o es algo demasiado costoso de analizar (como tomar errores en cuenta los costos de tiempo de desarrollo).
fuente
El servidor IIS tiene una característica configurable que recicla automáticamente los procesos de los trabajadores, ya sea después de que hayan utilizado una cierta cantidad de memoria o después de atender una determinada cantidad de solicitudes o después de que hayan estado activos durante un período de tiempo específico. ( http://msdn.microsoft.com/en-us/library/ms525803(v=vs.90).aspx ) y ( http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/ 1652e79e-21f9-4e89-bc4b-c13f894a0cfe.mspx? Mfr = true )
Cuando un CONTENEDOR como IIS lo hace, tiene sentido proteger el servidor de procesos no autorizados. Sin embargo, preferiría mantener esto desactivado, porque no tiene sentido si ha probado suficientemente su código.
Ya trabajamos en capas poco confiables (hardware, red), por lo que nunca escribiría ningún código que matara sus hilos o procesos al azar intencionalmente. La matanza aleatoria también es una mala idea desde una perspectiva económica: nadie usaría mi API si supieran que la he programado para que se bloquee al azar. Por último, si tuviera que consumir una API o utilizar un sistema con hilos que se bloquean al azar, tendría que gastar mucho dinero para crear un mecanismo de monitoreo lo suficientemente robusto para poder dormir tranquilo por la noche.
En cambio, si estuviera desarrollando un sistema o una API, escribiría scripts o usaría un arnés que haría esto únicamente para probar la resistencia del sistema. Y haría una prueba de este tipo en todas las compilaciones para identificar compilaciones malas. Sin embargo, si bien esta sería una prueba necesaria, nunca podría ser una prueba "suficiente".
fuente
Hay una literatura relacionada con esta idea, se llama software Crash-Only (también Computación Orientada a la Recuperación) y puede comenzar con este documento de Usdea de Candea & Fox de 2003. En lugar de asesinatos aleatorios, el autor argumenta que puede mejorar la confiabilidad del sistema solo alguna vez detenga sus programas eliminándolos, por lo que tiene un solo interruptor de apagado como botón de apagado y una ruta de inicio de recuperación bien ejercitada.
Si bien no estoy seguro de qué tan bien se dio cuenta la idea, algunas de las técnicas específicas siguen siendo útiles. Por ejemplo, no confiar en su software para poder apagarse cuando se le solicite y, por lo tanto, usar programas de supervisión especializados (por ejemplo, supervisión, etc.), y también pensar cuidadosamente sobre qué estado del programa es esencial y asegurarse de que se grabe en los momentos apropiados en un almacén de datos diseñado para habilitar la recuperación (por ejemplo, una base de datos sql).
fuente
Realmente al azar, no. Pero probablemente sea una buena idea que los procesos / subprocesos de larga ejecución salgan / reinicien en un intervalo determinado, o después de haber estado inactivo durante una duración determinada (pero dependiente de ciertos criterios), o después de ejecutar un tipo particular de tarea. El estado de acumulación de procesos de ejecución prolongada que inevitablemente incluye cosas obsoletas, presumiblemente puede conservar la memoria evitando que se libere espacio de intercambio, todo lo cual se limpia (o debería) limpiarse cuando salen, mejorando la estabilidad general del sistema.
fuente
Depende del tipo de aplicación que esté diseñando.
Los bloqueos aleatorios son una excelente manera de probar y mejorar la solidez de los sistemas distribuidos (en red).
En el ejemplo de Netflix, cuando su programa depende de servicios remotos que pueden fallar por una variedad de razones que están fuera de su control (el disco duro falla, pérdida de energía, accidentes de meteoritos en el centro de datos, etc.). Sin embargo, su servicio debe seguir ejecutándose de alguna manera.
¿Cómo haces eso? Agregar redundancia y escalado es una solución común.
Por ejemplo, si un mouse mastica el cable de alimentación de su servidor, entonces su servicio debería tener alguna solución para seguir funcionando. Por ejemplo, puede mantener servidores de respaldo redundantes que comenzará a usar en su lugar.
Sin embargo, si su programa es una aplicación de proceso único que no funciona en una red, entonces matarlo no probará nada, ya que no hay forma de recuperarse de eso.
Aquí hay algunos comentarios adicionales sobre el concepto Chaos Monkeys http://www.codinghorror.com/blog/2011/04/working-with-the-chaos-monkey.html
fuente
Es posible que ocurra un cambio aleatorio de bits debido a la radiación cósmica . Este problema fue reconocido y se desarrollaron varias técnicas para evitar que ocurriera un cambio de bits.
Sin embargo, no es posible repararlo al 100%, y la corrupción de la memoria aún puede causar problemas, y estos problemas siguen ocurriendo ( con muy baja probabilidad ).
Ahora para responder a tu pregunta. Si necesita o no diseñar un sistema muy robusto, depende de lo que esté haciendo. Si necesita crear una nave espacial, es mejor que sea súper robusta, y luego deberá tener en cuenta todos los problemas posibles.
Si necesita diseñar una aplicación de escritorio normal, debería ver los bloqueos aleatorios como errores en su código.
fuente
Esto no parece tan absurdo de una idea.
El sistema operativo Android mata y reinicia aleatoriamente las aplicaciones / servicios del usuario todo el tiempo. En mi experiencia definitivamente me ha ayudado a pensar más profundamente sobre las condiciones de error, así como a diseñar arquitecturas más robustas.
fuente
onDestroy
,onPause
,onSaveInstanceState
, etc ... será jamás pidió a una actividad o servicio. A nivel de aplicación, ni siquiera hay unaonDestory
devolución de llamada. Entonces, sí, hay algunos ganchos para cierres elegantes, pero aún debe estar preparado para salidas aleatorias.onPause()
antes de que se elimine una actividad. Después de Honeycomb, tienes garantizado ese plusonStop()
. Las aplicaciones de Android son solo colecciones de actividades que están relacionadas y no hay un concepto de nivel de aplicación de nada en lo que respecta al ciclo de vida de la ejecución.