Docker & Kubernetes

Dominando Istio Avançado: Circuit Breaker, Fault Injection e Observabilidade em Projetos Reais

13 min de leitura

Dominando Istio Avançado: Circuit Breaker, Fault Injection e Observabilidade em Projetos Reais

Circuit Breaker em Istio: Proteção Contra Falhas em Cascata O Circuit Breaker é um padrão de design que atua como um "disjuntor" para suas requisições. Quando um serviço downstream está com problemas, ao invés de continuar enviando requisições que falharão, o Circuit Breaker detecta o padrão de falha e temporariamente impede novas tentativas, evitando desperdício de recursos e degradação em cascata da arquitetura inteira. Em Istio, o Circuit Breaker é configurado através do recurso . Você define limites como número de conexões simultâneas, requisições pendentes e detecta outliers (hosts que se comportam mal) removendo-os do pool de balanceamento. O comportamento é automático e transparente para a aplicação, funcionando no nível da malha. Configurando um Circuit Breaker básico Considere um cenário onde você tem um serviço que frequentemente falha sob carga. Você quer proteger seus consumidores: Nesta configuração, o Circuit Breaker: Limita 100 requisições HTTP pendentes Detecta 5 erros 5xx consecutivos e remove o host por 30 segundos Nunca remove mais

<h2>Circuit Breaker em Istio: Proteção Contra Falhas em Cascata</h2>

<p>O Circuit Breaker é um padrão de design que atua como um &quot;disjuntor&quot; para suas requisições. Quando um serviço downstream está com problemas, ao invés de continuar enviando requisições que falharão, o Circuit Breaker detecta o padrão de falha e temporariamente impede novas tentativas, evitando desperdício de recursos e degradação em cascata da arquitetura inteira.</p>

<p>Em Istio, o Circuit Breaker é configurado através do recurso <code>DestinationRule</code>. Você define limites como número de conexões simultâneas, requisições pendentes e detecta outliers (hosts que se comportam mal) removendo-os do pool de balanceamento. O comportamento é automático e transparente para a aplicação, funcionando no nível da malha.</p>

<h3>Configurando um Circuit Breaker básico</h3>

<p>Considere um cenário onde você tem um serviço <code>payment-api</code> que frequentemente falha sob carga. Você quer proteger seus consumidores:</p>

<pre><code class="language-yaml">apiVersion: networking.istio.io/v1beta1

kind: DestinationRule

metadata:

name: payment-api-circuit-breaker

namespace: production

spec:

host: payment-api

trafficPolicy:

connectionPool:

http:

http1MaxPendingRequests: 100

maxRequestsPerConnection: 2

h2UpgradePolicy: UPGRADE

tcp:

maxConnections: 100

outlierDetection:

consecutive5xxErrors: 5

interval: 30s

baseEjectionTime: 30s

maxEjectionPercent: 50

minRequestVolume: 5

splitExternalLocalOriginErrors: true</code></pre>

<p>Nesta configuração, o Circuit Breaker:</p>

<ul>

<li>Limita 100 requisições HTTP pendentes</li>

<li>Detecta 5 erros 5xx consecutivos e remove o host por 30 segundos</li>

<li>Nunca remove mais de 50% dos hosts disponíveis</li>

<li>Requer no mínimo 5 requisições antes de considerar outliers</li>

</ul>

<h3>Entendendo os parâmetros de Outlier Detection</h3>

<p>O <code>outlierDetection</code> é o coração inteligente do Circuit Breaker. A propriedade <code>consecutive5xxErrors: 5</code> significa que após 5 falhas 5xx consecutivas, Istio remove aquele pod do balanceamento por <code>baseEjectionTime</code>. O campo <code>maxEjectionPercent: 50</code> é crítico em produção — garante que você nunca perde mais da metade da sua capacidade, mesmo com falhas em cascata.</p>

<p>A <code>minRequestVolume: 5</code> evita que decisões sejam tomadas com base em tráfego muito baixo, reduzindo falsos positivos. Em ambientes com pouco tráfego, esse valor deve ser ajustado para refletir o volume real esperado.</p>

<p>---</p>

<h2>Fault Injection: Injetando Falhas de Forma Controlada</h2>

<p>Fault Injection é a prática de injetar falhas (delays, aborts) propositalmente em seu sistema para testar resiliência. Istio permite fazer isso sem modificar código algum — é configuração pura na malha. Você pode simular lentidão de rede ou indisponibilidade temporária para validar se seus circuit breakers, retries e timeouts funcionam corretamente.</p>

