top of page
  • Foto do escritorkoby aharon

Liberando a resiliência: um guia prático para engenharia do caos em arquiteturas sem servidor

Um guia prático para engenharia do caos em arquiteturas sem servidor
Um guia prático para engenharia do caos em arquiteturas sem servidor

Engenharia do caos é uma metodologia proativa que introduz intencionalmente interrupções e falhas controladas em um sistema para descobrir fraquezas, aumentar a resiliência e garantir um desempenho robusto diante de interrupções imprevistas.


Nesta postagem, exploraremos práticas de engenharia do caos e forneceremos um código de exemplo para executar um experimento de caos em uma arquitetura sem servidor implantada na AWS.

Além disso, aproveitaremos o AWS FIS (Fault Injection Service) para experimentação aprimorada.


Esta é a segunda parte de uma série de posts discutindo engenharia de caos em arquiteturas serverless. Ela aplica os conceitos introduzidos na Parte 1 desta série.

 

Introdução do escritor convidado

Koby Aharon é um Arquiteto de Software Principal na CyberArk . Ele é um engenheiro profissional prático que adora usar tecnologia para resolver problemas complexos.

Você pode seguir Koby em suas contas do LinkedIn e do Medium .

 

Índice

 

Definição de Engenharia do Caos

Provedores de nuvem como a AWS gerenciam arquiteturas sem servidor, mas garantir que seus aplicativos sem servidor sejam resilientes ainda é essencial. Por exemplo, em uma interrupção em uma região, você quer garantir que sua arquitetura seja resiliente e que seus clientes em outras regiões não sejam afetados.

A engenharia do caos pode ajudar você a simular essas interrupções e validar a resiliência de seus aplicativos serverless. Seguindo seus princípios, você pode conduzir experimentos de caos que simulam uma falha de região e verificar se o sistema está funcionando conforme o esperado.

Antes de mergulhar no código, vamos recapitular brevemente nossa arquitetura de exemplo e as etapas de um experimento que abordamos na Parte 1 .

Apresentamos a seguinte arquitetura:

Imagem 1: Exemplo de arquitetura sem servidor
Imagem 1: Exemplo de arquitetura sem servidor

O diagrama de arquitetura apresenta uma arquitetura serverless clássica que roda em cima da AWS. Ela consistia nos seguintes recursos:

  • API hospedada no Amazon API gateway . Nossa API é implantada em duas regiões, us-east-1 e eu-west-1, e expõe dois caminhos: '/api/health' para verificação de integridade e '/api/hello' como nossa API de serviço. Nossa integridade retorna “Região {region} está íntegra”, enquanto nossa API de serviço retorna: “Olá da região {region}” (a região marca o ponto de extremidade que manipulou a solicitação, seja 'us-east-1' ou 'eu-west-1').

  • Há duas funções Lambda em cada região. Nossa API aciona as funções (temos um Lambda dedicado por API). Há mais sobre como usar o Lambda com o AWS API Gateway aqui .

  • Domínio personalizado registrado no Amazon Route 53. Cada API regional obterá um domínio personalizado dedicado informando a região relevante. Por exemplo: “example.{region}.mydomain.com” (a região deve ser 'us' ou 'eu', por exemplo, “ example.us.mydomain.com ”).

  • O roteamento baseado em latência do Route53 aponta para nossos endpoints em ambas as regiões. O endereço de entrada deve corresponder a “ example.mydomain.com .”

  • Health check do Route53 para verificar a saúde de nossas APIs. Cada API regional terá uma health check dedicada que aponta para o endereço de domínio relevante: “ https://exmaple .{region}.mydomain.com/api/health.”


Etapas do experimento do caos

Apresentamos as quatro etapas de um experimento de caos:

  1. Formule uma hipótese (plano)

  2. Introduzir estresse/falhas (fazer)

  3. Observar (verificar)

  4. Melhorar (agir)

E definiu a seguinte hipótese:

Dado: Temos um gateway de API multirregional por trás do roteamento baseado em latência.

