Voltar aos microsserviços com Istio. Parte 2



Nota perev. : A primeira parte desta série foi dedicada à introdução do Istio e à demonstração em ação. Agora, falaremos sobre aspectos mais complexos da configuração e uso dessa malha de serviço e, em particular, sobre roteamento bem ajustado e gerenciamento de tráfego de rede.

Lembramos também que o artigo usa configurações (manifestos para Kubernetes e Istio) do repositório istio-mastery .

Gerenciamento de tráfego


Com o Istio, novos recursos aparecem no cluster para fornecer:

  • Roteamento dinâmico de consultas : lançamentos de canários, teste A / B;
  • Balanceamento de carga : simples e consistente, com base em hashes;
  • Recuperação de queda : tempos limite, novas tentativas, disjuntores;
  • Entrada de falha : atrasos, interrupção de solicitações, etc.

Na continuação do artigo, esses recursos serão mostrados como um exemplo do aplicativo selecionado e novos conceitos serão introduzidos ao longo do caminho. O primeiro desses conceitos será o DestinationRules (ou seja, regras sobre o destinatário do tráfego / solicitações - aprox. Transl.) , Com o qual ativamos o teste A / B.

Teste A / B: Regras de Destino na Prática


O teste A / B é usado nos casos em que existem duas versões do aplicativo (geralmente elas diferem visualmente) e não temos 100% de certeza de qual deles melhorará a interação do usuário. Portanto, lançamos simultaneamente as duas versões e coletamos métricas.

Para implantar a segunda versão do front-end necessária para demonstrar o teste A / B, execute o seguinte comando:

 $ kubectl apply -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml deployment.extensions/sa-frontend-green created 

O manifesto de implantação da "versão verde" difere em dois locais:

  1. A imagem é baseada em outra tag - istio-green ,
  2. Os pods têm uma version: green rótulo version: green .

Como as duas implantações possuem o rótulo app: sa-frontend , as solicitações roteadas pelo serviço virtual sa-external-services para o serviço sa-frontend serão redirecionadas para todas as suas instâncias e a carga será distribuída usando o algoritmo round-robin , que levará à seguinte situação:


Arquivos solicitados não encontrados

Esses arquivos não foram encontrados devido ao fato de serem chamados de maneira diferente em diferentes versões do aplicativo. Vamos nos certificar disso:

 $ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main /static/css/main.c7071b22.css /static/js/main.059f8e9c.js $ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main /static/css/main.f87cd8c9.css /static/js/main.f7659dbb.js 

Isso significa que o index.html , solicitando uma versão dos arquivos estáticos, pode ser enviado pelo balanceador de carga para os pods que possuem uma versão diferente, onde, por razões óbvias, esses arquivos não existem. Portanto, para que o aplicativo funcione, precisamos colocar uma restrição: " a mesma versão do aplicativo que forneceu index.html também deve atender a solicitações subsequentes ".

Atingiremos a meta com balanceamento de carga consistente com base em hash (Consistent Hash Loadbalancing) . Nesse caso, as solicitações de um cliente são enviadas para a mesma instância de back-end , para a qual uma propriedade predefinida é usada - por exemplo, um cabeçalho HTTP. Implementado usando DestinationRules.

DestinationRules


Depois que o VirtualService enviou uma solicitação ao serviço desejado, usando DestinationRules, podemos determinar as políticas que serão aplicadas ao tráfego destinado às instâncias desse serviço:


Gerenciamento de Tráfego de Recursos do Istio

Nota : O efeito dos recursos do Istio no tráfego da rede é apresentado aqui de uma maneira simplificada. Para ser preciso, a decisão em qual instância enviar a solicitação é tomada pelo Envoy no Ingress Gateway configurado no CRD.

Usando as Regras de destino, podemos configurar o balanceamento de carga para que hashes consistentes sejam usados ​​e respostas da mesma instância de serviço sejam garantidas para o mesmo usuário. A seguinte configuração permite que isto ( destinationrule-sa-frontend.yaml ) consiga isso:

 apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: sa-frontend spec: host: sa-frontend trafficPolicy: loadBalancer: consistentHash: httpHeaderName: version # 1 

1 - o hash será gerado com base no conteúdo do cabeçalho da version HTTP.

Aplique a configuração com o seguinte comando:

 $ kubectl apply -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml destinationrule.networking.istio.io/sa-frontend created 

Agora execute o comando abaixo e certifique-se de obter os arquivos necessários ao especificar o cabeçalho da version :

 $ curl --silent -H "version: yogo" http://$EXTERNAL_IP/ | tr '"' '\n' | grep main 

Nota : para adicionar valores diferentes no cabeçalho e testar os resultados diretamente no navegador, você pode usar esta extensão para o Chrome (ou esta para o Firefox - aprox. Transl.) .

Em geral, o DestinationRules possui mais opções no campo de balanceamento de carga - consulte a documentação oficial para obter detalhes.

