Introdução do tradutor
Este artigo é sobre Erlang , mas tudo o que foi dito é igualmente aplicável ao Elixir , uma linguagem funcional executada sobre a mesma máquina virtual BEAM . Apareceu em 2012 e agora está se desenvolvendo ativamente. O Elixir obteve a sintaxe mais familiar, além de amplos recursos de metaprogramação , mantendo os benefícios do Erlang.
Mais do tradutorUm artigo de 2016, mas trata-se de conceitos básicos que não expiram.
As referências a conceitos e comentários meus (o tradutor) estão localizadas entre colchetes []
e são marcadas com uma “nota do tradutor”.
Se você achar que algumas partes da tradução não estão corretas o suficiente, principalmente em termos de termos, ou se encontrar outros erros, entre em contato. Corrigirei com prazer.
Agradecimentos especiais a Jan Gravshin por sua ajuda na revisão e edição do texto.
Esta é uma transcrição gratuita (ou uma paráfrase longa?) Da minha apresentação na conferência ConnectDev'16 organizada pela Genetec.

Eu acredito que a maioria das pessoas aqui nunca programou em Erlang. Você já deve ter ouvido falar ou sabe o nome. Portanto, minha apresentação afetará apenas os conceitos de alto nível de Erlang e de maneira a ser útil em seus trabalhos ou projetos paralelos, mesmo que você nunca se depare com esse idioma.

Se você já se interessou por Erlang, ouviu sobre o lema "Deixe bater" [ "Deixe cair" - aprox. tradutor ]. Meu primeiro encontro com ele me fez pensar sobre o que diabos era. O Erlang deveria ser ótimo para execução multithread e tolerância a falhas, mas aqui eles sugerem que eu deixe tudo cair: exatamente o oposto do comportamento do sistema que eu realmente quero. A proposta é surpreendente, mas, no entanto, o Zen de Erlang está diretamente relacionado a ela.

De certa forma, usar "Let it Crash" para Erlang é tão divertido quanto "Blow it up" [ " Blow it !" - aprox. tradutor ] para ciência de foguetes. "Explodir" é talvez a última coisa que você deseja na ciência de foguetes, e a catástrofe do Challenger é um lembrete vívido disso. Por outro lado, se você olhar para a situação de maneira diferente, os foguetes e todo o sistema de propulsão estão lidando com combustíveis perigosos que podem e vão explodir (e esse é um momento arriscado), mas de maneira tão controlada que eles podem ser usados para organizar o espaço viajando ou enviando cargas em órbita.
E o ponto aqui está realmente no controle; você pode tentar considerar a ciência dos foguetes como uma maneira de domar corretamente as explosões - ou pelo menos o poder delas - para fazer o que quiser com elas. Por sua vez, você pode ver "Deixe travar" do mesmo ângulo: trata-se de tolerância a falhas. A idéia não está em falhas generalizadas não controladas, é transformar falhas, exceções e falhas em ferramentas que podem ser usadas.

Queda próxima [Queda próxima - aprox. tradutor ] e o recozimento controlado são um exemplo real de combate ao fogo com fogo. Em Saguenay-lac-Saint-Jean, a região de onde eu venho, os campos de mirtilo são regularmente queimados de maneira controlada para ajudar a estimular e retomar seu crescimento. Muitas vezes, é possível ver áreas insalubres da floresta derrubadas pelo fogo para evitar incêndios, de modo que isso aconteça sob supervisão e controle adequados. O objetivo principal é remover material combustível para que um incêndio natural não possa se espalhar mais.
Em todas essas situações, o poder destrutivo do fogo varrendo culturas ou florestas é usado para curar culturas ou impedir a destruição muito maior e descontrolada de florestas.
Eu acho que o significado de "Let it crash" é exatamente isso. Se pudermos tirar proveito de falhas, falhas e exceções e torná-lo uma maneira gerenciável, eles deixarão de ser aquele evento assustador que precisa ser evitado e, em troca, se transformarão em um elemento de construção poderoso para a montagem de grandes sistemas confiáveis.