Hipótese: Falha em uma região não afeta outras regiões. Além disso, o failover do Route 53 deve detectar prontamente o problema e redirecionar o tráfego para a região saudável.

Este post apresentará como experimentar com AWS usando AWS FIS para testar nossa hipótese. Durante nosso experimento, usaremos uma extensão Lambda para injetar falhas em nossas funções Lambda (mais sobre isso abaixo). Veja a primeira parte para mais informações sobre as diferentes abordagens para injetar falhas.

Depois de apresentar nossa hipótese e explicar como injetaremos falhas na função Lambda, começaremos nosso experimento entendendo primeiro como validar nossa hipótese durante nosso experimento Chaos.

 

Preparando-se para nosso primeiro experimento

Antes de executar nosso experimento, é essencial validar se o aplicativo se comporta como esperado e simular o comportamento do usuário dentro do sistema. Além disso, determinar como o sistema funciona do ponto de vista do cliente é crucial.

Mais especificamente, se a região dos EUA estiver inativa, precisamos ser capazes de verificar se ela está inativa e se nossos clientes da UE não foram afetados.

Usaremos o Amazon CloudWatch para validar o comportamento do aplicativo e criar um painel com uma mistura de métricas integradas e personalizadas. Usando essas métricas, podemos monitorar nosso aplicativo tanto do ponto de vista do operador do sistema quanto do cliente. As métricas e o painel são centrais para a etapa "observar" do nosso experimento. Falaremos sobre essas métricas em detalhes mais adiante neste post.


Definindo o Experimento

Nosso experimento tem duas partes principais. A primeira simula o comportamento do cliente, enquanto a segunda o executa e injeta falhas.

Simulador de comportamento do cliente: simular o comportamento do cliente é crucial, pois queremos primeiro testar nossa hipótese em um ambiente controlado sem afetar os clientes reais. Para simular o comportamento do cliente, usaremos uma versão atualizada deste aplicativo chamada "load-gen", retirada do AWS Chaos Engineering Workshop . Este aplicativo pode ser implantado como uma função Lambda e invocado para simular a carga em uma determinada API. Para obter mais informações sobre o aplicativo e como usá-lo, consulte AWS Chaos Engineering Workshop .

Executando nosso experimento: Usaremos o AWS FIS (Fault Injection Service) para executar nosso experimento. O AWS FIS é um serviço totalmente gerenciado para executar experimentos de injeção de falhas (Chaos) na AWS. Diferentemente de ferramentas externas, o FIS injeta falhas diretamente por meio do plano de controle da AWS, permitindo que ele imite problemas do mundo real específicos dos serviços da AWS.

Além do AWS FIS, usaremos o AWS System Manager , um serviço que gerencia seus recursos e aplicativos da AWS no local ou na nuvem. Escreveremos um documento de automação personalizado no AWS System Manager e o usaremos no FIS. Entraremos em mais detalhes posteriormente neste post.


Conceitos do AWS FIS

Veja aqui uma análise dos principais conceitos do AWS FIS e como aproveitá-los para engenharia de caos em nosso ambiente sem servidor:

  • Modelo de Experimento: Este blueprint define nosso experimento. Ele especifica os recursos (por exemplo, funções Lambda) que queremos atingir, as falhas a serem injetadas (latência, erros) e as condições de parada (duração, limites de erro).

  • Ações: Essas são maneiras específicas de interromper nossos recursos, como limitar o tráfego de rede ou introduzir atrasos. O FIS fornece ações pré-construídas ou nos permite definir ações personalizadas. Veja aqui uma lista de ações suportadas.

  • Alvos: Queremos injetar falhas nesses recursos da AWS, como nossas funções Lambda.

  • Condições de parada: Defina quando o experimento deve parar automaticamente. Você pode basear a condição de parada em um limite de tempo, erros específicos encontrados ou limites de utilização de recursos excedidos.

Agora que entendemos os serviços que usaremos para conduzir nosso experimento, vamos revisar as etapas do experimento e explicar como usaremos o AWS FIS.

 

