¿Cuáles son las mejores bibliotecas Haskell para poner en funcionamiento un programa? [cerrado]

115

Si voy a poner un programa en producción, hay varias cosas que necesito que el programa haga para considerarlo "operacionalizado", es decir, en ejecución y mantenible de manera medible y verificable tanto por ingenieros como por personal de operaciones. Para mis propósitos, un programa operativo debe:

  • Ser capaz de iniciar sesión en varios niveles (p. Ej., Depuración, advertencia, etc.).
  • Ser capaz de recopilar y compartir métricas / estadísticas sobre los tipos de trabajo que realiza el programa y cuánto tiempo lleva ese trabajo. Idealmente, las métricas recopiladas están disponibles en un formato que es compatible con las herramientas de monitoreo de uso común, como Ganglia , o pueden ser modificadas.
  • Ser configurables, idealmente a través de un sistema que permita actualizar las propiedades configuradas en los programas en ejecución sin reiniciar dichos programas.
  • Se puede implementar en servidores remotos de forma repetible.

En el mundo de Scala, existen buenas bibliotecas para hacer frente al menos a los tres primeros requisitos. Ejemplos:

En cuanto a la implementación, un enfoque adoptado en el mundo de Scala es agrupar el código de bytes y las bibliotecas que componen el programa de uno con algo como assembly-sbt , luego enviar el paquete resultante (un "JAR gordo") a servidores remotos con una herramienta como Capistrano que ejecuta comandos en paralelo a través de SSH. Este no es un problema que necesite herramientas específicas del idioma, pero tengo curiosidad por saber si tal herramienta existe en la comunidad de Haskell.

Probablemente existen bibliotecas de Haskell que proporcionan los rasgos que describí anteriormente. Me gustaría saber cuáles de las bibliotecas disponibles se consideran "mejores"; es decir, cuáles son los más maduros, bien mantenidos, de uso común en la comunidad de Haskell y ejemplares de las mejores prácticas de Haskell.

Si hay otras bibliotecas, herramientas o prácticas para hacer que el código Haskell esté "listo para producción", me encantaría conocerlas también.

Alex Payne
fuente
1
La cuarta viñeta puede causar problemas, ya que Haskell está compilado en nativo. Podría intentar compilar estáticamente, lo que podría funcionar o no, pero de manera óptima tendría un entorno similar en el servidor de producción que en el servidor de desarrollo. Cabal-dev es un entorno de espacio aislado, que podría ser adecuado para transferir a otras máquinas. Incluso entonces, sería necesario instalar al menos las bibliotecas base en la máquina de destino.
Misa
1
Con respecto a otras herramientas y técnicas, esta pregunta SO tiene una descripción general: stackoverflow.com/questions/3077866/…
Don Stewart
1
Otra cosa: puede acceder en los sistemas * nix a una gran cantidad de estadísticas de procesos y metadatos directamente a través del sistema de archivos / proc. Entonces, si escribe algunas rutinas para introspectar eso, ayuda a sustituir la falta de enlaces directos en el tiempo de ejecución.
sclv
1
La implementación de un binario es fácil siempre y cuando se construya en el mismo entorno (debe tener un servidor intermedio si su computadora tiene una arquitectura diferente). Luego, puede sincronizar el binario y cualquier archivo externo. No existe una biblioteca ssh para haskell para ejecutar automáticamente comandos de reinicio, pero puedes usar capistrano.
Greg Weber
1
@tchrist Pasa el resto del primer párrafo y la lista con viñetas inmediatamente después de la palabra operacionalizada explicando su significado en un lenguaje sencillo.
Will McCutchen

Respuestas:

54

¡Esta es una gran pregunta! Aquí tienes un primer corte.

Ser capaz de iniciar sesión en varios niveles (p. Ej., Depuración, advertencia, etc.).

hslogger es fácilmente el marco de registro más popular.

Ser capaz de recopilar y compartir métricas / estadísticas sobre los tipos de trabajo que realiza el programa y cuánto tiempo lleva ese trabajo. Idealmente, las métricas recopiladas están disponibles en un formato que es compatible con las herramientas de monitoreo de uso común, como Ganglia, o pueden ser modificadas.

No conozco ninguna herramienta de informes estandarizada, sin embargo, la extracción de informes de las +RTS -stransmisiones (o mediante indicadores de salida de generación de perfiles) ha sido algo que hice en el pasado.

$ ./A +RTS -s
64,952 bytes allocated in the heap
1 MB total memory in use
 %GC time       0.0%  (6.1% elapsed)
 Productivity 100.0% of total user, 0.0% of total elapsed

También puede obtenerlo en formato legible por máquina:

$ ./A +RTS -t --machine-readable

 [("bytes allocated", "64952")
 ,("num_GCs", "1")
 ,("average_bytes_used", "43784")
 ,("max_bytes_used", "43784")
 ,("num_byte_usage_samples", "1")
 ,("peak_megabytes_allocated", "1")
 ,("init_cpu_seconds", "0.00")
 ,("init_wall_seconds", "0.00")
 ,("mutator_cpu_seconds", "0.00")
 ,("mutator_wall_seconds", "0.00")
 ,("GC_cpu_seconds", "0.00")
 ,("GC_wall_seconds", "0.00")
 ]

