Quais são as melhores bibliotecas Haskell para operacionalizar um programa? [fechadas]

115

Se vou colocar um programa em produção, há várias coisas que preciso que esse programa faça para considerá-lo "operacionalizado" - ou seja, executando e podendo ser mantido de forma mensurável e verificável por engenheiros e equipe de operações. Para meus propósitos, um programa operacionalizado deve:

  • Ser capaz de fazer logon em vários níveis (ex: depuração, aviso, etc.).
  • Ser capaz de coletar e compartilhar métricas / estatísticas sobre os tipos de trabalho que o programa está fazendo e quanto tempo esse trabalho está demorando. Idealmente, as métricas coletadas estão disponíveis em um formato compatível com ferramentas de monitoramento comumente usadas, como Ganglia , ou podem ser modificadas.
  • Ser configurável, de preferência através de um sistema que permite que as propriedades configuradas nos programas em execução sejam atualizadas sem reiniciar os referidos programas.
  • Pode ser implantado em servidores remotos de maneira repetível.

No mundo Scala, existem boas bibliotecas para lidar com pelo menos os três primeiros requisitos. Exemplos:

Quanto à implantação, uma abordagem adotada no mundo Scala é agrupar o bytecode e as bibliotecas que compõem o programa com algo como assembly-sbt e , em seguida, enviar o pacote resultante (um "JAR gordo") para servidores remotos com uma ferramenta como Capistrano que executa comandos em paralelo sobre SSH. Este não é um problema que necessite de ferramentas específicas de um idioma, mas estou curioso para saber se essa ferramenta existe na comunidade Haskell.

Provavelmente, existem bibliotecas Haskell que fornecem as características que descrevi acima. Gostaria de saber quais das bibliotecas disponíveis são consideradas "melhores"; isto é, que são mais maduros, bem mantidos, comumente usados ​​na comunidade Haskell e exemplares das melhores práticas de Haskell.

Se houver quaisquer outras bibliotecas, ferramentas ou práticas em torno de tornar o código Haskell "pronto para produção", eu adoraria saber sobre elas também.

Alex Payne
fonte
1
O quarto marcador pode causar problemas, já que Haskell é compilado para nativo. Você pode tentar compilar estaticamente, o que pode ou não funcionar, mas o ideal é que você tenha um ambiente semelhante no servidor de produção do que no servidor de desenvolvimento. Cabal-dev é um ambiente em área restrita, que pode ser adequado para transferência para outras máquinas. Mesmo assim, seria necessário que pelo menos as bibliotecas básicas fossem instaladas na máquina de destino.
Masse
1
Com relação a outras ferramentas e técnicas, esta pergunta do SO tem uma visão geral: stackoverflow.com/questions/3077866/…
Don Stewart
1
Outra coisa - você pode acessar nos sistemas * nix uma grande quantidade de estatísticas e metadados do processo diretamente através do sistema de arquivos / proc. Portanto, se você escrever algumas rotinas para introspectar isso, ajudará a substituir a falta de ganchos diretos no tempo de execução.
sclv
1
implantar um binário é fácil, desde que você construa no mesmo ambiente (você deve ter um servidor de teste se o seu computador tiver uma arquitetura diferente). Então você pode rsync o binário e quaisquer arquivos externos. Não há biblioteca ssh para haskell para executar comandos de reinicialização automaticamente, mas você pode usar o capistrano.
Greg Weber
1
@tchrist Ele passa o resto do primeiro parágrafo e a lista com marcadores imediatamente após a palavra operacionalizada, explicando seu significado em inglês simples.
Will McCutchen

Respostas:

54

Esta é uma grande pergunta! Aqui está um primeiro corte.

Ser capaz de fazer logon em vários níveis (ex: depuração, aviso, etc.).

hslogger é facilmente a estrutura de registro mais popular.

Ser capaz de coletar e compartilhar métricas / estatísticas sobre os tipos de trabalho que o programa está fazendo e quanto tempo esse trabalho está demorando. Idealmente, as métricas coletadas estão disponíveis em um formato compatível com ferramentas de monitoramento comumente usadas, como Ganglia, ou podem ser modificadas.

Não conheço nenhuma ferramenta de relatório padronizada, no entanto, extrair relatórios de +RTS -sfluxos (ou por meio de sinalizadores de saída de perfil) foi algo que fiz no passado.

$ ./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

Você também pode obter isso em um formato legível 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, você poderia anexar a um runtime GHC em execução em um soquete e olhar para essas estatísticas de GC interativamente, mas atualmente isso não é muito fácil (precisa de ligações FFI para a interface "rts / Stats.h"). Você pode anexar a um processo usando ThreadScopee monitorar o comportamento do GC e do encadeamento.