Etapas do experimento


1 - Formule uma Hipótese

Lembrete rápido: aqui está nossa hipótese:

Dado: Temos um gateway de API multirregional por trás do roteamento baseado em latência.

Hipótese: Falha em uma região não afeta outras regiões. Além disso, o failover do Route 53 deve detectar prontamente o problema e redirecionar o tráfego para a região saudável.


2 - Introduzir Falhas (Caos)

Pode-se escolher injetar diferentes tipos de falhas em uma função Lambda. Este post usará o tipo de falha Latency, que é simples e intuitivo. Este tipo de falha introduz atrasos artificiais na execução do Lambda adicionando latência, o que eventualmente causa falhas devido a timeouts. Mais sobre isso abaixo.

No momento em que este blog foi escrito, o AWS FIS não tinha ações pré-construídas para o serviço Lambda, então precisamos recorrer a outras abordagens. Usaremos uma extensão Lambda para injetar uma falha de latência em nosso Lambda. Uma vez conectado ao nosso Lambda, podemos habilitá-lo definindo nossas variáveis de ambiente Lambda e configurando-o para adicionar atrasos artificiais durante a invocação do Lambda. Você pode ler mais sobre a extensão no arquivo README oficial.

Para conectar a extensão ao nosso Lambda, usaremos a ação aws:ssm:start-automation-execution do FIS, que nos permite invocar um documento de automação do AWS System Manager. Para nossos propósitos, desenvolveremos um documento de automação que irá:

  • Obtenha um Lambda e um ARN de extensão Lambda como parâmetros.

  • Conecte a extensão ao Lambda.

  • Habilite a injeção de falhas (Chaos) definindo as variáveis de ambiente do Lambda.

  • (Opcional) Atualize um alias do Lambda para apontar para nossa nova versão (mais sobre isso abaixo).

Veja aqui mais informações sobre a automação do AWS System Manager e aqui mais informações sobre como escrever documentos de automação personalizados.

Você pode escrever documentos de automação no formato JSON ou YAML. Veja o seguinte snippet YAML para a lista de parâmetros que usaremos em nosso documento:


Como você pode ver no snippet, temos os seguintes parâmetros:

  • FunctionName — O nome da função lambda para adicionar a camada.

  • LayerArn — O ARN da camada a ser adicionada à função lambda.

  • AutomationAssumeRole — O ARN da função que permite que a Automation execute as ações em seu nome.

  • ChaosMode — (Opcional) Se queremos habilitar ou desabilitar o Chaos (o padrão é habilitar).

  • AliasName — (Opcional) O nome do alias lambda que precisa ser atualizado. Um alias Lambda é um ponteiro para uma versão de função, e normalmente o usamos ao conectar uma função Lambda a um API Gateway. Se você não usar um alias Lambda, pode ignorar esse parâmetro e deixá-lo vazio.

O documento pega os parâmetros e executa um script Python. Você pode ver o seguinte snippet contendo a função “handler”, que é a parte principal do nosso script:


Esta função Lambda conecta a extensão e adiciona variáveis de ambiente para habilitar o Chaos (injetar falha de latência).

Nosso script também oferece suporte à desativação do Chaos (interrompendo a injeção de falhas) desanexando a extensão e removendo as variáveis de ambiente adicionadas.

Você pode ver a versão completa do documento do SSM aqui .

 

Definição do Experimento FIS

Após revisar nosso documento de automação, vamos revisitar nosso modelo de experimento FIS, que é um blueprint que define nosso experimento. Você pode ver o seguinte snippet de exemplo do modelo FIS que usaremos (parcial):