Idealmente, podría conectarse a un tiempo de ejecución de GHC en ejecución a través de un socket y ver estas estadísticas de GC de forma interactiva, pero actualmente no es muy fácil (necesita enlaces FFI a la interfaz "rts / Stats.h"). Puede adjuntar a un proceso utilizando ThreadScopey supervisar el comportamiento de subprocesamiento y GC.

Se encuentran disponibles indicadores similares para la creación de perfiles de tiempo y espacio incrementales, registrados , que se pueden utilizar para la supervisión (por ejemplo, estos gráficos se pueden construir de forma incremental).

hpcrecopila una gran cantidad de estadísticas sobre la ejecución del programa, a través de su Tixtipo, y la gente ha escrito herramientas para registrar por intervalo de tiempo qué código se está ejecutando.

Ser configurables, idealmente a través de un sistema que permita actualizar las propiedades configuradas en los programas en ejecución sin reiniciar dichos programas.

Hay varias herramientas disponibles para esto, puede hacer una recarga de estado al estilo xmonad; o pasar a código hotswapping a través de plugins* paquetes o hint. Algunos de estos son más experimentales que otros.

Implementaciones reproducibles

Galois lanzó recientemente cabal-dev, que es una herramienta para realizar compilaciones reproducibles (es decir, las dependencias tienen un alcance y son controladas).

Don Stewart
fuente
6
Se supone que el paquete dyre abstrae la recarga de estado al estilo xmonad, por lo que creo que debería mencionarse en particular. Sin embargo, une la recompilación y la redistribución, por lo que realmente se trata de cambios en una máquina con toda la cadena de herramientas. Para redespliegues remotas, quieres algo más parecido al estado ácido, aunque es un poco pesado para mi gusto. Tengo esta abstracción de mvar persistente que tiene garantías más débiles, pero que puede tratar como un MVar simple que se rellena mágicamente en cada lanzamiento de un binario con los últimos datos que contenía.
sclv
2
Además, el nuevo EventLogmarco de registro de GHC (que se usa +RTS -len tiempo de ejecución) transmite la salida a un archivo, que se puede visualizar con cualquier herramienta que lea el formato de registro de eventos.
Don Stewart
2
Un programa emitirá registros de sus eventos, como este: galois.com/~dons/tmp/A.event.log - que puede visualizarse como - i.imgur.com/QAe6r.png . Me imagino construyendo otras herramientas de monitoreo sobre este formato.
Don Stewart
2
También tenga en cuenta que muchas de las herramientas de creación de perfiles son excelentes para realizar pruebas, pero no tanto para el código de producción. Dejando de lado los gastos generales, -prof, por ejemplo, solo se puede utilizar con un único procesador.
sclv
9
  • Con respecto a la configuración, he encontrado que ConfigFile es útil para mis proyectos. Lo uso para todos mis demonios en producción. No se actualiza automáticamente.
  • Utilizo cabal-dev para crear compilaciones reproducibles en todos los entornos (local, dev, colega local). Realmente cabal-dev es indispensable, especialmente por su capacidad para admitir versiones locales parcheadas de bibliotecas dentro del directorio del proyecto.
  • Por lo que vale, iría con la recarga de estado al estilo de xmonad. Pureza de Haskell hace que esto sea trivial; la migración es un problema, pero de todos modos lo es. Experimenté con hsplugins y hint para mi IRCd y en el primer caso hubo un problema de tiempo de ejecución de GHC y en el último una falla de segmentación. Dejé las ramas en Github para una autopsia posterior: https://github.com/chrisdone/hulk

Ejemplo de ConfigFile:

# Default options
[DEFAULT]
hostname: localhost
# Options for the first file
[file1]
location: /usr/local
user: Fred
Christopher Done
fuente
9

Me haría eco de todo lo que dijo Don y agregaría algunos consejos generales.

Por ejemplo, dos herramientas y bibliotecas adicionales que quizás desee considerar:

  • QuickCheck para pruebas basadas en propiedades
  • hlint como una versión extendida de-Wall

Ambos están dirigidos a la calidad del código.

Como práctica de codificación, evite Lazy IO. Si necesita IO de transmisión, vaya con una de las bibliotecas iteratee como enumerator . Si observa Hackage , verá bibliotecas como http-enumerator que utilizan un estilo de enumerador para las solicitudes http.

En cuanto a la selección de bibliotecas sobre piratería, a veces puede ayudar ver cuántos paquetes dependen de algo. Vea fácilmente las dependencias inversas de un paquete que puede usar este sitio web, que refleja el pirateo:

Si su aplicación termina haciendo ciclos ajustados, como un servidor web que maneja muchas solicitudes, la pereza puede ser un problema en forma de fugas de espacio. A menudo, se trata de agregar anotaciones de rigor en los lugares correctos. La elaboración de perfiles, la experiencia y el núcleo de lectura son las principales técnicas que conozco para combatir este tipo de cosas. La mejor referencia de creación de perfiles que conozco es el Capítulo 25 de Haskell del mundo real .

Jason Dagit
fuente