Esta é uma questão muito aberta, mas tentarei ilustrar por que Elixir / Erlang pode ser a melhor plataforma para desenvolver sistemas distribuídos (independentemente se você está trabalhando com microsserviços).
Primeiro, vamos começar com alguns antecedentes. A VM Erlang e sua biblioteca padrão foram projetadas antecipadamente para a construção de sistemas distribuídos e isso realmente aparece. Pelo que eu sei, é o único tempo de execução e VM amplamente usados na produção, projetados inicialmente para este caso de uso.
Formulários
Por exemplo, você já sugeriu "aplicativos". Em Erlang / Elixir, o código é empacotado dentro de aplicativos que:
- são iniciados e parados como unidade. Iniciar e parar o seu sistema é uma questão de iniciar todos os aplicativos nele
- fornece uma estrutura de diretório unificada e API de configuração (que não é XML!). Se você já trabalhou e configurou um aplicativo OTP, sabe como trabalhar com qualquer outro
- contém a árvore de supervisão do aplicativo, com todos os processos (por processo, quero dizer "processos VM" que são threads leves de computação) e seu estado
O impacto desse design é enorme. Isso significa que os desenvolvedores Elixir, ao escrever aplicativos, têm uma abordagem mais explícita para:
- como seu código é iniciado e interrompido
- quais são os processos que fazem parte de um aplicativo e, portanto, qual é o estado do aplicativo
- como esses processos irão reagir e ser afetados em caso de falhas ou quando algo der errado
Além disso, o conjunto de ferramentas em torno dessa abstração é ótimo. Se você tem Elixir instalado, abra-se "IEX" e digite: :observer.start()
. Além de mostrar informações e gráficos sobre o seu sistema ativo, você pode matar processos aleatórios, ver o uso de memória, estado e muito mais. Aqui está um exemplo de execução em um aplicativo Phoenix:
A diferença aqui é que Aplicativos e Processos fornecem uma abstração para raciocinar sobre seu código em produção . Muitas linguagens fornecem pacotes, objetos e módulos principalmente para organização de código, sem reflexo no sistema de tempo de execução. Se você tem um atributo de classe ou um objeto singleton: como você pode raciocinar sobre as entidades que podem manipulá-lo? Se você tiver um vazamento de memória ou um gargalo, como poderá encontrar a entidade responsável por isso?
Se você perguntar a qualquer pessoa que esteja executando um sistema distribuído, esse é o tipo de percepção que ela deseja, e com Erlang / Elixir você tem isso como o bloco de construção.
Comunicação
Tudo isso é apenas o começo. Ao construir um sistema distribuído, você precisa escolher um protocolo de comunicação e o serializador de dados. Muitas pessoas escolhem HTTP e JSON que, quando você pensa sobre isso, é uma combinação muito detalhada e cara para realizar o que realmente são chamadas RPC.
Com Erlang / Elixir, você já tem um protocolo de comunicação e um mecanismo de serialização prontos para uso. Se você quiser que duas máquinas se comuniquem entre si, você só precisa dar nomes a elas, garantir que tenham o mesmo segredo e pronto.
Jamie falou sobre isso na Erlang Factory 2015 e como eles puderam aproveitar isso para construir uma plataforma de jogo: https://www.youtube.com/watch?v=_i6n-eWiVn4
Se você deseja usar HTTP e JSON, tudo bem e bibliotecas como Plug e frameworks como Phoenix garantirão que você seja produtivo aqui também.
Microsserviços
Até agora não falei sobre microsserviços. Isso porque, até este ponto, eles realmente não importam. Você já está projetando seu sistema e nós em torno de processos muito pequenos que estão isolados. Chame-os de nanoserviços se quiser!
Além disso, eles também são empacotados em aplicativos, que os agrupam como entidades que podem ser iniciadas e interrompidas como unidade. Se você tem aplicativos A, B e C, e deseja implantá-los como [A, B] + [C] ou [A] + [B] + [C], você terá muito poucos problemas para fazer isso devido ao seu design inerente. Ou, melhor ainda, se você quiser evitar adicionar a complexidade das implantações de microsserviços em seu sistema antecipadamente, pode simplesmente implantá-los juntos no mesmo nó.
E, no final do dia, se você está executando tudo isso usando o protocolo distribuído Erlang, você pode executá-los em nós diferentes e eles serão capazes de alcançar outros contanto que você se refira a eles por em {:node@network, :name}
vez de :name
.
Eu poderia ir mais longe, mas espero ter convencido você neste ponto. :)