No snippet acima, podemos ver que nosso experimento contém as seguintes ações (linhas 4 a 35):

  • “S00_AttachExtensionToLambda” (linhas 5–13) - Habilite o Chaos em nosso Lambda invocando nosso documento de automação. Usaremos a extensão mencionada acima enquanto habilitamos o tipo de resposta de latência configurado com 60 segundos. Habilitar o tipo de resposta de latência causará um dos seguintes:

  1. Tempo limite da função - isso acontecerá se configurarmos nosso Lambda para rodar em menos de 60 segundos.

  2. Tempo limite da API do API Gateway — O API Gateway tem um tempo limite máximo de integração de 30 segundos (limite rígido).

  • “S01_Wait” (linhas 14–22) - Aguarde 10 minutos. Esta ação é essencial, pois precisamos esperar tráfego suficiente para validar nossa hipótese mais tarde.

  • “S02_DetachExtensionFromLambda” (linhas 23–34) - Desabilite o Chaos invocando nosso documento de automação com o parâmetro “ChaosMode” definido como “DISABLED”. Isso reverterá nosso Lambda ao seu estado original e concluirá o experimento.

É importante notar que o snippet acima focou na atualização de um único Lambda. No entanto, no nosso caso, devemos estendê-lo para injetar falhas em ambas as funções do Lambda na região dos EUA: health check e service. Caso contrário, não simularemos uma falha regional no serviço do Lambda.


Para obter mais informações sobre os modelos de experimentos do AWS FIS, clique aqui .

 

3 - Observar

Conforme mencionado acima, para verificar nossa hipótese durante o experimento, criaremos um painel do CloudWatch mostrando uma mistura de métricas internas e personalizadas contendo uma dimensão. Você pode ler mais sobre métricas e dimensões personalizadas aqui . O painel deve nos fornecer visibilidade de ambas as regiões e apresentar o código de resposta que nosso cliente recebe. Ele conterá as seguintes métricas:

  • Route53 HealthCheckStatus — Usando essa métrica interna da AWS, podemos verificar se nosso endpoint é considerado não íntegro do ponto de vista de um operador de sistema. Monitoraremos as métricas para nossa API em ambas as regiões.

  • “region_{region}” - uma métrica personalizada para marcar o número de solicitações que uma região específica manipula. Podemos calcular esse valor analisando a carga útil da resposta, pois nossa API retorna “Olá da região {região}” no caso de um código de resposta HTTP 200.

  • Código de retorno de invocação de API — várias métricas personalizadas para marcar o código de resposta HTTP retornado da chamada de nossa API. Teremos as seguintes métricas:

  1. status_2xx - número de respostas 2xx.

  2. status_4xx - número de respostas 4xx.

  3. status_5xx - número de respostas 5xx.

Nosso simulador de comportamento personalizado mencionado acima (o aplicativo “load-gen”) publicará nossas métricas personalizadas e conterá a API invocada como uma dimensão. Usando nossas métricas personalizadas, podemos entender se um cliente experimenta uma falha ao chamar nossa API e qual ponto de extremidade da API lidou com a solicitação (região 'us-east-1' ou 'eu-west-1').

Por exemplo, caso nossa URL de API seja “ https://example.mydomain.com” e recebamos um código de resposta HTTP 200 ao chamar a API ao atingir a região 'us-east-1', teremos as seguintes métricas:

4 - Melhorar

Assim que o experimento terminar de ser executado, visualizaremos nosso painel e validaremos nossa hipótese. Devemos corrigir qualquer problema que descobrirmos e executar novamente nosso experimento.

 

Liberte o caos em nossa arquitetura

Agora que revisamos todas as etapas necessárias para conduzir nosso experimento, veremos os passos exatos que tomaremos para desencadear o Caos:

1. Implante nossa arquitetura de exemplo apresentada acima.

2. Comece a executar nosso simulador de cliente (o aplicativo load-gen descrito acima). Podemos executá-lo como uma função Lambda nas regiões da UE e dos EUA, garantindo que ambas as instâncias chamem a URL baseada em latência: “ https://example.mydomain.com/api/hello.”

3. Abra nosso painel do CloudWatch e verifique se tudo está funcionando corretamente. Esperamos que nossos dois endpoints do Route53 estejam saudáveis e que os clientes em ambas as regiões recebam um código de resposta HTTP 200.

4. Inicie nosso experimento FIS.