Assim, a questão passa a ser como garantir que as falhas sejam mais construtivas do que destrutivas. O principal chip para isso em Erlang é o processo. Os processos Erlang são completamente isolados e têm uma arquitetura inseparável (não compartilham nada). Nenhum processo pode rastrear a memória de outra pessoa ou afetar o trabalho realizado distorcendo os dados usados. Isso é bom porque significa que um processo de morte com uma garantia de 100% manterá seus problemas para si e fornecerá ao sistema um isolamento de falhas muito forte.
Os processos em Erlang também são extremamente leves, para que milhares e milhares deles possam trabalhar simultaneamente sem problemas. A idéia é usar quantos processos forem necessários , e não quantos você puder pagar . Imagine que existe uma linguagem de programação orientada a objetos na qual, a qualquer momento, é permitido ter no máximo 32 objetos trabalhando simultaneamente. Você chegaria rapidamente à conclusão de que, para criar programas, as restrições são muito rígidas e bastante ridículas. A presença de muitos pequenos processos fornece maior variabilidade de falhas. Em um mundo onde queremos colocar o poder da falha ao serviço, isso é bom!
O mecanismo dos processos em Erlang pode parecer um pouco estranho. Quando você escreve um programa em C, você tem uma grande função main()
que faz uma tonelada de tudo. Este é o ponto de entrada para o programa. Não existe tal coisa em Erlang. Nenhum dos processos é o principal. Cada processo inicia uma função, e essa função desempenha o papel de main()
desse processo específico.
Agora temos um enxame de abelhas, mas deve ser muito difícil enviá-las para fortalecer a colméia se elas não puderem se comunicar de forma alguma. Onde as abelhas dançam [ abelhas dançam - aprox. tradutor ], Erlang processa as mensagens.

As mensagens são a forma mais intuitiva de comunicação em um ambiente competitivo. Ela é uma das pessoas mais velhas com quem lidar, desde os dias em que escrevemos cartas e as enviamos por correios a cavalo até mecanismos mais bizarros como os semáforos de Napoleão [ semáforo óptico - aprox. tradutor ] mostrado na ilustração. Neste último caso, você simplesmente envia um monte de caras para as torres, envia uma mensagem para eles e eles acenam sinalizadores para transmitir dados por longas distâncias de maneira mais rápida que os cavalos cansados. Gradualmente, esse método foi substituído por um telégrafo, que, por sua vez, mudou o telefone e o rádio, e agora temos todas essas tecnologias da moda para enviar mensagens muito longe e muito rápido.
Um aspecto extremamente importante de todas essas mensagens, especialmente nos velhos tempos, é que tudo era assíncrono e as mensagens eram copiadas. Ninguém ficou parado na varanda o dia inteiro esperando o correio retornar e ninguém (suspeito) estava sentado perto do semáforo, esperando uma resposta. Você enviou uma mensagem e retornou à sua empresa e, com o tempo, alguém lhe informou que uma resposta havia chegado.
Isso é bom - se o outro lado não responder, você não ficará preso na varanda até morrer. Por outro lado, o destinatário, por outro lado, não será confrontado com o fato de que uma mensagem recentemente recebida desapareceu ou mudou magicamente de repente, se você morrer repentinamente. Os dados devem ser copiados ao enviar mensagens. Esses dois princípios garantem que a falha durante a comunicação não leve a um estado distorcido ou irreparável [ estado - aprox. tradutor ]. Erlang implementa ambos.
Cada processo possui sua própria caixa de correio para todas as mensagens recebidas. Qualquer pessoa pode gravar na caixa de correio do processo, mas apenas o proprietário da caixa tem a oportunidade de examiná-la. Por padrão, as mensagens são processadas na ordem em que são recebidas, mas alguns recursos, como correspondência de padrões [ correspondência de padrões - aprox. tradutor ] permitem alterar prioridades e se concentrar constante ou temporariamente em qualquer tipo de mensagem.

