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.

Transcript

  1. @nirev Elixir: O que pode dar errado? 2019-05-25 Guilherme de

    Maio
  2. @nirev @nirev

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


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


    Elixir @ xerpa.com.br (2015)
 
 coorganizador SP Elixir Meetup ;)
 
 Muito Java e C antes
  5. @nirev

  6. @nirev

  7. @nirev

  8. @nirev Contexto Coisas que normalmente associamos com a BEAM

  9. @nirev Modelo de Atores

  10. @nirev Processos Isolados

  11. @nirev GC por Processo

  12. @nirev Super escalável, só escreve, funciona!

  13. @nirev Mas.. Essa é uma visão limitada

  14. @nirev Como quebrar sua app

  15. @nirev O Caso da tonelada de átomos 1

  16. @nirev Tons of atoms Poison.decode(body, keys: :atoms!)

  17. @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
  18. @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
  19. @nirev • Nomes de Modulos • Nomes de nós •

    Campos de Struct • “decode as atom” @nirev Tons of atoms
  20. @nirev O Caso do Agent linkado 2

  21. @nirev Linked Agent Process 1 Linked Process start_link

  22. @nirev Linked Agent Process 1 Linked Process start_link exit reason:

    exception
  23. @nirev Linked Agent Process 1 Linked Process start_link exit reason:

    exception
  24. @nirev Linked Agent Process 1 Linked Process start_link exit reason:

    normal
  25. @nirev Linked Agent Linked Process “I'm a survivor”

  26. @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
  27. @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
  28. @nirev Linked Agent ref = Process.monitor(pid) receive do {:DOWN, ^ref,

    :process, ^pid, _reason} -> # receive down message and do something
  29. @nirev

  30. @nirev O Caso da Monitoração de Requests 3

  31. @nirev Request Monitoring request Tracker pega dado do db api

    call atualizar status no db publicar na fila
  32. @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, ..})
  33. @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
  34. @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
  35. @nirev Request Monitoring 40 80 120 160 ??????

  36. @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.
  37. @nirev Request Monitoring 40 80 120 160 agents forever

  38. @nirev O Caso dos Restarts Infinitos 4

  39. @nirev Infinite Restarts Process

  40. @nirev Infinite Restarts Process

  41. @nirev Infinite Restarts Error
 Reporter
 Task Process

  42. @nirev Infinite Restarts Task Supervisor Error
 Reporter
 Task Error
 Reporter


    Task Process
  43. @nirev Infinite Restarts Task
 Supervisor Error
 Reporter
 Task Error
 Reporter


    Task API remota caiu!!!
  44. @nirev Infinite Restarts Task
 Supervisor supervisor(Task.Supervisor, [[name: XXX.TaskSupervisor, 
 restart:

    :transient]])
  45. @nirev Infinite Restarts Task
 Supervisor Error
 Reporter
 Task Error
 Reporter


    Task
  46. @nirev Infinite Restarts Task
 Supervisor Error
 Reporter
 Task Error
 Reporter


    Task API remota caiu!!!
  47. @nirev Infinite Restarts Task
 Supervisor supervisor(Task.Supervisor, [[name: XXX.TaskSupervisor, 
 restart:

    :temporary]])
  48. @nirev O Caso do Message Router 5

  49. @nirev Message Router Dispositivo de rastreamento

  50. @nirev Backend Server TCP Socket A P I Comandos Message

    Router
  51. @nirev Message Router Message Router 1 Genserver x Veículo

  52. @nirev Message Router Out of Memory Message Router

  53. @nirev Message Router Process Control Block Stack Heap Process Memory


    Layout
  54. @nirev Message Router Process Control Block Stack Heap
 
 Process

    Memory
 Layout Shared Heap Refc Binary ProcBin (pointers)
  55. @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
  56. @nirev Message Router Shared Heap Garbage Collection Contagem de Referências


    • todo binary sem referencias a ele será coletado Shared Heap Refc Binary
  57. @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
  58. @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
  59. @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
  60. @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
  61. @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
  62. @nirev O que fazer quando isso acontece

  63. @nirev O que fazer quando isso acontece (antes de acontecer)

  64. @nirev Introspecção!

  65. @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 []
  66. @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 []
  67. @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]
  68. @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]
  69. @nirev E agora?

  70. @nirev Veja o que está acontecendo! Process.list/0 Process.info/1 :sys.get_* MeuModulo.minha_task()

  71. @nirev :observer.start() Veja o que está acontecendo!

  72. @nirev :observer.start() Veja o que está acontecendo!

  73. @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!
  74. @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!
  75. @nirev Métricas!

  76. @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
  77. @nirev

  78. @nirev Visibilidade!

  79. @nirev Log aggregation

  80. @nirev Error Reporting -Sentry -Honeybadger -Bugsnag -Rollbar -…

  81. @nirev Moral da história?

  82. @nirev Tem várias maneiras de quebrar suas aplicações.

  83. @nirev Não vá para produção 
 sem visibilidade.

  84. @nirev Esteja preparado!

  85. Guilherme de Maio
 nirev@taming-chaos.com Obrigado! ❤ Elixir Brasil 2019 Check

    us out! 
 www.telnyx.com @nirev