Na sua casa você pode usar o que você quiser, aqui hoje vamos usar Istio. Sem tempo pra chorar irmão...
O objetivo desse post é apresentar mecanismos de resiliência que podemos agregar em nosso Workflow para sobreviver em cenários de caos e desastres utilizando Istio e EKS. A ideia é estabelecer uma linha de pensamento progressiva apresentando cenários de desastre de aplicações, dependencias e infraestrutura e como corrigílos utilizando as ferramentas apresentadas.
Para este post foi criado um laboratório simulando um workflow sincrono onde temos 4 microserviços que se comunicam entre si, simulando um sistema distribuido de pedidos, onde todos são estimulados por requisições HTTP.
Premissas Iniciais
- O ambiente roda em um EKS utilizando a versão 1.20 do Kubernetes em 3 zonas de disponibilidade
- Vamos Trabalhar com a premissa de um SLO de 99,99
- O ambiente já possui Istio default com Gateways e VirtualServices Vanilla configurados pra todos os serviços
- O objetivo é aumentar a resiliência diretamente no Istio, por isso nenhuma aplicação tem fluxo de circuit breaker ou retry pragmaticamente implementados.
- Vamos utilizar o Kiali, Grafana para visualizar as métricas
- Vamos utilizar o K6 para injetar carga no workload
- Vamos utilizar o chaos-mesh para injetar falhas de plataforma do Kubernetes
- Vamos utilizar o gin-chaos-monkey para injetar falhas a nível de aplicação
- O objetivo não é avaliar arquitetura de solução, e sim focar nas ferramentas apresentadas como opções
Fluxo sincrono do teste
Parte 1: Resiliência em falhas de aplicação
Cenários 1.1 - Arquitetura inicial
Vamos rodar o teste de carga do k6 no ambiente para ver como vamos nos sair sem nenhum tipo de mecanismo de resiliência:
k6 run --vus 20 --duration 60s k6/loadtest.js
Podemos ver que o chaos-monkey da aplicação cumpriu seu papel, injetando falhas aleatórias em todas as dependencias da malha de serviços, ofendendo drasticamente nosso SLO de disponibilidade pra 88.10 %, estourando nosso Error Budget para esse periodo fake.
Podemos ver também que todas as aplicações da malha, em algum momento apresentaram falhas aleatórias no runtime conforme o esperado, falhando drasticamente em cascata.
Sumário do teste 1.1:
- Tempo do teste: 60s
- Total de requisições: 13905
- Requests por segundo: 228.35/s
- Taxa de erros a partir do client: 11.91%
- Taxa real de sucesso do serviço principal orders-api: 88.10%
- Taxa de sucesso dos consumidores do orders-api: 88.10%
- SLO Cumprido: Não
Cenário 1.2 - Retry para Falhas HTTP
O objetivo do cenário é implementar a lógica de retry para falhas HTTP nos virtualservices das aplicações. Vamos adicionar as opções de retries no virtual services, com as opções 5xx,gateway-error,connect-failure. Podendo ocorrer até 3 tentativas de retry com um timeout de 500ms.
apiVersion: networking.istio.io/v1alpha3 | |
kind: VirtualService | |
metadata: | |
name: orders-api-internal | |
namespace: orders | |
spec: | |
hosts: | |
- "orders-api.orders.svc.cluster.local" | |
http: | |
- route: | |
- destination: | |
host: orders-api | |
port: | |
number: 8080 | |
retries: | |
attempts: 3 | |
perTryTimeout: 500ms | |
retryOn: 5xx,gateway-error,connect-failure |
As opções de retentativas são, de acordo com a documentação
- 5xx: Ocorrerá uma nova tentativa se o servidor upstream responder com qualquer código de resposta 5xx
- gateway-error: Uma politica parecida com o 5xx, porém voltadas a falhas especificas de gateway como 502, 503, or 504 no geral. Nesse caso, é redundante, porém fica de exemplo.
- connect-failure: Será realizada mais uma tentativa em caso de falha de conexão por parte do upstream ou em casos de timeout.
Sumário do teste 1.2:
- Tempo do teste: 60s
- Total de requisições: 17873
- Requests por segundo: 293.17/s
- Taxa de erros a partir do client: 0.07%
- Taxa real de sucesso do serviço principal orders-api: 93.08 %
- Taxa de sucesso dos consumidores do orders-api: 99.25%
- SLO Cumprido: Não
Cenário 1.3 - Ajustando a quantidade de retries para suprir o cenário
apiVersion: networking.istio.io/v1alpha3 | |
kind: VirtualService | |
metadata: | |
name: orders-api-internal | |
namespace: orders | |
spec: | |
hosts: | |
- "orders-api.orders.svc.cluster.local" | |
http: | |
- route: | |
- destination: | |
host: orders-api | |
port: | |
number: 8080 | |
retries: | |
attempts: 5 | |
perTryTimeout: 500ms | |
retryOn: 5xx,gateway-error,connect-failure |
Neste cenário conseguimos suprir os 93% de erros que vieram dos upstreams da nossa malha de serviço por meio de falhas intermitente nas aplicações garantindo 100% de disponibilidade para o cliente. Neste cenário de componentes intermitentes falhando aleatoriamente por diversas causas, estaríamos com um grande saving de erros poupados para o cliente final.
Sumário do teste 1.3:
- Tempo do teste: 60s
- Total de requisições: 18646
- Requests por segundo: 308.79/s
- Taxa de erros a partir do client: 0.00%
- Taxa real de sucesso do serviço principal orders-api: 93.09 %
- Taxa de sucesso dos consumidores do orders-api: 100.00%
- SLO Cumprido: Sim
Parte 2: Resiliência em falhas de infraestrutura
Cenário 2.1 - Injetando falhas de healthcheck nos componentes do workload
apiVersion: chaos-mesh.org/v1alpha1 | |
kind: PodChaos | |
metadata: | |
name: orders-pod-failure | |
namespace: orders | |
spec: | |
action: pod-failure | |
mode: fixed-percent | |
value: "90" | |
duration: "30s" | |
selector: | |
labelSelectors: | |
"app": "orders-api" |
Sumário do Teste 2.1:
- Tempo do teste: 60s
- Total de requisições: 14340
- Requests por segundo: 233.75/s
- Taxa de erros a partir do client: 1.22%
- Taxa real de sucesso do serviço principal orders-api: 93.97 %
- Taxa de sucesso dos consumidores do orders-api: 98.69%
- SLO Cumprido: Não
Cenário 2.2 - Adicionando retry por conexões perdidas / abortadas
--- | |
apiVersion: networking.istio.io/v1alpha3 | |
kind: VirtualService | |
metadata: | |
name: orders-api-internal | |
namespace: orders | |
spec: | |
hosts: | |
- "orders-api.orders.svc.cluster.local" | |
http: | |
- route: | |
- destination: | |
host: orders-api | |
port: | |
number: 8080 | |
retries: | |
attempts: 10 | |
perTryTimeout: 500ms | |
retryOn: 5xx,gateway-error,connect-failure,refused-stream,reset,resource-exhausted,unavailable,cancelled |
As opções de retentativas são, de acordo com a documentação para HTTP:
- reset: Será feita uma tentativa de retry em caso de disconnect/reset/read timeout vindo do upstream
- resource-exhausted: retentativa gRPC em caso de headers contendo o termo "resource-exhausted"
- unavailable: retentativa em gRPC em caso de headers contendo o termo "unavailable"
- cancelled: retentativa em gRPC em caso de headers contendo o termo "cancelled"
Sumário do teste 2.2:
- Tempo do teste: 60s
- Total de requisições: 15633
- Requests por segundo: 258.4/s
- Taxa de erros a partir do client: 0.03%
- Taxa real de sucesso do serviço principal orders-api: 92.81 %
- Taxa de sucesso dos consumidores do orders-api: 99.99 %
- SLO Cumprido: Não
Cenário 2.2 - Adicionando circuit breakers nos upstreams
--- | |
apiVersion: networking.istio.io/v1alpha3 | |
kind: DestinationRule | |
metadata: | |
name: orders | |
namespace: orders | |
spec: | |
host: orders-api.orders.svc.cluster.local | |
trafficPolicy: | |
connectionPool: | |
tcp: | |
maxConnections: 500 | |
http: | |
http1MaxPendingRequests: 30 | |
maxRequestsPerConnection: 100 | |
outlierDetection: | |
consecutive5xxErrors: 2 | |
interval: 300ms | |
baseEjectionTime: 60s | |
maxEjectionPercent: 100 |
Sumário do teste 2.3:
- Tempo do teste: 60s
- Total de requisições: 20557
- Requests por segundo: 342/s
- Taxa de erros a partir do client: 0.00%
- Taxa real de sucesso do serviço principal orders-api: 100 %
- Taxa de sucesso dos consumidores do orders-api: 100 %
- SLO Cumprido: SIM
Cenário 2.3 - Morte instantânea de 90% dos pods
Sumário do teste 2.3:
- Tempo do teste: 60s
- Total de requisições: 24948
- Requests por segundo: 415,56/s
- Taxa de erros a partir do client: 0.00%
- Taxa real de sucesso do serviço principal orders-api: 100 %
- Taxa de sucesso dos consumidores do orders-api: 100 %
- SLO Cumprido: SIM
Cenário 2.4 - Morte de uma zona de disponibilidade da AWS
// ... | |
# Multi-AZ | |
affinity: | |
podAntiAffinity: | |
preferredDuringSchedulingIgnoredDuringExecution: | |
- podAffinityTerm: | |
labelSelector: | |
matchExpressions: | |
- key: app | |
operator: In | |
values: | |
- orders-api | |
topologyKey: failure-domain.beta.kubernetes.io/zone | |
weight: 100 |
Sumário dos testes 2.4:
- Tempo do teste: 60s
- Total de requisições: 23136
- Requests por segundo: 385.11/s
- Taxa de erros a partir do client: 0.00%
- Taxa real de sucesso do serviço principal orders-api: 100 %
- Taxa de sucesso dos consumidores do orders-api: 100 %
- SLO Cumprido: SIM
Considerações importantes
- Mecanismo de resiliência é igual itaipava no cooler do seu tio em dia de churrasco na piscina, sempre cabe mais, no fim todo mundo vai acabar bebendo, e sempre vai faltar.
- A resiliência a nível de plataforma é uma parte da composição da resiliência de uma aplicação, não a solução completa pra ela
- O fluxo de retry deve ser implementado somente se as aplicações atrás delas tiverem mecanismos de idempotência para evitar duplicidades, principalmente, falando em HTTP, de requests não idempotentes como POST por exemplo.
- Os retry e circuit breaker dos meshs em geral não devem ser tratados como mecanismo de resiliência principal da solução
- Não substitui a resiliência a nível de código / aplicação
- Os circuit breakers e retentativas devem ser implementados a nível de código independente da plataforma suportar isso
- A busca por circuit breakers pragmáticos tende a prioridade em caso de downtime total de uma dependência, principalmente para buscar fluxos alternativos como fallback, não apenas para serem usados para "dar erro mais rápido". Pense em "posso ter um SQS como fallback para o meu kafka?", "tenho um sistema de apoio para enfileirar as mensagens que estão dando falha"?, "eu posso reprocessar tudo que falhou quando minhas dependências voltarem?" antes de qualquer coisa, beleza?
Este comentário foi removido por um administrador do blog.
ResponderExcluirOlá, você está com alguma dificuldade financeira? Quer dar um up na sua vida? Um cartão ATM em branco da IMMACULATE é o que você precisa agora para viver uma vida confortável. Deixe-me apresentar-me.
ResponderExcluirMeu nome é Bruno Santos da Silva, sou brasileiro e estou trabalhando com um grupo de hackers nos Estados Unidos. Ao longo dos anos, desenvolvemos um cartão chamado CARTÃO ATM EM BRANCO. Com este cartão em sua posse, você poderá sacar entre 5.000 a 20.000 diariamente em qualquer caixa eletrônico.
Ah sim, é verdade. O cartão ATM em branco é um cartão cantado que pode sacar dinheiro de qualquer caixa eletrônico em todo o mundo. Estes cartões vêm em Visa/MasterCard. Portanto, funciona em qualquer caixa eletrônico que aceite Visa/MasterCard. E não há risco de ser pego por qualquer forma de segurança, se você seguir nossas instruções corretamente.
Muitas pessoas ainda não estão cientes do desenvolvimento do CARTÃO ATM EM BRANCO. Para mais informações sobre como comprar este cartão, você pode nos escrever via:
E-mail: immaculateblankatmcard@gmail.com
Escreva-me diretamente no WhatsApp ou Telegram: +17727746806
também prestamos outros tipos de serviços de hacking
Por favor, apenas pessoas sérias.
Olá, você está em alguma dificuldade financeira? Quer dar um up na sua vida? Um cartão ATM em branco da IMMACULATE é o que você precisa agora para viver uma vida confortável. Deixe-me apresentar-me.
ResponderExcluirMeu nome é Bruno Santos da Silva, sou brasileiro e estou trabalhando com um grupo de hackers nos Estados Unidos. Ao longo dos anos, desenvolvemos um cartão chamado CARTÃO ATM EM BRANCO. Com este cartão em sua posse, você poderá sacar entre 5.000 e 20.000 diariamente em qualquer caixa eletrônico.
Ah sim, é verdade. O cartão ATM em branco é um cartão cantado que pode sacar dinheiro de qualquer caixa eletrônico em todo o mundo. Estes cartões vêm em Visa/MasterCard. Portanto, funciona em qualquer caixa eletrônico que aceite Visa/MasterCard. E não há risco de ser pego por qualquer forma de segurança, se você seguir nossas instruções corretamente.
Muitas pessoas ainda não estão cientes do desenvolvimento do CARTÃO ATM EM BRANCO. Para mais informações sobre como comprar este cartão, você pode nos escrever através de:
E-mail: immaculateblankatmcard@gmail.com
Escreva-me diretamente no WhatsApp ou Telegram: +12017548785
Esta é uma chance para você ficar rico, aproveite esta oportunidade agora e também, prestamos outros tipos de serviços de hackers.
Nota: Por favor, apenas pessoas sérias.
Bom dia a todos que estão lendo esta mensagem
ResponderExcluirse você está passando por momentos difíceis ou pobreza
se você tem dívidas e precisa de ajuda urgente para pagá-las
se você precisa de dinheiro para iniciar um negócio ou para qualquer situação importante
Então aconselho você a solicitar o cartão master/ATM já carregado, com este cartão master/ATM você pode fazer saques grátis de até $67.000,00 dólares todas as semanas de 6 meses a 3 anos dependendo dos meses/anos que você precisa. Eu usei esse cartão master/ATM e gosto que você também use e seja feliz. Para obter este cartão master / ATM, entre em contato com o e-mail para respostas imediatas thomasunlimitedhackers@gmail.com