Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elixir: o que pode dar errado?

Elixir: o que pode dar errado?

Apresentação feita na https://2019.elixirbrasil.com :)

Normalmente fala-se muito de como uma linguagem nova é incrível e todas as suas possibilidades! Todos queremos mostrar casos de sucesso e que mais pessoas usem a linguagem que amamos. Porém, coisas dão errado! Nesta palestra vou mostrar alguns casos que podem quebrar sua aplicação Elixir em produção e como evitá-los.

More Decks by Guilherme de Maio, nirev

Other Decks in Programming

Transcript

  1. @nirev Baseado em São Paulo
 
 Elixir @ xerpa.com.br (2015)


    
 coorganizador SP Elixir Meetup ;)
 
 Muito Java e C antes
  2. @nirev Elixir Engineer @ Telnyx
 Baseado em São Paulo
 


    Elixir @ xerpa.com.br (2015)
 
 coorganizador SP Elixir Meetup ;)
 
 Muito Java e C antes
  3. @nirev defmodule X do def explode do Enum.each(1 ..2_000_000, fn

    i -> IO.puts(" #{i}") 20 |> :crypto.strong_rand_bytes() |> Base.encode64() |> String.to_atom() end) end end Tons of atoms
  4. @nirev 82534 ... 82535 ... 82536 ... 82537 ... 82538

    ... 82539 ... 82540 ... no more index entries in atom_tab (max=100000) Crash dump is being written to: erl_crash.dump ...done Tons of atoms
  5. @nirev • Nomes de Modulos • Nomes de nós •

    Campos de Struct • “decode as atom” @nirev Tons of atoms
  6. @nirev Linked Agent defmodule X do def spawn do spawn(fn

    -> {:ok, _pid} = Agent.start_link(fn -> 42 end) Process.sleep(1_000) exit(:normal) end) end end
  7. @nirev Linked Agent iex(1)> Process.list() |> Enum.count() 50 iex(2)> for

    _ <- 1 ..10, do: X.spawn [#PID<0.94.0>, #PID<0.95.0>, #PID<0.96.0>, #PID<0.97.0>, #PID<0.98.0>, #PID<0.99.0>, #PID<0.100.0>, #PID<0.101.0>, #PID<0.102.0>, #PID<0.103.0>] iex(3)> Process.list() |> Enum.count() 70 iex(4)> Process.sleep(2_000) :ok iex(5)> Process.list() |> Enum.count() 60
  8. @nirev Linked Agent ref = Process.monitor(pid) receive do {:DOWN, ^ref,

    :process, ^pid, _reason} -> # receive down message and do something
  9. @nirev Request Monitoring request Tracker pega dado do db api

    call atualizar status no db publicar na fila
  10. @nirev Request Monitoring request Tracker pega dado do db api

    call atualizar status no db publicar na fila Tracker.add_breadcrumb(:key, metadata) Tracker.add_breadcrumb(:update_db, %{user: x, role: y, ..})
  11. @nirev Request Monitoring request Tracker CRASH breadcrumbs = Tracker.get_breadcrumbs(tracker) send_report(exception,

    breadcrumbs)
 pega dado do db api call atualizar status no db publicar na fila
  12. @nirev Request Monitoring Pra cada request: -Iniciar um agent -monitorar

    o agent e o processo -matar o agent quando o processo termina normalmente 
 OU 
 pegar os breadcrumbs e depois matar em caso de exception
  13. @nirev Request Monitoring Cowboy implements the keep-alive mechanism by reusing

    the same process for all requests. This allows Cowboy to save memory. This works well because most code will not have any side effect impacting subsequent requests. But it also means you need to clean up if you do have code with side effects. The terminate/3 function can be used for this purpose.
  14. @nirev Message Router Process Control Block Stack Heap
 
 Process

    Memory
 Layout Shared Heap Refc Binary ProcBin (pointers)
  15. @nirev Message Router Process Control Block Stack Heap Private Heap

    Garbage Collection Generational
 • young generation: dados recentemente alocados • old generation: dados que sobrevivem uma
 passada de GC
 Fullsweep vs Generational:
 • min_heap_size • fullsweep_after
  16. @nirev Message Router Shared Heap Garbage Collection Contagem de Referências


    • todo binary sem referencias a ele será coletado Shared Heap Refc Binary
  17. @nirev Message Router O problema do Message Router Recebe mensagens

    > 64bytes (Refc bins) Então, uma referencia ao Large Binary fica no heap Message Router
  18. @nirev Message Router O problema do Message Router Recebe mensagens

    > 64bytes (Refc bins) Então, uma referencia ao Large Binary fica no heap Mas, como o router não usa muita memória O heap não cresce mais que o min_heap_size Message Router
  19. @nirev Message Router O problema do Message Router Recebe mensagens

    > 64bytes (Refc bins) Então, uma referencia ao Large Binary fica no heap Mas, como o router não usa muita memória O heap não cresce mais que o min_heap_size Logo, referencias vivem pra sempre, e os "large binaries" continuam no Shared Heap. Message Router
  20. @nirev Message Router O problema do Message Router Recebe mensagens

    > 64bytes (Refc bins) Então, uma referencia ao Large Binary fica no heap Mas, como o router não usa muita memória O heap não cresce mais que o min_heap_size Logo, referencias vivem pra sempre, e os "large binaries" continuam no Shared Heap. Message Router Out of Memory
  21. @nirev Message Router A SOLUÇÃO pro Message Router 1) fullsweep_after

    process flag
 configura a frequencia do fullsweep GC,
 e isso vai coletar os ProcBins
 2) Hibernar o processo
 quando hiberna, o fullsweep GC roda
 3) Mover o trabalho para processos de vida curta, 
 se possível Message Router
  22. @nirev Conectar a um nó $ iex Erlang/OTP 21 [erts-10.2]

    [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> Node.list []
  23. @nirev Conectar a um nó $ iex --sname node1@localhost --cookie

    delicia Erlang/OTP 21 [erts-10.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help) iex(node1@localhost)1> Node.list []
  24. @nirev Conectar a um nó $ iex --sname node2 --cookie

    delicia --remsh node1@localhost Erlang/OTP 21 [erts-10.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help) iex(node1@localhost)1> Node.list [:node2@C02T24Z2HF1R]
  25. @nirev Conectar a um nó $ iex --sname node2 --cookie

    delicia --remsh node1@localhost Erlang/OTP 21 [erts-10.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help) iex(node1@localhost)1> Node.list [:node2@C02T24Z2HF1R]
  26. @nirev https: //ferd.github.io/recon/
 
 Recon is a library to be

    dropped into any other Erlang project, to be used to assist DevOps people diagnose problems in production nodes. Veja o que está acontecendo!
  27. @nirev https: //ferd.github.io/recon/
 
 :recon.bin_leak(3) [ {#PID<0.80.0>, -606, [current_function: {Process,

    :sleep, 1}, initial_call: {:erlang, :apply, 2}]}, {#PID<0.124.0>, -176, [ :ssl_manager, {:current_function, {:gen_server, :loop, 7}}, {:initial_call, {:proc_lib, :init_p, 5}} ]}, {#PID<0.1905.0>, -165, [current_function: {:ranch_conns_sup, :loop, 4}, initial_call: {:proc_lib, :init_p, 5} ]} ] Veja o que está acontecendo!
  28. @nirev VM metrics vmstats: manda metricas pro statsd
 https: //github.com/ferd/vmstats

    prometheus: manda métricas pro… prometheus https: //github.com/deadtrickster/prometheus.ex