<p>Este padrão é essencial para Chaos Engineering. Em vez de esperar que falhas aconteçam naturalmente, você as provoca de forma controlada em ambientes de staging ou produção, identificando fragilidades antes que afetem usuários reais.</p>

<h3>Injetando delays e aborts</h3>

<p>Use um <code>VirtualService</code> para configurar injeção de falhas. Aqui está um exemplo prático:</p>

<pre><code class="language-yaml">apiVersion: networking.istio.io/v1beta1

kind: VirtualService

metadata:

name: payment-api-fault-injection

namespace: production

spec:

hosts:

  • payment-api

http:

  • match:
  • sourceLabels:

version: canary

fault:

delay:

percentage: 10

fixedDelay: 5s

abort:

percentage: 3

grpcStatus: UNAVAILABLE

route:

  • destination:

host: payment-api

port:

number: 8080

  • route:
  • destination:

host: payment-api

port:

number: 8080</code></pre>

<p>Aqui, requisições originadas de pods com label <code>version: canary</code> receberão:</p>

<ul>

<li>10% de atraso de 5 segundos</li>

<li>3% de respostas imediatas com erro <code>UNAVAILABLE</code></li>

</ul>

<p>Tráfego de outras fontes passa direto para o destino sem injeção. Isso permite testar código novo (canary) com falhas controladas enquanto mantém o tráfego regular estável.</p>

<h3>Diferença entre delay e abort</h3>

<p><code>delay</code> simula rede lenta — a requisição ainda é processada, mas com latência extra. Útil para testar timeouts. <code>abort</code> encerra a conexão imediatamente com um código de erro, simulando indisponibilidade. Combining ambos oferece testes mais realistas: parte falha rápido (abort), parte falha lentamente (delay).</p>

<p>Para Debug, você pode aumentar temporariamente as percentagens em staging:</p>

<pre><code class="language-yaml">fault:

delay:

percentage: 100

fixedDelay: 2s

abort:

percentage: 50

grpcStatus: RESOURCE_EXHAUSTED</code></pre>

<p>Com 100% de delay e 50% de abort, você verá imediatamente se sua aplicação comporta-se corretamente sob essas condições extremas.</p>

<p>---</p>

<h2>Observabilidade: Rastreando Tudo na Malha</h2>

<p>Observabilidade em Istio funciona em três pilares: métricas, logs e traces distribuídos. A malha injeta sidecar Envoy em cada pod, e esses proxies coletam dados detalhados sobre tráfego, latência, erros e dependências. Você obtém visibilidade total sem instrumentar código.</p>

<p>Métricas são números (requisições por segundo, latência p99). Logs são eventos estruturados. Traces mostem o caminho completo de uma requisição através de múltiplos serviços, essencial para debugging de problemas em arquiteturas distribuídas.</p>

<h3>Coletando métricas com Prometheus</h3>

<p>Istio expõe métricas em formato Prometheus nos sidecars. Configure um <code>ServiceMonitor</code> (se usar Prometheus Operator) ou um scrape_config manual:</p>

<pre><code class="language-yaml">apiVersion: monitoring.coreos.com/v1

kind: ServiceMonitor

metadata:

name: istio-mesh

namespace: istio-system

spec:

selector:

matchLabels:

release: istio

endpoints:

  • port: http-monitoring

interval: 30s

path: /stats/prometheus</code></pre>

<p>Com isso configurado, você terá métricas como:</p>

<pre><code># Requisições bem-sucedidas

istio_requests_total{destination_service=&quot;payment-api&quot;, response_code=&quot;200&quot;} 15234

Latência em percentis

istio_request_duration_milliseconds_bucket{le=&quot;100&quot;, destination_service=&quot;payment-api&quot;} 5000

istio_request_duration_milliseconds_bucket{le=&quot;500&quot;, destination_service=&quot;payment-api&quot;} 14500

Taxa de erro

istio_requests_total{destination_service=&quot;payment-api&quot;, response_code=&quot;500&quot;} 42</code></pre>

<p>Você pode criar alertas baseados nessas métricas. Por exemplo, alertar quando a taxa de erro 5xx de um serviço ultrapassa 5%:</p>

<pre><code class="language-yaml">groups:

  • name: istio_alerts

rules:

  • alert: HighErrorRate

expr: |

sum(rate(istio_requests_total{response_code=~&quot;5..&quot;}[5m])) by (destination_service) /

sum(rate(istio_requests_total[5m])) by (destination_service) &gt; 0.05

for: 5m

annotations:

summary: &quot;High error rate for {{ $labels.destination_service }}&quot;</code></pre>

