Disjuntor Istio: desabilitando contêineres defeituosos

As férias acabaram e estamos de volta com nosso segundo post da série Istio Service Mesh.

Disjuntor Istio: desabilitando contêineres defeituosos

O tema de hoje é Disjuntor, que traduzido para a engenharia elétrica russa significa “disjuntor”, na linguagem comum – “disjuntor”. Somente no Istio esta máquina não desconecta um circuito em curto ou sobrecarregado, mas sim contêineres com defeito.

Como isso deve funcionar idealmente

Quando os microsserviços são gerenciados pelo Kubernetes, por exemplo, na plataforma OpenShift, eles aumentam ou diminuem automaticamente dependendo da carga. Como os microsserviços são executados em pods, pode haver várias instâncias de um microsserviço em contêiner em um endpoint, e o Kubernetes encaminhará as solicitações e fará o balanceamento de carga entre elas. E - idealmente - tudo isso deveria funcionar perfeitamente.

Lembramos que os microsserviços são pequenos e efêmeros. A efemeridade, que aqui significa a facilidade de aparecer e desaparecer, é muitas vezes subestimada. O nascimento e a morte de outra instância de microsserviço em um pod são coisas bastante esperadas, o OpenShift e o Kubernetes lidam bem com isso e tudo funciona muito bem - mas novamente na teoria.

Como isso realmente funciona

Agora imagine que uma instância específica de um microsserviço, ou seja, um contêiner, ficou inutilizável: ou não responde (erro 503), ou, o que é mais desagradável, responde, mas muito lentamente. Em outras palavras, ele apresenta falhas ou não responde às solicitações, mas não é removido automaticamente do pool. O que deve ser feito neste caso? Para tentar novamente? Devo removê-lo do esquema de roteamento? E o que significa “muito lento” – quantos são em números e quem os determina? Talvez apenas dê um tempo e tente novamente mais tarde? Se sim, quanto tempo depois?

O que é ejeção de pool no Istio

E aqui o Istio vem ao resgate com suas máquinas de proteção Circuit Breaker, que removem temporariamente contêineres defeituosos do pool de recursos de roteamento e balanceamento de carga, implementando o procedimento Pool Ejection.

Usando uma estratégia de detecção de valores discrepantes, o Istio detecta pods de curva que estão fora de linha e os remove do pool de recursos por um período de tempo especificado, chamado de janela de suspensão.

Para mostrar como isso funciona no Kubernetes na plataforma OpenShift, vamos começar com uma captura de tela de microsserviços funcionando normalmente do exemplo no repositório Demonstrações para desenvolvedores da Red Hat. Aqui temos dois pods, v1 e v2, cada um executando um contêiner. Quando as regras de roteamento do Istio não são usadas, o padrão do Kubernetes é o roteamento round-robin uniformemente balanceado:

Disjuntor Istio: desabilitando contêineres defeituosos

Preparando-se para um acidente

Antes de fazer a ejeção do pool, você precisa criar uma regra de roteamento do Istio. Digamos que queremos distribuir solicitações entre pods na proporção de 50/50. Além disso, aumentaremos o número de contêineres v2 de um para dois, assim:

oc scale deployment recommendation-v2 --replicas=2 -n tutorial

Agora definimos uma regra de roteamento para que o tráfego seja distribuído entre os pods em uma proporção de 50/50.

Disjuntor Istio: desabilitando contêineres defeituosos
Veja como é o resultado desta regra:

Disjuntor Istio: desabilitando contêineres defeituosos
Você pode encontrar falhas no fato de que esta tela não é 50/50, mas 14:9, mas com o tempo a situação vai melhorar.

Fazendo uma falha

Agora vamos desabilitar um dos dois contêineres v2 para que tenhamos um contêiner v1 íntegro, um contêiner v2 íntegro e um contêiner v2 com defeito:

Disjuntor Istio: desabilitando contêineres defeituosos

Corrigindo a falha

Então, temos um contêiner com defeito e é hora da Ejeção do Pool. Usando uma configuração muito simples, excluiremos esse contêiner com falha de qualquer esquema de roteamento por 15 segundos, na esperança de que ele retorne a um estado íntegro (seja reiniciando ou restaurando o desempenho). Esta é a aparência desta configuração e os resultados de seu trabalho:

Disjuntor Istio: desabilitando contêineres defeituosos
Disjuntor Istio: desabilitando contêineres defeituosos
Como você pode ver, o contêiner v2 com falha não é mais usado para rotear solicitações porque foi removido do pool. Mas após 15 segundos ele retornará automaticamente à piscina. Na verdade, acabamos de mostrar como funciona o Pool Ejection.

Vamos começar a construir arquitetura