Alguns de vocês notarão a estranheza no que eu digo. Continuo repetindo que o isolamento e a independência são tão maravilhosos que os componentes do sistema podem morrer e cair sem afetar o resto. Mas também mencionei a comunicação entre muitos processos ou agentes.
Cada vez no início do diálogo de dois processos, uma dependência implícita entre eles aparece. Um estado implícito surge no sistema que conecta os dois. Se o processo A envia uma mensagem para o processo B, e B morre sem responder, A pode esperar uma resposta para sempre ou depois de algum tempo se recusar a se comunicar. A segunda é uma estratégia aceitável, mas é muito ambígua: não está totalmente claro se o lado remoto morreu ou está ocupado por tanto tempo e as mensagens sem contexto podem chegar à sua caixa de correio.
Em troca, Erlang nos fornece dois mecanismos para resolver esse problema: monitores e links [ links - aprox. tradutor ].
Monitores são sobre ser um observador. Você decide ficar de olho no processo e, se ele morrer por algum motivo, uma mensagem o notificará do que aconteceu na sua caixa de entrada. Você pode responder a isso e tomar decisões com base nas informações encontradas. O segundo processo nunca saberá que você fez tudo isso. Portanto, os monitores são muito bons se você é um observador. tradutor ] ou cuide do status do parceiro.
Links [ links - aprox. tradutor ] - bidirecional, e a criação de um combina o destino de ambos os processos relacionados. Quando um processo morre, todos os processos associados a ele recebem um comando para finalizar [ sinal de saída - aprox. tradutor ]. Esta equipe, por sua vez, mata outras pessoas [ relacionadas - aprox. tradutor ] processos.
Tudo isso se torna realmente interessante, porque você pode usar monitores para detectar rapidamente falhas e usar a ligação como um projeto arquitetônico que permite combinar vários processos para que a falha se espalhe para eles como um todo. Sempre que meus componentes independentes se tornarem viciados um com o outro, eu posso começar a adicionar isso ao programa. Isso é útil porque evita que o sistema caia acidentalmente em estados instáveis e parcialmente alterados. As conexões garantem aos desenvolvedores: se algo quebrou, ele quebrou completamente, deixando para trás uma folha em branco e de forma alguma afetou os componentes que não participaram do exercício.
Para esta ilustração, escolhi a imagem de alpinistas amarrados com uma corda de segurança. Se os escaladores estiverem conectados apenas um ao outro, eles se encontrarão em uma posição miserável. Cada vez que um único alpinista desliza, o restante da equipe morre imediatamente. Não é uma boa maneira de fazer negócios.
Em vez disso, Erlang permite especificar que alguns processos são especiais e marcá-los com o parâmetro trap_exit
. Eles poderão receber comandos de saída enviados por meio de comunicações e convertê-los em mensagens. Isso permitirá que eles solucionem problemas e possivelmente baixem um novo processo para concluir o trabalho do falecido. Ao contrário dos escaladores, um processo especial desse tipo não pode impedir a queda do processo de parceria; isso já é de responsabilidade do próprio parceiro, implementado, por exemplo, usando construções try ... catch
. O processo, que captura os resultados, ainda não tem a oportunidade de reproduzir a memória de outro e salvá-lo, mas pode evitar a morte conjunta.
Isso está se tornando uma oportunidade crucial para criar supervisores. Entraremos em contato com eles em breve.