<h3>Distributed Tracing com Jaeger</h3>

<p>Istio integra-se nativamente com Jaeger. Cada sidecar propaga headers de trace (<code>x-trace-id</code>, <code>x-parent-span-id</code>) automaticamente:</p>

<pre><code class="language-yaml">apiVersion: telemetry.istio.io/v1alpha1

kind: Telemetry

metadata:

name: tracing-sampling

namespace: istio-system

spec:

tracing:

  • providers:
  • name: jaeger

randomSamplingPercentage: 10</code></pre>

<p>Com 10% de sampling, 10% das requisições são traçadas. Em produção, ajuste conforme volume — muita amostragem consome recursos, pouca perde contexto.</p>

<p>Uma vez configurado, você verá traces como este em Jaeger:</p>

<pre><code>Request ID: a1b2c3d4e5f6g7h8

├─ payment-service (5ms)

│ ├─ database query (3ms)

│ └─ cache lookup (0.5ms)

├─ fraud-service (8ms)

│ └─ external ML model (7ms)

└─ notification-service (1ms)

Total: 14ms</code></pre>

<p>Isso permite identificar exatamente qual serviço é lento em uma cadeia de chamadas.</p>

<h3>Logs Estruturados com Fluentd</h3>

<p>Configure coleta de logs dos sidecars:</p>

<pre><code class="language-yaml">apiVersion: v1

kind: ConfigMap

metadata:

name: fluent-bit-config

namespace: istio-system

data:

parsers.conf: |

[PARSER]

Name docker

Format json

Time_Key time

Time_Format %Y-%m-%dT%H:%M:%S.%L%z

fluent-bit.conf: |

[SERVICE]

Flush 5

Log_Level info

[INPUT]

Name tail

Path /var/log/containers/_istio-proxy_.log

Parser docker

Tag istio.*

[OUTPUT]

Name stackdriver

Match *

resource k8s_pod</code></pre>

<p>Cada requisição processada por Envoy gera um log JSON estruturado, facilitando buscas e agregações em ferramentas como Stackdriver ou ELK.</p>

<p>---</p>

<h2>Integrando Tudo: Um Exemplo Completo de Produção</h2>

<p>Agora vamos integrar Circuit Breaker, Fault Injection e observabilidade em um cenário real. Suponha você tem dois serviços: <code>order-service</code> (frontend) e <code>inventory-service</code> (backend).</p>

<pre><code class="language-yaml"># Namespace

apiVersion: v1

kind: Namespace

metadata:

name: ecommerce

labels:

istio-injection: enabled

---

DestinationRule com Circuit Breaker

apiVersion: networking.istio.io/v1beta1

kind: DestinationRule

metadata:

name: inventory-circuit-breaker

namespace: ecommerce

spec:

host: inventory-service

trafficPolicy:

connectionPool:

http:

http1MaxPendingRequests: 50

maxRequestsPerConnection: 1

tcp:

maxConnections: 50

outlierDetection:

consecutive5xxErrors: 3

interval: 15s

baseEjectionTime: 30s

maxEjectionPercent: 100

minRequestVolume: 3

---

VirtualService com Fault Injection para teste

apiVersion: networking.istio.io/v1beta1

kind: VirtualService

metadata:

name: inventory-fault-injection

namespace: ecommerce

spec:

hosts:

  • inventory-service

http:

  • match:
  • sourceLabels:

app: order-service

test: true

fault:

delay:

percentage: 20

fixedDelay: 2s

timeout: 5s

retries:

attempts: 3

perTryTimeout: 2s

route:

  • destination:

host: inventory-service

port:

number: 8080

  • route:
  • destination:

host: inventory-service

port:

number: 8080

---

Telemetria para observabilidade

apiVersion: telemetry.istio.io/v1alpha1

kind: Telemetry

metadata:

name: production-tracing

namespace: ecommerce

spec:

tracing:

  • providers:
  • name: jaeger

randomSamplingPercentage: 5

useRequestIdForTraceSampling: true</code></pre>

<p>Deploy seu order-service com labels para testes:</p>

<pre><code class="language-yaml">apiVersion: apps/v1

kind: Deployment

metadata:

name: order-service

namespace: ecommerce

spec:

replicas: 2

selector:

matchLabels:

app: order-service

template:

metadata:

labels:

app: order-service

version: v1

test: &quot;true&quot;

spec:

containers:

  • name: order-api

image: order-service:1.2.0

ports:

  • containerPort: 8080

env:

  • name: INVENTORY_SERVICE_URL

value: &quot;http://inventory-service:8080&quot;