Antes de explorar o VirtualService, removeremos a "versão verde" do aplicativo e a regra correspondente na direção do tráfego, executando os seguintes comandos:

 $ kubectl delete -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml deployment.extensions “sa-frontend-green” deleted $ kubectl delete -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml destinationrule.networking.istio.io “sa-frontend” deleted 

Espelhamento: Serviços Virtuais na Prática


O sombreamento ("blindagem") ou o espelhamento ("espelhamento") são usados ​​nos casos em que queremos testar uma alteração na produção sem afetar os usuários finais: para isso, duplicamos ("espelhar") solicitações para a segunda instância, onde são feitas as alterações necessárias, e veja as consequências. Simplificando, é quando seu (a) colega seleciona a questão mais crítica e faz uma solicitação de puxar na forma de um monte de sujeira tão grande que ninguém pode realmente fazer uma revisão.

Para testar esse cenário em ação, crie uma segunda instância do SA-Logic com bugs ( buggy ) executando o seguinte comando:

 $ kubectl apply -f resource-manifests/kube/shadowing/sa-logic-service-buggy.yaml deployment.extensions/sa-logic-buggy created 

E agora executamos o comando para garantir que todas as instâncias com app=sa-logic tenham rótulos com as versões correspondentes:

 $ kubectl get pods -l app=sa-logic --show-labels NAME READY LABELS sa-logic-568498cb4d-2sjwj 2/2 app=sa-logic,version=v1 sa-logic-568498cb4d-p4f8c 2/2 app=sa-logic,version=v1 sa-logic-buggy-76dff55847-2fl66 2/2 app=sa-logic,version=v2 sa-logic-buggy-76dff55847-kx8zz 2/2 app=sa-logic,version=v2 

O sa-logic tem como alvo pods com o rótulo app=sa-logic , para que todos os pedidos sejam distribuídos entre todas as instâncias:



... mas queremos que as solicitações sejam direcionadas para instâncias com a versão v1 e espelhadas para instâncias com a versão v2:



Conseguiremos isso através do VirtualService em combinação com o DestinationRule, onde as regras determinarão os subconjuntos e rotas do VirtualService para um subconjunto específico.

Definindo subconjuntos nas regras de destino


Os subconjuntos são definidos pela seguinte configuração ( sa-logic-subsets-destinationrule.yaml ):

 apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: sa-logic spec: host: sa-logic # 1 subsets: - name: v1 # 2 labels: version: v1 # 3 - name: v2 labels: version: v2 

  1. O host determina que esta regra se aplica apenas aos casos em que a rota vai para o sa-logic ;
  2. Os nomes dos subconjuntos são usados ​​ao rotear para instâncias do subconjunto;
  3. Um rótulo define os pares de valores-chave que as instâncias devem corresponder para se tornar parte de um subconjunto.

Aplique a configuração com o seguinte comando:

 $ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-destinationrule.yaml destinationrule.networking.istio.io/sa-logic created 

Agora que os subconjuntos estão definidos, você pode seguir em frente e configurar o VirtualService para aplicar as regras às solicitações à sa-logic, para que elas:

  1. Encaminhado para um subconjunto da v1 ,
  2. Espelhado para um subconjunto da v2 .

O seguinte manifesto permite que você realize seu plano ( sa-logic-subconjuntos-shadowing-vs. Yaml ):

 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 mirror: host: sa-logic subset: v2 

Nenhuma explicação é necessária aqui, então dê uma olhada na ação:

 $ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-shadowing-vs.yaml virtualservice.networking.istio.io/sa-logic created 

Adicione a carga chamando este comando:

 $ while true; do curl -v http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}'; \ sleep .8; done 

Vejamos os resultados no Grafana, onde podemos ver que a versão com buggy falha em aproximadamente 60% das solicitações, mas nenhuma dessas falhas afeta os usuários finais porque eles têm um serviço em funcionamento.


Sucesso de respostas de diferentes versões do sa-logic

Aqui vimos pela primeira vez como o VirtualService é aplicado aos Envoys de nossos serviços: quando o sa-web-app faz uma solicitação à sa-logic , ele passa pelo Envecar sidecar Envoy, que - através do VirtualService - está configurado para rotear a solicitação para o subconjunto v1 e espelhar uma solicitação para um subconjunto da v2 do sa-logic .

Eu sei: você já teve tempo de pensar que os Serviços Virtuais são simples. Na próxima seção, expandimos essa visão pelo fato de que elas também são verdadeiramente magníficas.

Canary rolls


O Canary Deployment é o processo de lançar uma nova versão de um aplicativo para um pequeno número de usuários. É usado para garantir que não haja problemas no lançamento e somente depois disso, já tendo confiança na qualidade suficiente (do lançamento), para se espalhar para um público maior.

Para demonstrar lançamentos de canários, continuaremos trabalhando com um subconjunto de buggy na sa-logic .

Não vamos perder tempo com isso e envie imediatamente 20% dos usuários para a versão com bugs (isso representará nossa distribuição de canários) e os 80% restantes para o serviço normal. Para fazer isso, aplique o seguinte VirtualService ( sa-logic-subsets-canary-vs.yaml ):

 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 weight: 80 # 1 - destination: host: sa-logic subset: v2 weight: 20 # 1 

