Este artigo foi enviado por Alexandre Juca . Quer partilhar conhecimento com os demais seguidores do MenosFios? Siga os passos.
________________________________________________________________________
Tarde ou cedo, chega um momento da vida de um programador em que deve focar-se em conceitos que o permitem criar sistemas cada vez mais complexos e que lidam com muitos dados. Especialmente por vivermos num tempo em que há mais pessoas na Internet e há mais dados a serem gerados. Exemplos de sistemas locais do género são vPOS (Sistema de pagamentos Angolano), Tupuca, e a EMIS e as internacionais que posso mencionar são Netflix, Google, Amazon, Yoco, Stripe, PayPal entre outros. Estes sistemas mencionados acima precisam de três características importantes:
- Robustos e alta disponibilidade
- Escalabilidade
- Sustentabilidade
Hoje vamos abordar sobre a primeira característica, Robustos e alta disponibilidade.
O que significa ter um sistema robusto e com alta disponibilidade?
Um sistema robusto é tolerante à falhas, quer dizer que ela pode funcionar normalmente (apresentando o desempenho esperado e funcionalidade esperado) mesmo em situações não favoráveis. Um sistema robusto é capaz de antecipar e lidar com falhas de hardware, software ou até mesmo humanas e têm um uptime de 95% a 100%.
Como deixar um sistema mais robusto e tolerante a falhas?
Primeiro temos de saber porque surgem certas falhas. Veja algumas das falhas que podem ocorrer durante o ciclo de vida de um sistema:
- Disco duro quebrado
- Memória RAM quebrado
- Servidor fora do ar
- CPU queimado
- Indisponibilidade da base de dados por falha humana, de software ou hardware
- Bugs
O que algumas destas falhas têm em comum? Elas podem afectar a robustez e disponibilidade de um sistema. Por quê? Porque quando há um ponto único de falha num determinado sistema isso pode afetar a disponibilidade do sistema e logo sua robustez.
Como solucionar isso?
Uma maneira de solucionar isso é usar a redundância. Adicionar disco duros em RAID, hot swappable CPUs, múltiplos servidores, múltiplos servidores de base de dados, etc.
Tive o prazer de trabalhar na vPOS como engenheiro de software e ajudar a equipe a criar um sistema com essa característica, pois os meus líderes técnicos perceberam que isso é importante para o negócio. O sistema precisava lidar com pagamentos 24 horas por dia, sem parar! Por isso usamos vários servidores backend, como de base de dados em cluster para não termos um único ponto de falha porque às consequências para o negócio seriam desastrosos.
Fazer isso permite que a gente faça manutenção e atualizações aos sistemas sem interromper os nossos serviços que actualmente são usados pela Tupuca, Soba-Store e muitas outras empresas e que lidam com milhares de transações por dia. Também conseguimos lidar com ataques de negação de serviço e isso tudo porque entendemos o quão importante a característica em questão era para o problema que tínhamos e isso ajudou-nos a escolher as tecnologias certas e uma boa arquitetura para o nosso sistema.
Com maior entendimento desta característica e o problema que estamos a resolver escolhemos uma tecnologia que oferece essa característica, o Elixir. Escolhemos o Elixir e às tecnologias em sua volta porque são baseadas numa tecnologia robusta conhecida como “BEAM” (Björn’s Erlang Abstract Machine ou Máquina Virtual do Erlang). O “BEAM” faz parte do núcleo do OTP (Open Telecoms Platform) e todo código escrito em Elixir é compilada e convertida em bytecode que é executada pela Máquina Virtual do Erlang.
Como essa tecnologia ajuda-nos a criar sistemas robustos?
Todo e qualquer código executado pela máquina virtual do Erlang é executado dentro de um processo, um processo no contexto do Erlang é diferente de um processo do sistema operativo no sentido de que é trivial iniciar milhares até milhões de processos. O processo é uma implementação da runtime da Máquina Virtual do Erlang e não é o mesmo que o thread de um sistema operativo. Podemos dizer que estes processos são como green threads mas muito mais leve. Consegues iniciar um processo em menos tempo que um thread e elas tendem a usar muito menos memória.
Estes processos podem ser iniciadas e “supervisionadas” por outros processos especiais conhecidas como Supervisors. Elas monitoram o comportamento de outros processos e podem reiniciá-los se houver uma falha, podemos até criar uma árvore de supervisors conhecidas como supervision tree.
Processos também ajudam-nos a lidar com “processos run-away”, que são processos ou threads nativos (do sistema operativo) que usam quase todos os recursos partilhados, como tempo de CPU, memória, espaço no disco e largura de banda. Isso porque os processos executados pelo escalonador da Máquina Virtual do Erlang não permitem que um processo seja executado por muito tempo, logo é quase impossível que um único processo no BEAM deixa cair o sistema todo. Com estas abstrações, podemos desenhar com facilidade sistemas tolerantes a falhas e com alta disponibilidade.