Antes de passar para os supervisores, vamos dar uma olhada nos poucos ingredientes restantes que nos permitirão preparar com êxito um sistema que usa gotas para nosso próprio benefício. Um deles está relacionado ao funcionamento do agendador de processos. O caso real ao qual gostaria de me referir é o pouso na lua do Apollo 11 [ Apollo 11 - aprox. tradutor ].
A Apollo 11 é uma missão que foi para a lua em 1969. Na imagem, vemos o módulo lunar com Buzz Aldrin e Neil Armstrong a bordo, e acredito que a foto foi tirada por Michael Collins, que permaneceu no módulo de comando.
No caminho para o pouso na lua, o módulo foi controlado pelo Apollo PGNCS (Sistema de orientação, navegação e controle primário) [ Apollo PGNCS - aprox. tradutor ]. O sistema de controle executou várias tarefas com um número cuidadosamente calculado de ciclos [ CPU - aprox. tradutor ] cada. A NASA também descobriu que o processador deve ser usado não mais do que 85% de sua capacidade, com 15% livres em estoque.
Como os astronautas queriam ter um plano de backup confiável, caso precisassem interromper a missão, deixaram o radar da reunião com o módulo de comando e serviço ligado - seria útil. Isso decentemente carregou a energia restante da CPU. Assim que Buzz Aldrin começou a digitar comandos, começaram a aparecer mensagens sobre sobrecarga e, de fato, sobre exceder o poder de computação disponível. Se o sistema tivesse se desviado disso, provavelmente não teria sido capaz de fazer seu trabalho, e tudo teria terminado com dois astronautas mortos.
Primeiro, a sobrecarga ocorreu porque o radar tinha um problema de hardware conhecido, fazendo com que sua frequência fosse incompatível com a frequência do computador de controle, o que levou a um "roubo" de um número muito maior de ciclos do que seria usado de outra forma. As pessoas da NASA não eram idiotas e, em vez de usar novas tecnologias que não foram testadas na vida real por uma missão tão importante, elas reutilizaram componentes comprovados, dos quais eles conheciam erros raros. Mas, mais importante, eles criaram um agendamento prioritário.
Isso significa que, quando esse radar, ou talvez os comandos inseridos, sobrecarregam o processador, suas tarefas são interrompidas para dar ciclos de CPU às coisas vitais que têm maior prioridade e realmente precisam deles. Foi em 1969. Hoje existem muito mais idiomas e estruturas que oferecem apenas despacho cooperativo e nada mais.
Erlang não é uma linguagem que deva ser usada para sistemas vitais; ela leva em conta apenas restrições suaves em tempo real - aprox. tradutor ] e não restrições estritas em tempo real e, portanto, usá-lo para esses cenários não seria uma boa ideia. Mas Erlang fornece um planejamento proativo [ ela é uma programação preventiva, aprox. tradutor ] e priorização de processos. Isso significa que você, como desenvolvedor ou arquiteto de sistema, não precisa tomar cuidado para que, para evitar congelamentos, todo mundo calcule cuidadosamente a carga da CPU necessária para seus componentes (incluindo as bibliotecas usadas). Eles simplesmente não podem obter esse poder. E se você quiser que uma tarefa importante seja executada sempre que precisar, também é possível fornecê-la.
Isso não parece uma demanda séria ou frequente, e as pessoas ainda lançam projetos realmente bem-sucedidos baseados apenas no agendamento cooperativo de processos paralelos, mas certamente são extremamente valiosos porque o protegem dos erros de outras pessoas e também dos seus. Também abre a porta para mecanismos como balanceamento automático de carga, processos de “punir maus” ou “incentivar bons” ou atribuir prioridades mais altas a processos com mais tarefas. Tudo isso torna seus sistemas adaptáveis o suficiente para cargas e eventos imprevistos.

