DEV Community

Elxpro
Elxpro

Posted on • Edited on

8 6

Essa e a maior vantagem de Utilizar Elixir

Saudacao

Seja muito bem vindo, seja muito bem vinda ao FullstackElxpro
Do you want to learn Elixir in three months? https://elxpro.com/sell

Aqui nós discutimos as estratégias e dicas de sua jornada de aprendizado em Elixir. Isso é do zero até a sua primeira vaga como desenvolvedor elixir

Eu sou o Gustavo e o tema de hoje é: Sistemas Distribuidos em Elixir

ps: Voce pode acompanhar o artigo com o video

O que é?

Um sistema distribuído é uma coleção de programas de computador que utilizam recursos computacionais em vários pontos centrais de computação diferentes para atingir um objetivo comum e compartilhado. Os sistemas distribuídos visam remover gargalos ou pontos centrais de falha de um sistema.

nesse caso na linguagem que escolhemos (Elixir) vamos utilizar recursos do NODE

https://hexdocs.pm/elixir/1.12/Node.html

Por quê Entender sobre Distribuicao de Sistemas é importante?

Qual que é o princípio de programar em Elixir? E quais são as vantagens?

Todo mundo que escolhe trabalhar com Elixir e sempre o mesmo assunto:

  • Linguagem Funcional
  • Concorrencia
  • Paralelismo

O importante e o que eu vejo que pode ser uma tendencia no futuro em desenvolvedores Elixir avancados e a utilizacao principalmente de concorrencia e paralelismo em sistemas distribuidos para diminuir o custo em uma empresa.

E como Elixir nos ajuda com distribuição?

Uma lista de frameworks abaixo, mas antes de utilizar esses frameworks, você precisa de entender um conceito muito importante.

MNESIA - https://elixirschool.com/pt/lessons/storage/mnesia
PUBSUB - https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html
LibCluster - https://github.com/bitwalker/libcluster

E a leitura deste artigo: https://dashbit.co/blog/you-may-not-need-redis-with-elixir

Eu poderia falar sobre o MNESIA, Pubsub, Libcluster, Só que antes de entender e antes de começar a distribuir sistemas com Elixir você precisa entender o que está por trás de todos esses frameworks.

Ainda não respondi o porquê e o porquê você entendeu desse tribuição de sistemas É principalmente baixo custo e utilizar performance de sistemas de computadores e de hardware uma linguagem fantástica que no nosso caso e Elixir

Como você chegou nessa conclusão?

Cheguei nessa conclusão resolvendo uma Feature onde eu tinha minhas aplicações rodando em três computadores (nos de Kubernetes) diferentes eu precisava ler um arquivo e mandar esse serviço mandar esse arquivo para o serviço externo, e a esse serviço externo salvar informações no banco de dados quando tava rodando esse serviço produção ou staging, algumas vezes esses arquivos não eram lidos, então procuramos entender o que que tava acontecendo.

O nosso problema é que tinhamos 3 nós rodando e o arquivo e algumas vezes era enviado para o batch e na hora do processamento em background, e ao tentar ler o arquivo ele não encontrava.

A solução mais simples para esse caso seria salvar esses dados um Storage (S3). porém quando a gente fala de linguagem funcional e uma linguagem poderosa que facilita a concorrência, paralelismo e Distribuição, 3 minutos para ler arquivos é muito tempo e daí que veio a ideia da próxima versão utilizar sistemas distribuídos e alguns recursos só que esses recursos que exige muito conhecimento de como Elixir funciona por debaixo dos panos por isso cheguei nessa conclusão e quero compartilhar minha experiência com você e como você pode tomar decisões sábias após esse artigo.

Por onde começar?

Primeiros passos com Distribuicao em Elixir

Este artigo sao exemplos de como utilizar Nodes e RPC. O nosso primeiro passo e saber como criar nos e RPC (remote procedure call).

Vamos comecar pelo IEX

iex --sname gus #desta maneira voce criar um shortname
Enter fullscreen mode Exit fullscreen mode
iex --name gus@ip #desta maneira voce criar um name 
Enter fullscreen mode Exit fullscreen mode

a maior diferenca e o acesso entre internet e local.

Image description

Vamos aprender um pouco dos comandos acima:

Node.ping :app_name 

Enter fullscreen mode Exit fullscreen mode

Voce vai fazer um ping verificando se e possivel se conectar com o APP

Node.connect :app_name

Enter fullscreen mode Exit fullscreen mode

Voce vai se conectar a um Node.

Node.list
Enter fullscreen mode Exit fullscreen mode

voce vai ver a lista de conecoes que voce possui. O que e interessante e que neste caso, quando voce vai conectando os nodes eles criam comunicacao entre todos eles. conforme voce ve no Ultimo Node.list

Chamando funcoes.

Antes de comecar a falar de processos, algo que o Elixir nos entrega de graca e um :rpc. coisa que e muito complexo em outras aplicacoes.

Vamos ver o cenario abaixo:

Image description

No exemplo acima temos o RPC que segue o seguinte padrao para ser chamado:

:rpc.call app_name, MODULE, :function, [parametros] 
Enter fullscreen mode Exit fullscreen mode

E interessante observar quando nao existe o modulo e quando existe, o retorno sempre e para o node que esta chamando.

Utilizando processos em Chamadas.