livenessProbe:

httpGet:

path: /health

port: 8080

initialDelaySeconds: 10

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: 8080

initialDelaySeconds: 5

periodSeconds: 5</code></pre>

<p>Com esta configuração:</p>

<ol>

<li><strong>Circuit Breaker</strong> atuará quando inventory-service falhar 3x consecutivamente</li>

<li><strong>Fault Injection</strong> adicionará delay de 2s em 20% das requisições do order-service (test=true)</li>

<li><strong>Observabilidade</strong> traçará 5% das requisições em Jaeger, permitindo investigar latências</li>

</ol>

<p>Você pode validar com um teste simples:</p>

<pre><code class="language-bash"># Terminal 1: Monitorar traces em Jaeger

kubectl port-forward -n istio-system svc/jaeger 16686:16686

Terminal 2: Gerar tráfego

kubectl run -it --rm -n ecommerce \

--image=curlimages/curl:latest \

--restart=Never \

test-curl -- \

bash -c &#039;for i in {1..100}; do curl http://order-service:8080/api/orders; sleep 0.1; done&#039;</code></pre>

<p>Em Jaeger, você verá traces como:</p>

<ul>

<li>Requisições normais (~2ms)</li>

<li>Requisições com delay injetado (~2000ms)</li>

<li>Requisições rejeitadas pelo Circuit Breaker (após falhas)</li>

</ul>

<p>---</p>

<h2>Conclusão</h2>

<p>Istio oferece três capacidades transformadoras para resiliência e observabilidade em Kubernetes:</p>

<ol>

<li><strong>Circuit Breaker</strong> automatiza proteção contra falhas em cascata através de <code>DestinationRule</code> e outlier detection, eliminando necessidade de instrumentação em código. A chave é dimensionar corretamente <code>maxEjectionPercent</code> e <code>consecutive5xxErrors</code> para sua carga de trabalho.</li>

</ol>

<ol>

<li><strong>Fault Injection</strong> via <code>VirtualService</code> permite testar resiliência de forma controlada sem esperar por falhas reais, transformando Chaos Engineering em prática segura e previsível. Combine com retries e timeouts para cenários realistas.</li>

</ol>

<ol>

<li><strong>Observabilidade</strong> através de métricas Prometheus, logs estruturados e traces distribuídos fornece visibilidade completa sem alterar aplicações, sendo essencial para debugging em microsserviços. Ajuste sampling de traces conforme volume para balancear fidelidade vs. custo.</li>

</ol>

<p>A combinação desses três pilares transforma sua arquitetura de microsserviços de frágil para robusto, permitindo confiança em produção.</p>

<p>---</p>

<h2>Referências</h2>

<ol>

<li><a href="https://istio.io/latest/docs/reference/config/networking/destination-rule/#OutlierDetection" target="_blank" rel="noopener noreferrer">Istio Documentation - Circuit Breaker</a></li>

</ol>

<ol>

<li><a href="https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPFaultInjection" target="_blank" rel="noopener noreferrer">Istio Documentation - Fault Injection</a></li>

</ol>

<ol>

<li><a href="https://www.envoyproxy.io/docs/envoy/latest/api-v3/cluster/outlier_detection.proto" target="_blank" rel="noopener noreferrer">Envoy Proxy - Outlier Detection</a></li>

</ol>

<ol>

<li><a href="https://www.jaegertracing.io/docs/" target="_blank" rel="noopener noreferrer">Jaeger Distributed Tracing Documentation</a></li>

</ol>

<ol>

<li><a href="https://prometheus.io/docs/practices/naming/" target="_blank" rel="noopener noreferrer">Prometheus Metrics Best Practices</a></li>

</ol>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Docker & Kubernetes

Boas Práticas de Operators em Kubernetes: Construindo Controladores Customizados para Times Ágeis
Boas Práticas de Operators em Kubernetes: Construindo Controladores Customizados para Times Ágeis

Introdução: O que são Operators em Kubernetes Um Kubernetes Operator é um pad...

Guia Completo de Services em Kubernetes: ClusterIP, NodePort, LoadBalancer e ExternalName
Guia Completo de Services em Kubernetes: ClusterIP, NodePort, LoadBalancer e ExternalName

O que é um Service no Kubernetes Um Service no Kubernetes é um objeto que exp...

Network Policies em Kubernetes: Isolamento de Rede entre Pods: Do Básico ao Avançado
Network Policies em Kubernetes: Isolamento de Rede entre Pods: Do Básico ao Avançado

Network Policies em Kubernetes: Isolamento de Rede entre Pods Network Policie...