Sinalizadores semelhantes estão disponíveis para perfis incrementais, de tempo e espaço registrados , que podem ser usados ​​para monitoramento (por exemplo, esses gráficos podem ser construídos de forma incremental).

hpccoleta muitas estatísticas sobre a execução do programa, por meio de seu Tixtipo, e as pessoas escreveram ferramentas para registrar por fração de tempo o código que está sendo executado.

Ser configurável, de preferência através de um sistema que permite que as propriedades configuradas nos programas em execução sejam atualizadas sem reiniciar os referidos programas.

Várias ferramentas estão disponíveis para isso, você pode fazer o recarregamento de estado no estilo xmonad; ou vá para a troca de código via plugins* packages ou hint. Alguns deles são mais experimentais do que outros.

Implantações reproduzíveis

Galois lançou recentemente cabal-dev, que é uma ferramenta para fazer compilações reproduzíveis (ou seja, as dependências têm escopo e são controladas).

Don Stewart
fonte
6
O pacote dyre supostamente abstrai o recarregamento de estado no estilo xmonad, então deve ser mencionado em particular, eu acho. No entanto, ele une recompilação e reimplantação, portanto, trata realmente de mudanças em uma máquina com toda a cadeia de ferramentas. Para reimplantações remotas, você quer algo mais parecido com o estado ácido, embora seja um pouco pesado para o meu gosto. Eu tenho essa abstração mvar persistente que tem garantias mais fracas, mas que você pode simplesmente tratar como um MVar simples que magicamente é preenchido em cada inicialização de um binário com os últimos dados que ele continha.
sclv
2
Além disso, a nova EventLogestrutura de registro do GHC (usando +RTS -lem tempo de execução) transmite a saída para um arquivo, que pode ser visualizado com qualquer ferramenta de leitura do formato de registro de eventos.
Don Stewart
2
Um programa irá emitir logs de seus eventos, como este: galois.com/~dons/tmp/A.event.log - que pode ser visualizado como - i.imgur.com/QAe6r.png . Eu poderia imaginar a construção de outras ferramentas de monitoramento em cima deste formato.
Don Stewart
2
Observe também que muitas das ferramentas de criação de perfil são ótimas para teste, mas não tanto para código de produção. Deixando de lado a sobrecarga, -prof por exemplo só pode ser usado com um único processador.
sclv
9
  • Em relação à configuração, descobri que o ConfigFile é útil para meus projetos. Eu o uso para todos os meus daemons em produção. Não é atualizado automaticamente.
  • Eu uso cabal-dev para criar compilações reproduzíveis em ambientes (local, dev, colega-local). Realmente, cabal-dev é indispensável, especialmente por sua capacidade de oferecer suporte a versões locais com patches de bibliotecas dentro do diretório do projeto.
  • Pelo que vale a pena, eu escolheria o recarregamento de estado no estilo xmonad. Pureza de Haskell torna isso trivial; a migração é um problema, mas é assim mesmo. Experimentei hsplugins e dica para meu IRCd e, no primeiro caso, havia um problema de tempo de execução do GHC e, no último, uma falha de segmentação. Deixei os branches no Github para post mortem posterior: https://github.com/chrisdone/hulk

Exemplo de ConfigFile:

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

Gostaria de repetir tudo o que Don disse e adicionar alguns conselhos gerais.

Por exemplo, duas ferramentas e bibliotecas adicionais que você pode querer considerar:

  • QuickCheck para teste baseado em propriedade
  • hlint como uma versão estendida de-Wall

Ambos são direcionados à qualidade do código.

Como prática de codificação, evite Lazy IO. Se você precisa de streaming de IO, vá com uma das bibliotecas iteratee, como enumerator . Se você olhar em Hackage, verá bibliotecas como http-enumerator que usam um estilo de enumerador para solicitações http.

Quanto à escolha de bibliotecas para hackeamento, às vezes pode ajudar ver quantos pacotes dependem de algo. Veja facilmente as dependências reversas de um pacote. Você pode usar este site, que espelha o hackeamento:

Se seu aplicativo acaba fazendo loops apertados, como um servidor da web que lida com muitas solicitações, a preguiça pode ser um problema na forma de vazamentos de espaço. Freqüentemente, isso é uma questão de adicionar anotações de rigidez nos lugares certos. Criação de perfis, experiência e leitura básica são as principais técnicas que conheço para combater esse tipo de coisa. A melhor referência de perfil que conheço é o Capítulo 25 do Real-World Haskell .

Jason Dagit
fonte