Disjuntor Istio: Desconecte Recipientes Quebrados

As férias terminaram e estamos voltando com nosso segundo post na série Istio Service Mesh.



O tópico de hoje é o disjuntor, que, traduzido para o russo como eletrotécnico, significa "disjuntor", em linguagem comum - "disjuntor". Somente no Istio esta máquina desconecta não circuitos em curto ou sobrecarregados, mas recipientes com defeito.

Como deve funcionar idealmente


Quando os microsserviços são gerenciados pelo Kubernetes, por exemplo, como parte da plataforma OpenShift, eles aumentam e diminuem automaticamente, dependendo da carga. Como os microsserviços funcionam em pods, pode haver várias instâncias de microsserviço em contêiner em um ponto de extremidade, e o Kubernetes encaminhará solicitações e equilibrará a carga entre elas. E - idealmente - tudo isso deve funcionar perfeitamente.

Lembramos que os microsserviços são pequenos e efêmeros. A efemeridade, que aqui significa a simplicidade da emergência e do desaparecimento, é frequentemente subestimada. O nascimento e a morte da próxima instância do microsserviço em pod são bastante esperados, o OpenShift e o Kubernetes fazem isso bem, e tudo funciona muito bem - mas, novamente, em teoria.

Como isso realmente funciona


Agora imagine que uma instância específica do microsserviço, ou seja, o contêiner, se tornou inutilizável: ele não responde (erro 503) ou, o que é mais desagradável, reage, mas muito lentamente. Em outras palavras, ele silencia ou não responde às solicitações, mas não o remove automaticamente do pool. O que deve ser feito neste caso? Tentar de novo? Removê-lo do esquema de roteamento? E o que significa "muito lento" - quanto custa em números e quem os determina? Talvez apenas lhe dê uma pausa e tente mais tarde? Se sim, quanto tempo depois?

O que é Ejeção de Piscina no Istio


E aqui o Istio vem em socorro com seus disjuntores, que removem temporariamente contêineres defeituosos do pool de recursos de roteamento e balanceamento de carga, implementando o procedimento de Ejeção de Pool.

Usando uma estratégia de detecção externa, o Istio detecta curvas de pods que são eliminadas da linha geral e as remove do pool de recursos por um determinado período, chamado de “janela de suspensão”.

Para mostrar como isso funciona no Kubernetes na plataforma OpenShift, começamos com uma captura de tela dos microsserviços que normalmente funcionam do exemplo no repositório Red Hat Developer Demos . Aqui temos dois pods, v1 e v2, em cada um dos quais um contêiner funciona. Quando as regras de roteamento do Istio não são usadas, o Kubernetes, por padrão, aplica o roteamento round-robin uniformemente equilibrado:


Preparando-se para uma falha


Antes de executar a Ejeção de Pool, você deve criar uma regra de roteamento do Istio. Suponha que desejemos distribuir solicitações entre os pods em relação a 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.


E aqui está o resultado desta regra:


É possível reclamar que nesta tela não é 50/50, mas 14: 9, mas com o tempo a situação vai melhorar.

Nós organizamos uma falha


E agora desabilitaremos um dos dois contêineres v2 para que tenhamos um contêiner íntegro v1, um contêiner íntegro v2 e um contêiner com falha v2:


Corrigir a falha


Portanto, 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 expectativa de que ele retorne a um estado íntegro (será reiniciado ou restaurará o desempenho). Aqui está a aparência dessa configuração e os resultados de seu trabalho:



Como você pode ver, o contêiner com falha v2 não é mais usado no roteamento de solicitações, pois foi removido do pool. Mas, após 15 segundos, ele retornará automaticamente para a piscina. Na verdade, apenas mostramos como a Ejeção de Pool funciona.

Comece a construir a arquitetura


A Ejeção de Pool, combinada aos recursos de monitoramento do Istio, permite que você comece a criar uma estrutura para substituir automaticamente os contêineres defeituosos para reduzir ou até mesmo eliminar o tempo de inatividade e as falhas.

A NASA tem um lema de alto nível - Failure Is Not a Option, de autoria do diretor de vôo Gene Krantz . Pode ser traduzido para o russo como "Derrota não é uma opção", e o ponto aqui é que tudo pode ser feito para funcionar com vontade suficiente. No entanto, na vida real, as falhas não acontecem apenas, 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 OpenShift e Istio .

Istio, como escrevemos acima, implementa o conceito de disjuntores, que se provou no mundo físico. E assim como uma máquina automática desconecta uma parte problemática de um circuito, o disjuntor do software no Istio desconecta a conexão entre o fluxo de solicitação e o contêiner do problema quando algo está errado com o terminal, por exemplo, quando o servidor trava ou começa a desacelerar.

Além disso, no segundo caso, existem apenas mais problemas, já que os freios de um contêiner não apenas causam uma cascata de atrasos nos serviços que o acessam e, como resultado, reduzem o desempenho do sistema como um todo, mas também causam solicitações repetidas ao serviço que já está lento, o que apenas agrava a situação. .

Disjuntor em teoria


O disjuntor é um proxy que controla o fluxo de solicitações para o terminal. Quando esse ponto pára de funcionar ou, dependendo das configurações, começa a ficar mais lento, o proxy se desconecta do contêiner. O tráfego é então redirecionado para outros contêineres, bem, apenas por causa do balanceamento de carga. A conexão permanece aberta (aberta) por uma determinada janela de suspensão, por exemplo, dois minutos e, em seguida, é considerada semiaberta (semiaberta). Tentar enviar a próxima solicitação determina o estado adicional da comunicação. Se tudo estiver bem com o serviço, a conexão retornará ao estado operacional e novamente será fechada. Se ainda houver algo errado com o serviço, a conexão será aberta e a janela de suspensão será reativada. Aqui está a aparência do diagrama simplificado de estados do disjuntor:


É importante observar aqui que tudo isso acontece no nível da arquitetura do sistema, por assim dizer. Portanto, em algum momento, você precisará ensinar seus aplicativos a trabalhar com o disjuntor, por exemplo, fornecer um valor padrão em resposta ou, se possível, ignorar a existência do serviço. Um padrão de antepara é usado para isso, mas está além do escopo deste artigo.

Disjuntor na prática


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

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


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 é de até 12 segundos. Isso é claramente um gargalo e precisa ser bordado.

Para fazer isso, usaremos o Istio para eliminar o acesso a contêineres lentos. Aqui está a aparência da configuração correspondente usando o Disjuntor:


A última linha com o parâmetro httpMaxRequestsPerConnection sinaliza que a conexão com deve abrir ao tentar criar mais uma - a segunda - conexão além da existente. Como nosso contêiner imita um serviço de frenagem, essas situações ocorrem periodicamente, e o Istio retornará um erro 503, e aqui está o que o cerco mostrará:


OK, temos disjuntor, o que vem a seguir?


Por isso, implementamos um desligamento automático, sem tocar no código fonte dos próprios serviços. Usando o disjuntor e o procedimento de ejeção de pool descrito acima, podemos remover os contêineres de freio do pool de recursos até que retornem ao normal e verificar seu status com a frequência especificada - em nosso exemplo, são dois minutos (parâmetro sleepWindow).

Observe que a capacidade do aplicativo de responder ao erro 503 ainda está definida no nível do seu código-fonte. Existem muitas estratégias para trabalhar com o disjuntor, que são aplicadas dependendo da situação.

No próximo post: falaremos sobre rastreamento e monitoramento, que já são integrados ou facilmente adicionados ao Istio, além de como introduzir intencionalmente erros no sistema.

Source: https://habr.com/ru/post/pt483262/


All Articles