voce pode utilizar o projeto: https://github.com/elxpro-br/distributed_stock

mas voce pode tambem criar o modulo abaixo:

defmodule DistributedStock do
  def handle_sock(stock) do
    receive do
      {:add, product} ->
        stock_updated = [product] ++ stock
        handle_sock(stock_updated)
      :status ->
        IO.inspect stock
        handle_sock(stock)
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

Image description

vamos comecar pelo start da aplicacao:

❯ iex --sname elxpro-server -S mix 
Enter fullscreen mode Exit fullscreen mode

neste exemplo iniciamos uma aplicacao normal em elixir porem com um short-name

um processo foi criado e registrado com um nome.

> pid = spawn DistributedStock, :handle_sock, [[]]
> Process.register pid, :my_stock
Enter fullscreen mode Exit fullscreen mode

ps: O artigo abaixo vai ajudar a entender mais sobre spawn, send e receive

https://www.youtube.com/watch?v=em4QECkQx4s&t=801s

E agora comecamos a enviar dados para atualizar o nosso estoque, porem no mesmo modulo que comecamos a aplicacao.

> send :my_stock, :status
> send :my_stock, {:add, {"pumpkin", 5}} 
> send :my_stock, :status  
> send :my_stock, {:add, {"pumpkin", 5}} 
Enter fullscreen mode Exit fullscreen mode

O que e interessante notar e o que e feito apos a conexao com a aplicacao servidora. E como vamos atualizar o estoque. Voce vai reparar que para chamar um processo em outro app voce so precisa incluir no seu send a seguinte estrutura.

 send {:pid_name, :app_name}, mensagem
Enter fullscreen mode Exit fullscreen mode

E ao chamar N vezes o servico sempre vai para o app servidor conforme a imagem acima.

Lidando com Respostas entre processos

defmodule DistributedStock do
  def handle_sock(stock) do
    receive do
      {:add, from, product} ->
        stock_updated = [product] ++ stock
        send(from, stock_updated)
        handle_sock(stock_updated)

      {:status, from} ->
        send(from, stock)
        handle_sock(stock)
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Image description

No exemplo acima, atualizamos o nosso codigo para sempre retornar a resposta para algum processo seja ele o que for. Usamos funcoes como Process.info(pid, :messages) para saber se tem mensagens e flush para ler as mensagens.

Sobre comunicacao de Nodes e Processos

defmodule DistributedStock do
  def handle_sock(stock) do
    receive do
      {:add, from, product} ->
        stock_updated = [product] ++ stock
        log(from, :add)
        send(from, stock_updated)
        handle_sock(stock_updated)

      {:status, from} ->
        log(from, :status)
        send(from, {:show, stock})
        handle_sock(stock)
    end
  end

  defp log(pid, :add) do
    IO.inspect("#{:erlang.pid_to_list(pid)} added a new item on stock")
  end

  defp log(pid, :status) do
    IO.inspect("#{:erlang.pid_to_list(pid)} checked the stock")
  end
end
Enter fullscreen mode Exit fullscreen mode

Image description

Na imagem acima, so aplicamos o que aprendemos durante todo este artigo. O que mudou foi a comunicacao entre os Nodes e processos agora sempre quando um pid chama um servidor voce pode observar que tem um numero como: <19077.122.0> que traduzindo seria: .

Vamos particar um pouco sobre distribuicao.

Imagine que voce tem uma central para estocar os produtos de diversas lojas, e toda a vez que um cliente solicita um produto na loja, as lojas verifica se a central possui o produto, e retorna a mensagem para o cliente. Segue o exemplo abaixo.

defmodule DistributedStock do
  def handle_sock(stock) do
    receive do
      {:add, from, product} ->
        stock_updated = [product] ++ stock
        log(from, :add)
        send(from, stock_updated)
        handle_sock(stock_updated)

      {:status, from} ->
        log(from, :status)
        send(from, stock)
        handle_sock(stock)
    end
  end

  defp log(pid, :add) do
    IO.inspect("#{:erlang.pid_to_list(pid)} added a new item on stock")
  end

  defp log(pid, :status) do
    IO.inspect("#{:erlang.pid_to_list(pid)} checked the stock")
  end
end

Enter fullscreen mode Exit fullscreen mode
defmodule DistributedProviders do
  def get() do
    receive do
      {:ask, from, product} ->
        IO.inspect("#{:erlang.pid_to_list(from)} wants to know if get a product")
        send({:server, :"server@Gustavos-MacBook-Pro"}, {:status, self()})
        return_itens(from, product)
    end

    get()
  end

  def return_itens(from, product) do
    receive do
      products ->
        case Enum.find(products, &(&1.name == product)) do
          nil -> send(from, {:print, "There is no Product #{product}"})
          product -> send(from, {:print, product})
        end
    end
  end

  def show_msg do
    receive do
      {:print, msg} -> msg
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Image description

No exemplo acima, se voce testou o codigo. Voce teve o seguinte resultado:

  • O servidor guarda os produtos (estado do processo)
  • As lojas, alteram o estado (adicionando ou buscando produtos)
  • E clientes consultam os produtos.

Espero ter ajudado, o aprendizado ainda continua e teremos segunda parte deste artigo.

Referencias

https://elixir-lang.org/getting-started/mix-otp/distributed-tasks.html

https://hexdocs.pm/elixir/1.12/Node.html

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more