O Pool Ejection, combinado com os recursos de monitoramento do Istio, permite que você comece a construir uma estrutura para substituir automaticamente contêineres defeituosos para reduzir, se não eliminar, o tempo de inatividade e as falhas.

A NASA tem um lema alto - O fracasso não é uma opção, cujo autor é considerado o diretor de vôo Gene Kranz. Pode ser traduzido para o russo como “O fracasso não é uma opção”, e o significado aqui é que tudo pode funcionar se você tiver vontade suficiente. Porém, na vida real, as falhas não acontecem simplesmente, são inevitáveis, em todos os lugares e em tudo. E como lidar com eles no caso de microsserviços? Em nossa opinião, é melhor confiar não na força de vontade, mas nas capacidades dos contêineres, Kubernetes, Red Hat OpenShiftE Istio.

O Istio, como escrevemos acima, implementa o conceito de disjuntores, que tem se mostrado bem no mundo físico. E assim como um disjuntor elétrico desliga uma seção problemática de um circuito, o software Circuit Breaker do Istio abre a conexão entre um fluxo de solicitações e um contêiner de problema quando algo está errado com o endpoint, por exemplo, quando o servidor travou ou começou a falhar. desacelerar.

Além disso, no segundo caso só há mais problemas, uma vez que os freios de um contêiner não só provocam uma cascata de atrasos nos serviços que o acessam e, consequentemente, reduzem o desempenho do sistema como um todo, mas também geram repetidas solicitações para um serviço já lento, o que só agrava a situação.

Disjuntor em teoria

Circuit Breaker é um proxy que controla o fluxo de solicitações para um endpoint. Quando este ponto para de funcionar ou, dependendo das configurações especificadas, começa a ficar lento, o proxy interrompe a conexão com o container. O tráfego é então redirecionado para outros contêineres, simplesmente devido ao balanceamento de carga. A conexão permanece aberta por uma determinada janela de suspensão, digamos dois minutos, e então é considerada entreaberta. Uma tentativa de enviar a próxima solicitação determina o estado posterior da conexão. Se tudo estiver OK com o serviço, a conexão volta à condição de funcionamento e é novamente fechada. Se ainda houver algo errado com o serviço, a conexão será desconectada e a janela de suspensão será reativada. Esta é a aparência de um diagrama simplificado do estado do disjuntor:

Disjuntor Istio: desabilitando contêineres defeituosos
É importante notar aqui que tudo isso acontece, por assim dizer, no nível da arquitetura do sistema. Então em algum momento você terá que ensinar suas aplicações a trabalhar com Circuit Breaker, como fornecer um valor padrão em resposta ou, se possível, ignorar a existência do serviço. Um padrão de anteparo é usado para isso, mas está além do escopo deste artigo.

Disjuntor na prática

Por exemplo, executaremos duas versões do nosso microsserviço de recomendação no OpenShift. A versão 1 funcionará bem, mas na v2 criaremos um atraso para simular lentidão no servidor. Para visualizar os resultados, use a ferramenta cerco:

siege -r 2 -c 20 -v customer-tutorial.$(minishift ip).nip.io

Disjuntor Istio: desabilitando contêineres defeituosos
Tudo parece funcionar, mas a que custo? À primeira vista, temos 100% de disponibilidade, mas observe mais de perto - a duração máxima da transação chega a 12 segundos. Isto é claramente um gargalo e precisa ser ampliado.

Para fazer isso, usaremos o Istio para eliminar chamadas para contêineres lentos. Esta é a aparência da configuração correspondente usando o disjuntor:

Disjuntor Istio: desabilitando contêineres defeituosos
A última linha com o parâmetro httpMaxRequestsPerConnection sinaliza que a conexão com deve ser desconectada ao tentar criar outra - uma segunda - conexão além da existente. Como nosso contêiner simula um serviço lento, tais situações surgirão periodicamente e o Istio retornará um erro 503, mas é isso que o siege mostrará:

Disjuntor Istio: desabilitando contêineres defeituosos

OK, temos o disjuntor, o que vem a seguir?

Assim, implementamos o desligamento automático sem alterar o código-fonte dos próprios serviços. Usando o Circuit Breaker e o procedimento Pool Ejection descrito acima, podemos remover contêineres de freio do pool de recursos até que retornem ao normal e verificar seu status em uma frequência especificada - em nosso exemplo, são dois minutos (parâmetro sleepWindow).

Observe que a capacidade de um aplicativo responder a um erro 503 ainda é definida no nível do código-fonte. Existem muitas estratégias para usar o Circuit Breaker, dependendo da situação.

Na próxima postagem: Falaremos sobre o rastreamento e o monitoramento que já estão integrados ou facilmente adicionados ao Istio, bem como sobre como introduzir erros intencionalmente no sistema.

Fonte: habr.com

Adicionar um comentário