5. Após terminar, olhe para o nosso painel e valide nossa hipótese. Se não virmos o comportamento esperado no painel, devemos verificar o porquê, corrigir o problema e executar novamente o experimento retornando à etapa 2.

Depois de revisar as etapas que devemos seguir, vamos dar uma olhada no seguinte painel que monitorou um experimento que conduzimos:


Painel de Experimentos — Erro
Painel de Experimentos — Erro

Vamos revisar os widgets no painel da esquerda para a direita:

  1. Saúde “us-east-1” - Exibe a saúde do nosso endpoint da região dos EUA (1 — saudável, 0 — não saudável). Este widget usa o Route53 HealthCheckStatus .

  2. “us-east-1” #requests—Exibe o número de solicitações que chegaram à região dos EUA. Este widget usa nosso valor de região em nossa métrica personalizada apresentada acima.

  3. “eu-west-1” #requests — O mesmo que o widget 2 para a região da UE.

Este painel mostra um problema oculto que temos. Pare por um segundo e pense: Qual pode ser o problema no nosso caso?

Temos cerca de 44 solicitações em nossas regiões dos EUA e cerca de 29 em nossas regiões da UE. Assim que iniciamos nosso experimento (marcado na seta vermelha), vemos um declínio nas solicitações que chegam à região dos EUA, enquanto a UE permanece constante. Não vemos um aumento nas solicitações que chegam à região da UE, pois esperamos que o failover da Rota 53 entre em ação e roteie o tráfego de nossa região não saudável.

A pista para o problema é que nosso endpoint dos EUA é considerado saudável durante todo o nosso experimento (widget 1); no entanto, esperamos que ele não seja saudável. Como ambos os endpoints são considerados saudáveis, o Route53 continua apontando os clientes dos EUA para o endpoint dos EUA, fazendo com que falhem em vez de movê-los para a região da UE.

Qual é o problema? Configuramos acidentalmente nossa verificação de saúde dos EUA para apontar para “ example.eu.mydomain.com ” em vez de “ example.us.mydomain.com .”


É ótimo! Encontramos um problema, e o experimento foi benéfico!

Nossos clientes nos EUA teriam sofrido uma interrupção durante uma interrupção regional real, em vez de serem transferidos para a região europeia.

Vamos consertar isso e refazer o experimento.

 

Validando a correção

Após corrigir o problema, vamos dar uma olhada no seguinte painel:


Painel de Experimentos - Sucesso
Painel de Experimentos - Sucesso

Neste painel, adicionamos outro widget (o último na primeira linha), apresentando os códigos de status retornados pela invocação de nossas APIs. Ele usa nossa métrica personalizada de invocação de API mencionada acima.

Vemos que tudo está funcionando conforme o esperado: assim que iniciamos nosso experimento (seta vermelha), vemos uma diminuição nas solicitações us-east-1 com um aumento correspondente no número de códigos de status HTTP 5xx (o último widget na primeira linha). Após alguns minutos, o failover do Route53 entra em ação, marcando nosso endpoint dos EUA como não íntegro (seta verde no primeiro widget na primeira linha) e roteando todo o tráfego para a região da UE. Podemos validá-lo vendo um aumento nas solicitações que chegam à região da UE (o último widget na segunda linha) e uma diminuição correspondente nos códigos de resposta HTTP 5xx (componente de códigos de status na primeira linha).

 

Resumo

É isso por enquanto. Nesta publicação, pegamos a arquitetura de exemplo e os conceitos apresentados na primeira parte e os colocamos em prática. Executamos um experimento usando o AWS FIS e um documento SSM personalizado, encontramos uma configuração incorreta e a corrigimos. Agora estamos prontos para um tempo de inatividade regional.

Espero que você ache este post (e o anterior) útil e prático e o incentive a testar suas arquiteturas serverless. Você pode se surpreender com o que verá :)


Agradecimentos especiais

Gostaria de agradecer a Ran Isenberg e Maxim Drobachevsky por reservarem um tempo para revisar esta postagem e fornecer seus valiosos comentários.

Comments


bottom of page