O último componente que gostaria de discutir como parte de garantir uma resiliência decente é a capacidade de trabalhar na rede. Em qualquer sistema desenvolvido visando atividades de longo prazo, a capacidade de executar em mais de um computador rapidamente se torna um requisito obrigatório. Você não quer sentar em algum lugar trancado atrás de portas de titânio com seu carro de ouro, sem poder compensar falhas que afetam principalmente seus usuários.
Então, mais cedo ou mais tarde, você precisará de dois computadores, para que um sobreviva à falha do segundo e possivelmente do terceiro, se você quiser implantar parte do seu sistema durante falhas.
O avião da ilustração - Mustang F-82 Twin [Mustang F-82 Twin - aprox. tradutor ], uma aeronave projetada durante a Segunda Guerra Mundial para escoltar bombardeiros por distâncias que a maioria dos outros caças simplesmente não conseguia percorrer. Ele tinha duas cabines, para que os pilotos pudessem controlar o dispositivo em turnos; no momento certo, era possível dividir responsabilidades para que um piloto pudesse pilotar o avião e o segundo - controlar radares no papel de interceptador. As aeronaves modernas ainda têm capacidades semelhantes; eles têm inúmeros sistemas duplicados e, com frequência, os membros da tripulação dormem durante o voo, para que haja sempre alguém pronto, se necessário, para assumir imediatamente o controle da aeronave.
Quanto às linguagens de programação ou ambientes de desenvolvimento, a maioria deles é projetada sem a possibilidade de trabalho distribuído, embora seja claro que, ao desenvolver uma pilha de servidores, você precisará trabalhar com mais de um servidor. No entanto, se você estiver trabalhando com arquivos, existem ferramentas para isso na biblioteca padrão. O máximo que a maioria dos idiomas pode fornecer é suporte a soquete ou um cliente HTTP.
Erlang presta homenagem à realidade dos sistemas distribuídos e oferece uma implementação para sua criação, documentada e transparente. , , - [ pylyglot systems — . ].

" ". - , . "Let it crash" , , .
— .

[ supervision trees — . ] — , . — , — — , . , — "OTP", , "Erlang/OTP" [ OTP — Open Telecom Platform — . ].
— , , , , , "" . , : , , .
, , , , — .

. " , ". , . .
. " " [ one for one — . *]. . , .
— " " [ one for all — . *]. , . , , . , . , . , , . , , !
, , , . , . : , .
, . — " " [ rest for one — . ]. , , . .
[ , — — . ] . 1 , 150 .

, , " , !"
. , , , . "" [ — . ] "" [ — . ], Jim Gray 1985 ( Jim Gray, !)
-, — , , . . , , . , , , , .
— , , , . , , . , , .
, , .

, — .
, . , , .
, — , , . , — ; . , , . , , , .
, , .
. , , [ Property-Based Testing Basics , Property-based testing — . ] ( ), — - , . , , , .

( ). , , .
, . , , , , . - -.
. , , , , , , .
, . Jim Gray, , , 132 , , . 131 132 , , . , , , , ; , , , 100 000 , — 10 , - .
, , .

?
, . . , . , , . , "" Facebook ( ), , , Facebook .
, , , , . , , .
, . : , , , , .
, ( ), , . , .

, , . , , , .
, , .

() . , : . Tally () , Live Reports ( ) .
, . District (; ) , (Storage). (Cache) ( ) (Worker pool).
[ supervision strategies — . ], , , , . , " ", , , . ( ) " ". , (OCR) , , . , , , , .
OCR , C , . , C, , , .
, , , . 10 , , , .
, , . , . — , .
, , , . OCR C , . OCR . . , , ( ). , , — , .
OCR , . , , — . — . , , , , - , .
, . , — - , - ( ) , . , — , . — let it crash!
. , if/else
, switch
', try/catch
. , , , . [ , — . ], .

, , , , . : , .
, , , . (, SMS).
, , , , , .

OTP. OTP- — , . , , . , , , . , , , .
, OTP- . OTP-, . [: OTP-, , ]
:
- , ;
- , , , ;
- , ;
- , , , , ;
- ( , );
- .
. , . , , . , — , , .

, ? , . , Heroku .
. (vegur) , , , . , , .
- , . , : 500 000 1 000 000 ! , . ? , , , 100 000 , ? - 1:17000 1:7000. , , , .
, . , , , . , . , , .

. .
, - : " , . , , , . , , . , ."
. .
, , , 60 . ( United 734), , , , - . , , , , ABS, .
( ), . , . , , .

, . ( , ) Richard Cook. , YouTube, .
- . , , , .. — ( , , ..) , , - , .
, , , . , , - - .
, , , . , . , . - - , , , .

, . , , : , . . , , , .
, , , . .

, , . , , , .
. , , , - , , , , , . , .

, 'let it crash' — , , , , , — , , , . . fail-fast , , " ", .
, . , , . . , , . Let it crash.

: , , , — . , ( , !) .