1 é o peso, que determina a porcentagem de solicitações que serão enviadas ao destinatário ou a um subconjunto do destinatário.

Atualize a configuração anterior do VirtualService para sa-logic seguinte comando:

 $ kubectl apply -f resource-manifests/istio/canary/sa-logic-subsets-canary-vs.yaml virtualservice.networking.istio.io/sa-logic configured 

... e veja imediatamente que parte das solicitações falha:

 $ while true; do \ curl -i http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}' \ --silent -w "Time: %{time_total}s \t Status: %{http_code}\n" \ -o /dev/null; sleep .1; done Time: 0.153075s Status: 200 Time: 0.137581s Status: 200 Time: 0.139345s Status: 200 Time: 30.291806s Status: 500 

Os Serviços Virtuais ativam lançamentos de canários: nesse caso, reduzimos as possíveis conseqüências dos problemas para 20% da base de usuários. Ótimo! Agora, em cada caso, quando não temos certeza do nosso código (em outras palavras, sempre ...), podemos usar espelhamento e lançamentos de canários.

Tempos limite e novas tentativas


Mas nem sempre os erros estão no código. Na lista de " 8 erros na computação distribuída ", em primeiro lugar, aparece a opinião errônea de que "a rede é confiável". Na realidade, a rede não é confiável e, por esse motivo, precisamos de tempos limite e novas tentativas .

Para demonstração, continuaremos a usar a mesma versão do sa-logic ( buggy ) e simularemos a falta de confiabilidade da rede com falhas aleatórias.

Permita que nosso serviço com erros tenha 1/3 de chance de uma resposta muito longa, 1/3 de conclusão com um erro interno do servidor e 1/3 de retorno de página bem-sucedido.

Para mitigar as consequências de tais problemas e melhorar a vida dos usuários, podemos:

  1. adicione um tempo limite se o serviço responder por mais de 8 segundos,
  2. tente novamente se a solicitação falhar.

Para implementação, usaremos a seguinte definição de recurso ( sa-logic-retries-timeouts-vs.yaml ):

 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 weight: 50 - destination: host: sa-logic subset: v2 weight: 50 timeout: 8s # 1 retries: attempts: 3 # 2 perTryTimeout: 3s # 3 

  1. O tempo limite para a solicitação é definido como 8 segundos;
  2. Tentativas repetidas de solicitação são feitas 3 vezes;
  3. E cada tentativa é considerada malsucedida se o tempo de resposta exceder 3 segundos.

Portanto, alcançamos a otimização, porque o usuário não precisa esperar mais de 8 segundos e faremos três novas tentativas para obter uma resposta em caso de falhas, aumentando a chance de uma resposta bem-sucedida.

Aplique a configuração atualizada com o seguinte comando:

 $ kubectl apply -f resource-manifests/istio/retries/sa-logic-retries-timeouts-vs.yaml virtualservice.networking.istio.io/sa-logic configured 

E verifique nos gráficos da Grafana se o número de respostas bem-sucedidas acabou:


Melhorias nas estatísticas de respostas bem-sucedidas após adicionar tempos limite e novas tentativas

Antes de prosseguir para a próxima seção (ou melhor, para a próxima parte do artigo, porque não haverá mais experimentos nesta prática - aprox. Transl.) , Exclua sa-logic-buggy e VirtualService executando os seguintes comandos:

 $ kubectl delete deployment sa-logic-buggy deployment.extensions “sa-logic-buggy” deleted $ kubectl delete virtualservice sa-logic virtualservice.networking.istio.io “sa-logic” deleted 

Padrões de disjuntor e anteparo


Estamos falando de dois padrões importantes na arquitetura de microsserviços que permitem obter serviços de autocorreção .

O disjuntor ("disjuntor") é usado para interromper as solicitações que chegam a uma instância de um serviço considerado não íntegro e restaurá-lo enquanto as solicitações do cliente são redirecionadas para instâncias íntegras desse serviço (o que aumenta a porcentagem de respostas bem-sucedidas). (Nota: Uma descrição mais detalhada do padrão pode ser encontrada, por exemplo, aqui .)

O anteparo ("partição") isola as falhas de serviço da derrota de todo o sistema. Por exemplo, o serviço B está quebrado e outro serviço (o cliente do serviço B) faz uma solicitação para o serviço B, como resultado do qual ele usará seu pool de encadeamentos e não poderá atender a outras solicitações (mesmo que não estejam relacionadas ao serviço B). (Nota: Uma descrição mais detalhada do padrão pode ser encontrada, por exemplo, aqui .)

Omitirei os detalhes sobre a implementação desses padrões, porque eles são fáceis de encontrar na documentação oficial e quero realmente mostrar autenticação e autorização, que serão discutidas na próxima parte do artigo.

PS do tradutor


Leia também em nosso blog:

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


All Articles