Service_Mesh/Istio

[Istio-3주차] Resilience (이론, 실습)

lati-tech 2025. 4. 27. 07:56

6장 Resilience: Solving application networking challenges

별첨

  • Istio DestinationRule 한줄 정리
    • 서비스 또는 서비스의 부분집합(subset)에 대해 정의하여, 라우팅 이후 적용되는 로드밸런싱, 연결 풀, 서킷 브레이커 등의 세부 트래픽 전달(host: aa.com 일 시 label: v2) 규칙을 구성하여 Istio에게 힌트를 주는 정책 정의 리소스

들어가며

  • 주요 사항
    • 회복탄력성의 중요성 이해 Understanding the importance of resilience
    • 클라이언트 측 로드 밸런싱 활용 Leveraging client-side load balancing
    • 요청 시간 초과 및 재시도 구현 Implementing request timeouts and retries
    • 회로 차단 및 연결 풀링 Circuit breaking and connection pooling
    • 마이그레이션 Migrating from application libraries used for resilience
  • 애플리케이션 오류, 네트워크 파티션, 기타 주요 문제는 이따금 예측할 수 없이 실패하여 수작업으로 전환이 어렵다.
  • 이에 합리적인 대응 동작을 구축할 필요가 있다.
  • Istio는 수작업으로 개발자가 코드를 변경하지 않고도 타임아웃, 재시도, 서킷 브레이커를 추가 가능하다. 

 


6.1 Building resilience into the application

들어가며

  • 마이크로서비스는 복원력이 최우선
  • 서비스 장애는 모든 서비스를 중단시킬 수 있음
  • 서비스 관리자는 애플리케이션 및 서비스 전반에 걸쳐 몇 가지 복원력 패턴을 일관되게 채택해야 할 필요성이 있음
  • 예를 들어 서비스 B에 장애가 발생했을 때 과도한 요청 재시도로 서비스 과부하가 일어날 수 있음
  • 과도한 요청 재시도로 연쇄적인 지연이 발생하면,(10초가 모이면 1분, 10분까지 진행) 심각한 연쇄 오류 발생 가능
  • 해결책은 애플리케이션이 장애를 예상해 요청을 처리할 때 자동으로 복원을 시도하거나 대체 경로로 돌아갈 수 있도록 구축
    • 요청 재시도
    • 타임아웃
    • 서킷 브레이킹 패턴
  • 복원력을 올바르고 일관되게 구현할 수 있도록 함 (실습)
  1. 6.1.1 Building resilience into application libraries : 언어 마다 구현 상이, 운영 부담
    • 트위터 Finagle(스칼라/자바/JVM, 타임아웃 재시도 서킷브레이킹) 혹은 NetflixOSS 스택: Hystrix(서킷 브레이커), Ribbon(클라이언트 측 로드 밸런싱) 과 같이 인기 있는 애플리케이션 라이브러리/프레임워크들이 있다..
    • 이런 프레임워크의 한 가지 문제점언어, 프레임워크, 인프라 조합마다 구현 방식이 상이하다는 것이다.
    • 트위터 FinagleNetfilxOSS는 자바 개발자에게는 훌륭하지만 Node.js, Go 언어, 파이썬 개발자는 이런 패턴의 변형을 찾거나 직접 구현해야 했다.
    • 때에 따라서는 이런 라이브러리가 애플리케이션 코드에 침입해 네트워킹 코드가 여거저기 흩어지고 실제 비즈니스 로직을 가려버리는 상황이 발생하기도 했다.
    • 나아가 여러 언어와 프레임워크에 걸쳐 이런 라이브러리들을 유지 관리하는 것은 마이크로서비스 운영 측면에서 부담이 된다.
      (모든 조합을 동시에 패치하고 기능을 동일하게 유지해야 하기 때문)
  2. 6.1.2 Using Istio to solve these problems : 이스티오 서비스 프록시가 복원력 기능 제공
    • Istio 서비스 프록시는 애플리케이션 옆에 위치하며 애플리케이션을 드나드는 모든 네트워크 트래픽을 처리 (그림 6.2)
    • 서비스 프록시는 애플리케이션 수준 요청과 메시지(HTTP 요청 등)를 이해하므로, 프록시 안에서 복원력 기능 구현 가능
    • 서비스 프록시서비스 인스턴스마다 배포되므로 애플리케이션마다 복원력 기능 수행 가능
      Istio 서비스 프록시는 복원력 유지에 중요 기능
    • ex. 서비스 호출 시 HTTP 503 오류 발생 시 3번 Retry 설정 (failed, count, timeout 각각 세부 설정 가능)
    • 복원력 패턴
      • 클라이언트 측 로드 밸런싱 Client-side load balancing
      • 지역 인식 로드 밸런싱 Locality-aware load balancing
      • 타임아웃 및 재시도 Timeouts and retries
      • 서킷 브레이킹 Circuit breaking
  3. 6.1.3 Decentralized implementation of resilience : 복원력 패턴을 분산 구현
    • Istio 사용 시 중앙집중식 게이트웨이 불필요 - Proxy가 애플리케이션 인스턴스와 같은 위치에 존재
    • 중앙집중식 게이트웨이 단점: 1회 하드웨어 구성 시 변경이 어려움 - 동적이고 탄력적인 클라우드 아키텍처와 대응 및 확장에 어려움
    • Istio를 사용 시 애플리케이션 별 복원력 패턴 처리 가능 - 분산 구현
    • 예시: 닉 잭슨 의 Fake Service라는 프로젝트 - https://github.com/nicholasjackson/fake-service

      •  simple-web 서비스가 simple-backend 백엔드를 호출

 


6.2 Client-side load balancing 클라이언트 측 로드 밸런싱 (실습)

들어가며

    • EDS, DestinationRule(Client LoadBalancer)
      • 클라이언트 측 로드 밸런싱이란?: 클라이언트에게 서비스에서 사용할 수 있는 여러 엔드포인트를 알려주고 클라이언트가 특정 로드 밸런싱 알고리듬을 선택하게 하는 방식 (엔드포인트 간에 요청을 최적으로 분산시키기 위함)
      • 장점
        • 중앙집중식 로드 밸런싱에 의존할 필요성이 줄어듦
        • 클라이언트가 다중 홉을 거칠 필요 없이 특정 엔드포인트로 직접적이면서 의도적으로 요청 가능
        • 클라이언트-서비스는 확장이 용이해져 변화하는 토폴로지에 대응 가능
      • 구성
        • 서비스, Endpoint Discovery(EDS) 를 사용: 서비스 간 통신의 클라이언트 측 프록시에 올바른 최신 정보 제공
        • istio 설정으로 클라이언트 측 로드 밸런식 설정 가능
        • DestinationRule 리소스: 클라이언트가 어떤 로드 밸런싱 알고리즘을 사용할지 설정.
        • Istio의 로드 밸런싱 알고리즘 (Envoy에서 지원, 일부)
          • 라운드 로빈 (기본값)
          • 랜덤
          • 가중치를 적용한 최소 요청
      • Server side load balancing vs. Client side load balancing  정의 및 비교 (장/단점)

        정의

        • Server Side Load Balancing(서버 사이드 로드밸런싱)
          server-side lb

          중앙에 위치한 로드밸런서(하드웨어 또는 소프트웨어)가 모든 클라이언트 요청을 받아, 내부 알고리즘(예: 라운드 로빈, 최소 연결 등)을 통해 여러 서버로 트래픽을 분산시키는 방식이다. 클라이언트는 로드밸런서의 주소만 알고, 실제 서버 목록이나 상태는 알 필요가 없다.

        • Client Side Load Balancing(클라이언트 사이드 로드밸런싱)
          client-side lb

          요청을 보내는 주체(클라이언트)가 직접 서버 목록을 관리하고, 자체적으로 로드밸런싱 알고리즘(예: 라운드 로빈, 랜덤 등)을 사용해 어떤 서버에 요청을 보낼지 결정하는 방식이다. 마이크로서비스 환경에서 각 서비스 인스턴스가 클라이언트 역할을 할 수 있다.

        비교: 장점과 단점

        구분 Server Side Load Balancing Client Side Load Balancing
        구성 위치 중앙 로드밸런서(네트워크 중간) 클라이언트(서비스 또는 앱 내부)
        서버 목록 관리 로드밸런서가 관리 클라이언트가 직접 관리(서비스 디스커버리 필요)
        구현 복잡도 클라이언트는 단순, 로드밸런서 구축 필요 클라이언트가 복잡, 로드밸런싱 로직 내장 필요
        장애 허용성 로드밸런서 장애 시 전체 영향(단일 장애점) 분산 구조, 일부 클라이언트 장애가 전체 영향 없음
        성능(지연) 네트워크 홉 추가로 지연 가능 중간자 없이 직접 연결, 지연 최소화
        확장성 서버 추가 시 로드밸런서 재설정 필요 클라이언트가 동적으로 서버 목록 갱신 가능
        적용 사례 전통적 웹/엔터프라이즈 환경, L4/L7 로드밸런서 마이크로서비스, 클라우드 네이티브 환경
         

        Server Side Load Balancing

        장점

        • 클라이언트가 단순해지고, 서버 추가/제거가 중앙에서 관리된다.
        • 트래픽, 장애 조치, 정책 등을 중앙에서 일괄 관리 가능하다.
        • SSL 종료, 보안 등 추가 기능 제공이 용이하다.

        단점

        • 로드밸런서 자체가 단일 장애점이 될 수 있다(이중화 필요).
        • 네트워크 홉이 추가되어 지연이 발생할 수 있다.
        • 하드웨어/소프트웨어 장비 도입·운영 비용이 발생한다.

        Client Side Load Balancing

        장점

        • 중간 로드밸런서가 없어 네트워크 지연이 줄어든다.
        • 분산 구조로, 일부 클라이언트 장애가 전체 서비스에 영향을 주지 않는다.
        • 동적으로 서버 목록을 갱신할 수 있어 유연하다.

        단점

        • 각 클라이언트에 로드밸런싱 로직과 서버 목록 관리 기능을 구현해야 한다.
        • 클라이언트가 많을수록 관리 복잡도가 증가한다.
        • 서비스 디스커버리 시스템과의 연동이 필요하다.

        결론

        • 전통적인 대규모 웹 서비스나 엔터프라이즈 환경에는 서버 사이드 로드밸런싱이 적합하다.
        • 마이크로서비스, 클라우드 네이티브 환경에서는 클라이언트 사이드 로드밸런싱이 더 유연하고 확장성 있는 선택이 될 수 있다

 

  1. 6.2.1 Getting started with client-side load balancing : DestinationRule 실습
      • 실습 전 초기화
        kubectl delete gw,vs,deploy,svc,destinationrule --all -n istioinaction
        


      • 예제 서비스 2개와 gateway, virtualservice 배포
        # (옵션) kiali 에서 simple-backend-1,2 버전 확인을 위해서 labels 설정 : ch6/simple-backend.yaml
        open ch6/simple-backend.yaml
        ...
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          labels:
            app: simple-backend
            version: v1
          name: simple-backend-1
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: simple-backend
          template:
            metadata:
              labels:
                app: simple-backend
                version: v1
        ...
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          labels:
            app: simple-backend
            version: v2
          name: simple-backend-2
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: simple-backend
          template:
            metadata:
              labels:
                app: simple-backend
                version: v2
        ...
        
        # 예제 서비스 2개 배포
        kubectl apply -f ch6/simple-backend.yaml -n istioinaction
        kubectl apply -f ch6/simple-web.yaml -n istioinaction
        
        # 확인
        kubectl get deploy,pod,svc,ep -n istioinaction -o wide
        NAME                               READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS       IMAGES                                 SELECTOR
        deployment.apps/simple-backend-1   1/1     1            1           105m   simple-backend   nicholasjackson/fake-service:v0.17.0   app=simple-backend
        deployment.apps/simple-backend-2   2/2     2            2           105m   simple-backend   nicholasjackson/fake-service:v0.17.0   app=simple-backend
        deployment.apps/simple-web         1/1     1            1           105m   simple-web       nicholasjackson/fake-service:v0.17.0   app=simple-web
        ...
        
        # gw,vs 배포
        cat ch6/simple-web-gateway.yaml
        apiVersion: networking.istio.io/v1alpha3
        kind: Gateway
        metadata:
          name: simple-web-gateway
        spec:
          selector:
            istio: ingressgateway
          servers:
          - port:
              number: 80
              name: http
              protocol: HTTP
            hosts:
            - "simple-web.istioinaction.io"
        ---
        apiVersion: networking.istio.io/v1alpha3
        kind: VirtualService
        metadata:
          name: simple-web-vs-for-gateway
        spec:
          hosts:
          - "simple-web.istioinaction.io"
          gateways:
          - simple-web-gateway
          http:
          - route:
            - destination:
                host: simple-web
                
        kubectl apply -f ch6/simple-web-gateway.yaml -n istioinaction
        
        # 확인
        kubectl get gw,vs -n istioinaction
        
        docker exec -it myk8s-control-plane istioctl proxy-status
        NAME                                                  CLUSTER        CDS        LDS        EDS        RDS        ECDS         ISTIOD                      VERSION
        istio-ingressgateway-996bc6bb6-ztcx5.istio-system     Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-xmjbj     1.17.8
        simple-backend-1-7449cc5945-d9zmc.istioinaction       Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-xmjbj     1.17.8
        simple-backend-2-6876494bbf-vdttr.istioinaction       Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-xmjbj     1.17.8
        simple-backend-2-6876494bbf-zn6v9.istioinaction       Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-xmjbj     1.17.8
        simple-web-7cd856754-tjdv6.istioinaction              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-xmjbj     1.17.8
        
        
        # 도메인 질의를 위한 임시 설정 : 실습 완료 후에는 삭제 해둘 것
        echo "127.0.0.1       simple-web.istioinaction.io" | sudo tee -a /etc/hosts
        cat /etc/hosts | tail -n 3
        
        # 윈도우(Powershell) 도메인 질의 임시 설정
        Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "127.0.0.1       simple-web.istioinaction.io"
        Get-Content $env:SystemRoot\System32\drivers\etc\hosts | Select-Object -Last 3
        
        
        # 호출
        curl -s http://simple-web.istioinaction.io:30000
        open http://simple-web.istioinaction.io:30000
        
        # 신규 터미널 : 반복 접속 실행 해두기
        while true; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
        
        
        # 로그 확인
        kubectl stern -l app=simple-web -n istioinaction
        kubectl stern -l app=simple-web -n istioinaction -c istio-proxy
        kubectl stern -l app=simple-web -n istioinaction -c simple-web
        kubectl stern -l app=simple-backend -n istioinaction
        kubectl stern -l app=simple-backend -n istioinaction -c istio-proxy
        kubectl stern -l app=simple-backend -n istioinaction -c simple-backend
        
        
        # (옵션) proxy-config
        # proxy-config : simple-web
        docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/simple-web.istioinaction
        
        docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/simple-web.istioinaction
        docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/simple-web.istioinaction | grep backend
        80                                                            simple-backend, simple-backend.istioinaction + 1 more...     /* 
        
        docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local
        SERVICE FQDN                                       PORT     SUBSET     DIRECTION     TYPE     DESTINATION RULE
        simple-backend.istioinaction.svc.cluster.local     80       -          outbound      EDS
        
        docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json
        ...
               "name": "outbound|80||simple-backend.istioinaction.svc.cluster.local",
                "type": "EDS",
                "edsClusterConfig": {
                    "edsConfig": {
                        "ads": {},
                        "initialFetchTimeout": "0s",
                        "resourceApiVersion": "V3"
                    },
                    "serviceName": "outbound|80||simple-backend.istioinaction.svc.cluster.local"
                },
                "connectTimeout": "10s",
                "lbPolicy": "LEAST_REQUEST",
        ...
        
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local'
        ENDPOINT            STATUS      OUTLIER CHECK     CLUSTER
        10.10.0.14:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
        10.10.0.15:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
        10.10.0.16:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
        
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
        ...
        예제 서비스 2개 배포 후 확인
        Gateway, VirtualService 배포 후 확인
        Istio Proxy 현황 확인
        hosts 설정: wsl2

        호출: curl
        호출: Browser


        1:2 분산인 이유: 1번 backend는 Pod가 1개고 2번 backend는 Pod가 2개라 그렇다.
        simple-backend fqdn에 대한 cluster 정보 확인

        endpoint: EDS / lbPolicy: LEAST_REQUEST 인 점 확인

        Endpoint IP 확인



      • DestinationRule로 LB 정책 지정 (ROUND_ROBIN) : simple-backend 서비스 호출하는 모든 클라이언트 대상
        # cat ch6/simple-backend-dr-rr.yaml
        apiVersion: networking.istio.io/v1beta1
        kind: DestinationRule
        metadata:
          name: simple-backend-dr
        spec:
          host: simple-backend.istioinaction.svc.cluster.local
          trafficPolicy:
            loadBalancer:
              simple: ROUND_ROBIN # 엔드포인트 결정을 '순서대로 돌아가며'

         

        적용 및 확인

        • simple-web 은 simple-backend 를 호출하는데, simple-backend 서비스에는 복제본이 여러 개 있다.
        • 이는 의도한 것으로, 런타임에 일부 엔드포인트를 수정해볼 것
        # DestinationRule 적용 : ROUND_ROBIN
        cat ch6/simple-backend-dr-rr.yaml
        kubectl apply -f ch6/simple-backend-dr-rr.yaml -n istioinaction
        
        # 확인 : DestinationRule 단축어 dr
        kubectl get dr -n istioinaction
        NAME                HOST                                             AGE
        simple-backend-dr   simple-backend.istioinaction.svc.cluster.local   11s
        
        kubectl get destinationrule simple-backend-dr -n istioinaction \
         -o jsonpath='{.spec.trafficPolicy.loadBalancer.simple}{"\n"}'
        ROUND_ROBIN
        
        # 호출 : 이 예시 서비스 집합에서는 호출 체인을 보여주는 JSON 응답을 받느다
        ## simple-web 서비스는 simple-backend 서비스를 호출하고, 우리는 궁극적으로 simple-backend-1 에서 온 응답 메시지 Hello를 보게 된다.
        ## 몇 번 더 반복하면 simple-backend-1 과 simple-backend-2 에게 응답을 받는다. 
        curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"
        
        # 반복 호출 확인 : 파드 비중은 backend-2가 2개임
        for in in {1..10}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done
        for in in {1..50}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr
        
        
        # 로그 확인 : backend 요청을 하면 요청을 처리할 redirect 주소를 응답 (301), 전달 받은 redirect(endpoint)로 다시 요청
        kubectl stern -l app=simple-web -n istioinaction -c istio-proxy
        ## simpleweb → simple-backend (301) redirect 응답 수신
        simple-web-7cd856754-tjdv6 istio-proxy [2025-04-20T04:22:24.317Z] "GET // HTTP/1.1" 301 - via_upstream - "-" 0 36 3 3 "172.18.0.1" "curl/8.7.1" "ee707715-7e7c-42c3-a404-d3ee22f79d11" "simple-backend:80" "10.10.0.16:8080" outbound|80||simple-backend.istioinaction.svc.cluster.local 10.10.0.17:46590 10.200.1.161:80 172.18.0.1:0 - default
        ## simpleweb → simple-backend (200)
        simple-web-7cd856754-tjdv6 istio-proxy [2025-04-20T04:22:24.324Z] "GET / HTTP/1.1" 200 - via_upstream - "-" 0 278 156 156 "172.18.0.1" "curl/8.7.1" "ee707715-7e7c-42c3-a404-d3ee22f79d11" "simple-backend:80" "10.10.0.14:8080" outbound|80||simple-backend.istioinaction.svc.cluster.local 10.10.0.17:38336 10.200.1.161:80 172.18.0.1:0 - default
        ## simpleweb → 외부 curl 응답(200)
        simple-web-7cd856754-tjdv6 istio-proxy [2025-04-20T04:22:24.307Z] "GET / HTTP/1.1" 200 - via_upstream - "-" 0 889 177 177 "172.18.0.1" "curl/8.7.1" "ee707715-7e7c-42c3-a404-d3ee22f79d11" "simple-web.istioinaction.io:30000" "10.10.0.17:8080" inbound|8080|| 127.0.0.6:40981 10.10.0.17:8080 172.18.0.1:0 outbound_.80_._.simple-web.istioinaction.svc.cluster.local default
        
        kubectl stern -l app=simple-backend -n istioinaction -c istio-proxy
        ## simple-backend → (응답) simpleweb (301)
        simple-backend-2-6876494bbf-zn6v9 istio-proxy [2025-04-20T04:22:45.209Z] "GET // HTTP/1.1" 301 - via_upstream - "-" 0 36 3 3 "172.18.0.1" "curl/8.7.1" "71ba286a-a45f-41bc-9b57-69710ea576d7" "simple-backend:80" "10.10.0.14:8080" inbound|8080|| 127.0.0.6:54105 10.10.0.14:8080 172.18.0.1:0 outbound_.80_._.simple-backend.istioinaction.svc.cluster.local default
        ## simple-backend → (응답) simpleweb (200)
        simple-backend-1-7449cc5945-d9zmc istio-proxy [2025-04-20T04:22:45.216Z] "GET / HTTP/1.1" 200 - via_upstream - "-" 0 278 152 152 "172.18.0.1" "curl/8.7.1" "71ba286a-a45f-41bc-9b57-69710ea576d7" "simple-backend:80" "10.10.0.15:8080" inbound|8080|| 127.0.0.6:43705 10.10.0.15:8080 172.18.0.1:0 outbound_.80_._.simple-backend.istioinaction.svc.cluster.local default
        
        #
        docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json
        ...
               "name": "outbound|80||simple-backend.istioinaction.svc.cluster.local",
                "type": "EDS",
                "edsClusterConfig": {
                    "edsConfig": {
                        "ads": {},
                        "initialFetchTimeout": "0s",
                        "resourceApiVersion": "V3"
                    },
                    "serviceName": "outbound|80||simple-backend.istioinaction.svc.cluster.local"
                },
                "connectTimeout": "10s",
                "lbPolicy": "LEAST_REQUEST", # RR은 기본값(?)이여서, 해당 부분 설정이 이전과 다르게 없다
        ...
        
        # 
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json

        DestinationRule 적용: ROUND_ROBIN
        반복 호출: 4:6 비율 호출

        반복 호출: 3:7 비율 호출
        로그 확인: simple-web

        로그 확인 - simple-backend


    • simple-web 과 함께 배포된 서비스 프록시가 모든 simple-backend 엔드포인트를 알고 있고 기본 알고리듬을 사용해 요청을 받을 엔드포인트를 결정
    • 부하 생성기를 사용해 simple-backend 서비스 지연 시간을 변화시키는 어느 정도 현실적인 시나리오 (다음 실습)
  2. 6.2.2 Setting up our scenario : Fortio 설치
    • 서비스 소요 시간의 원인들
      • 요청 크기 Request size
      • 처리 복잡도 Processing complexity
      • 데이터베이스 사용량 Database usage
      • 시간이 걸리는 다른 서비스 호출 Calling other services that take time
      • 서비스 외적인 이유
        • 예기치 못한, 모든 작업을 멈추는 stop-the-world 가비지 컬렉션 Unexpected, stop-the-world garbage collections
        • 리소스 경합 Resource contention (CPU, 네트워크 등)
        • 네트워크 혼잡 Network congestion
      • 서비스 지연 및 편차를 주고, 서비스를 다시 호출하여 최초 응답 시간 차이 관찰 (실습)
        # 호출 3회 반복 : netshoot 에서 서비스명으로 내부 접속
        kubectl exec -it netshoot -- time curl -s -o /dev/null http://simple-web.istioinaction
        kubectl exec -it netshoot -- time curl -s -o /dev/null http://simple-web.istioinaction
        kubectl exec -it netshoot -- time curl -s -o /dev/null http://simple-web.istioinaction
        real    0m 0.17s
        user    0m 0.00s
        sys     0m 0.00s
        ...
        • 서비스를 호출 할 때마다 응답 시간이 달라진다.
        • 로드 밸런싱은 주기적으로 혹은 예기치 못하게 지연 시간이 급증하는 엔드포인트의 영향을 줄이는 효과적인 전략이 될 수 있다.

         

      • Fortio(CLI 부하 생성 도구) 사용 - 클라이언트 측 로드 밸런싱차이 관찰
        • https://github.com/fortio/fortio / 프리뷰 https://demo.fortio.org/
        • Fortio는 그리스어로 '부하'라는 뜻이며,포르티오 라고 읽는다.
        • 부하 테스트 라이브러리, 명령줄 도구, 고급 에코 서버 및 Go(Golang)로 작성된 웹 UI이다.
        • 초당 쿼리 로드를 지정하고 대기 시간 히스토그램 및 기타 유용한 통계를 기록할 수 있다.
          # mac 설치
          brew install fortio
          fortio -h
          fortio server
          open http://127.0.0.1:8080/fortio
          
          # windows 설치
          1. 다운로드 https://github.com/fortio/fortio/releases/download/v1.69.3/fortio_win_1.69.3.zip
          2. 압축 풀기
          3. Windows Command Prompt : fortio.exe server
          4. Once fortio server is running, you can visit its web UI at http://localhost:8080/fortio/


        • Fortio가 우리 서비스를 호출할 수 있는지 확인
          fortio curl http://simple-web.istioinaction.io:30000
          14:16:29.874 r1 [INF] scli.go:122> Starting, command="Φορτίο", version="1.69.3 h1:G1cy4S0/+JKwd1fuAX+1jKdWto4fPpxAdJHtHrWzF1w= go1.24.2 arm64 darwin", go-max-procs=8
          HTTP/1.1 200 OK
          ...


  3. 6.2.3 Testing various client-side load-balancing strategies* : LB 알고리즘에 따란 지연 시간 성능 측정
    그림 출처 https://netpple.github.io/docs/istio-in-action/Istio-ch6-resilience

    • Fortio 사용 방안
      • 60초 동안 10개의 커넥션을 통해 초당 1000개요청 예정
      • Fortio: 각 호출 지연 시간 추적 + 지연 시간 백분위수 분석 ⇒ 히스토그램 표시
      • 테스트 전: 지연 시간 1초로 늘린 simple-backend-1 서비스 투입
        (엔드포인트 중 하나에 긴 가비지 컬렉션 이벤트 또는 기타 애플리케이션 지연 시간이 발생한 상황 시뮬레이션)
      • 로드 밸런싱 전략을 라운드 로빈, 랜덤, 최소 커넥션으로 바꿔가면서 차이점을 관찰

      • 지연된 simple-backend-1 서비스 배포 - fake-service - Dockerhub , Github
        #
        cat ch6/simple-backend-delayed.yaml
        ...
              - env:
                - name: "LISTEN_ADDR"
                  value: "0.0.0.0:8080"
                - name: "SERVER_TYPE"
                  value: "http"                      
                - name: "NAME"
                  value: "simple-backend"      
                - name: "MESSAGE"
                  value: "Hello from simple-backend-1"                     
                - name: "TIMING_VARIANCE"
                  value: "10ms"                              
                - name: "TIMING_50_PERCENTILE"
                  value: "1000ms"                                      
                - name: KUBERNETES_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
                image: nicholasjackson/fake-service:v0.17.0
        ...
        kubectl apply -f ch6/simple-backend-delayed.yaml -n istioinaction
        kubectl rollout restart deployment -n istioinaction simple-backend-1
        
        # 확인???
        kubectl exec -it deploy/simple-backend-1 -n istioinaction -- env | grep TIMING
        TIMING_VARIANCE=10ms
        TIMING_50_PERCENTILE=150ms # ???
        
        kubectl exec -it deploy/simple-backend-2 -n istioinaction -- env | grep TIMING
        TIMING_VARIANCE=10ms
        TIMING_50_PERCENTILE=150ms
        
        # 직접 deploy 편집 수정???
        KUBE_EDITOR="nano" kubectl edit deploy/simple-backend-1 -n istioinaction
        ...
              - name: TIMING_50_PERCENTILE
                  value: 1000ms
        ...
        
        kubectl rollout restart deployment -n istioinaction simple-backend-1
        kubectl exec -it deploy/simple-backend-1 -n istioinaction -- env | grep TIMING
        TIMING_VARIANCE=10ms
        TIMING_50_PERCENTILE=150ms # ???
        
        
        # 동작 중 파드에 env 직접 수정..
        kubectl exec -it deploy/simple-backend-1 -n istioinaction -- sh
        -----------------------------------
        export TIMING_50_PERCENTILE=1000ms
        exit
        -----------------------------------
        
        #
        kubectl describe pod -n istioinaction -l app=simple-backend | grep TIMING_50_PERCENTILE:
              TIMING_50_PERCENTILE:  1000ms
              TIMING_50_PERCENTILE:  150ms
              TIMING_50_PERCENTILE:  150ms
        
        # 테스트
        curl -s http://simple-web.istioinaction.io:30000 | grep duration  
        curl -s http://simple-web.istioinaction.io:30000 | grep duration 
        curl -s http://simple-web.istioinaction.io:30000 | grep duration              
          "duration": "1.058699s",
              "duration": "1.000934s",
        1초 지연 설정

        1초 지연 발생

        Jagger로 트레이싱 확인 (1초 지연 요소 확인)




      • Fortio 인자 입력 후 확인
        ⇒ Start 클릭

        테스트 완료: 결과 파일이 파일시스템에 저장 + 결과 그래프도 표시
        • 라운드 로빈 밸런싱 전략의 경우 지연 시간 결과 ⇒ 75분위수에서 응답이 1초 이상 걸림.
        • target 50% 0.19247
        • target 75% 1.08485
        • target 90% 1.26949
        • target 99% 1.38028
        • target 99.9% 1.39136
      • 로드 밸런싱 알고리즘을 RANDOM 으로 변경하고 다시 로드 테스트
        #
        cat ch6/simple-backend-dr-random.yaml
        apiVersion: networking.istio.io/v1beta1
        kind: DestinationRule
        metadata:
          name: simple-backend-dr
        spec:
          host: simple-backend.istioinaction.svc.cluster.local
          trafficPolicy:
            loadBalancer:
              simple: RANDOM
        
        kubectl apply -f ch6/simple-backend-dr-random.yaml -n istioinaction
        
        # 확인
        kubectl get destinationrule simple-backend-dr -n istioinaction \
         -o jsonpath='{.spec.trafficPolicy.loadBalancer.simple}{"\n"}'
        
        #
        docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json | grep lbPolicy
        "lbPolicy": "RANDOM",

        • RANDOM 로드 밸런싱 알고리즘 지연 시간 결과 ⇒  ⇒ 75분위수에서 응답이 1초 이상 으로  RoundRobin 과 비슷함
          • target 50% 0.193694
          • target 75% 1.0535
          • target 90% 1.12688
          • target 99% 1.17091
          • target 99.9% 1.17532
      • 로드 밸런싱 알고리즘을 Least connection 으로 변경하고 다시 로드 테스트
        #
        cat ch6/simple-backend-dr-least-conn.yaml
        apiVersion: networking.istio.io/v1beta1
        kind: DestinationRule
        metadata:
          name: simple-backend-dr
        spec:
          host: simple-backend.istioinaction.svc.cluster.local
          trafficPolicy:
            loadBalancer:
              simple: LEAST_CONN
        
        kubectl apply -f ch6/simple-backend-dr-least-conn.yaml -n istioinaction
        
        # 확인
        kubectl get destinationrule simple-backend-dr -n istioinaction \
         -o jsonpath='{.spec.trafficPolicy.loadBalancer.simple}{"\n"}'
        
        #
        docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json | grep lbPolicy
        "lbPolicy": "LEAST_REQUEST",


        • Least connection 로드 밸런싱 알고리즘 지연 시간 결과 ⇒ 75분위수에서 응답이 200ms(0.19..) 이내 응답성능으로, RR, Random 보다 좋음!
          • target 50% 0.185492
          • target 75% 0.221552
          • target 90% 1.17661
          • target 99% 1.49254
          • target 99.9% 1.52414
    • 실습 완료 후 Ctrl+CFortio 서버를 종료
  4. 6.2.4 Understanding the different load-balancing algorithms

 

  • 로드 테스트 종합해보면,
    • 첫째, 여러 로드 밸런서는 현실적인 서비스 지연 시간 동작하에서 만들어내는 결과가 서로 다르다.
    • 둘째, 히스토그램과 백분위수는 모두 다르다.
    • 마지막으로, 최소 커넥션이 랜덤과 라운드 로빈보다 성능이 좋다.
      • 이유
        • 라운드 로빈(또는 next-in-loop)은 엔드포인트에 차례대로 요청을 전달한다. 랜덤은 엔드포인트를 무작위로 균일하게 고름
        • 둘 다 비슷한 분포를 기대할 수 있는데, 이 두 전략의 과제는 로드 밸런서 풀의 엔드포인트가 일반적으로 균일하지 않다는 것
        • 최소 커넥션 least-connection 로드 밸런서(엔보이에서는 최소 요청 least request으로 구현)는 특정 엔드포인트의 지연 시간을 고려한다.
        • 요청을 엔드포인트로 보낼 때 대기열 깊이 queue depth 를 살펴 활성 요청 개수를 파악하고, 활성 요청이 가장 적은 엔드포인트를 고른다.
        • 이런 알고리즘 유형을 사용하면, 형편없이 동작하는 엔드포인트로 요청을 보내는 것을 피하고 좀 더 빠르게 응답하는 엔드포인트를 선호할 수 있다.
        • 로드 밸런서에 대한 자세한 정보는 엔보이 문서를 참고 - Docs

 


6.3 Locality-aware load balancing 지역 인식 로드 밸런싱 (실습)

들어가며

  • 컨트롤 플레인: 서비스 토폴로지를 이해하고 어떻게 발전할 수 있는 지 파악하는 역할도 함
  • 서비스 메시에서 전체 서비스 토폴로지를 이해할 때의 이점
    • 서비스와 피어 서비스의 위치 같은 휴리스틱 heuristic 을 바탕으로, 라우팅과 로드 밸런싱을 자동으로 결정할 수 있음
      동일한 위치의 서비스를 호출하는 것을 선호한다
    • Istio가 지원하는 로드 밸런싱 유형 중 하나는, 워크로드의 위치에 따라 루트에 가중치를 부여하고 라우팅 결정을 내리는 것
      • ex. 이스티오는 특정 서비스를 배포한 리전과 가용 영역을 식별하고, 더 가까운 서비스에 우선순위를 부여 가능
    • 만약 simple-backend 서비스를 여러 리전에 배포했다면(us-west, us-east, europe-west), 호출하는 방법은 여러 가지
    • simple-web을 us-west 리전에 배포했다면, 우리는 simple-web이 하는 simple-backend 호출이 us-west 로컬이길 바랄 것 (그림 참고)
    • 모든 엔드포인트를 동등하게 취급한다면 리전이나 영역을 넘나들면서 지연 시간이 길어지고 비용이 발생할 가능성이 높음

 

  1. 6.3.1 Hands-on with locality load balancing*
    • 지역 인식 로드 밸런싱이 잘 동작하는지 살펴보기
    • 쿠버네티스에 배포할 때, 리전과 영역 정보를 노드 레이블에 추가할 수 있음
      • ex. failure-domain.beta.kubernetes.io/region 레이블 및 failure-domain.beta.kubernetes.io/zone 은 각각 리전과 영역을 지정 할 수 있게 해 줌
      • 최근에는 쿠버네티스 API 정식 버전에서는 이 레이블들을 topology.kubernetes.io/regiontopology.kubernetes.io/zone 으로 대체
    • 이런 레이블은 구글 클라우드나 AWS 같은 클라우드 프로바이더가 자동으로 추가하는 경우가 많음
    • Istio는 이런 노드 레이블을 가져와 엔보이 로드 밸런싱 엔드포인트에 지역 정보로 보강

    • 현재 노드 1대(?)로 실습 하고 있으니, 다른 방식으로 지역 노드(?)로 실습 하기

    • Istio에는 워크로드에 지역을 명시적으로 설정할 수 있는 방법 존재
      • Pod에 istio-locality 라는 레이블을 달아 리전/영역을 지정할 수 있다.
      • 이러면 지역 인식 라우팅 및 로드 밸런싱을 시연하는 것이 가능
    • 예를 들어, simple-web 디플로이먼트는 다음과 같을 수 있음
      # cat ch6/simple-service-locality.yaml
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        labels:
          app: simple-web
        name: simple-web
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: simple-web
        template:
          metadata:
            labels:
              app: simple-web
              istio-locality: us-west1.us-west1-a
      ...
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        labels:
          app: simple-backend
        name: simple-backend-1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: simple-backend
        template:
          metadata:
            labels:
              app: simple-backend
              istio-locality: us-west1.us-west1-a
              version: v1 # 추가해두자!
      ...
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        labels:
          app: simple-backend
        name: simple-backend-2
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: simple-backend
        template:
          metadata:
            labels:
              app: simple-backend
              istio-locality: us-west1.us-west1-b
              version: v2 # 추가해두자!
      ...


      • simple-backend 서비스를 배포할 때 지역 레이블 지정
        • simple-web과 같은 지역인 us-west1-a 에 simple-backend-1을 배포
        • us-west1-b 에 simple-backend-2 를 배포 (리전은 동일하지만 Zone이 다름)
      • 지역 간에 로드 밸런싱을 수행할 수 있는 Istio의 기능에는 리전, 영역, 심지어는 더 세밀한 하위 영역 subzone 도 포함함

    • 다음 서비스를 배포
      #
      kubectl apply -f ch6/simple-service-locality.yaml -n istioinaction
      
      # 확인
      ## simple-backend-1 : us-west1-a  (same locality as simple-web)
      kubectl get deployment.apps/simple-backend-1 -n istioinaction \
      -o jsonpath='{.spec.template.metadata.labels.istio-locality}{"\n"}'
      us-west1.us-west1-a
      
      ## simple-backend-2 : us-west1-b
      kubectl get deployment.apps/simple-backend-2 -n istioinaction \
      -o jsonpath='{.spec.template.metadata.labels.istio-locality}{"\n"}'
      us-west1.us-west1-b
      서비스 배포
      • Istio의 지역 인식 로드 밸런싱은 기본적으로 활성화되어 있음 https://istio.io/v1.17/docs/reference/config/istio.mesh.v1alpha1/
        • Locality aware load balancing is enabled by default
      • 비활성화meshConfig.localityLbSetting.enabled: false
      • Istio in actions 책 저자가 추천하는 이스티오의 지역 인식 로드 밸런싱 블로깅
        https://karlstoney.com/locality-aware-routing/
        • 실습과 같이, 클러스터의 노드가 여러 가용성 영역에 배포돼 있다면 기본 지역 인식 로드 밸런싱이 항상 바람직하지는 않을 수도 있음을 고려해야 함
        • 예제에서는 어느 지역에서도 simple-backend(목표 서비스) 복제본이 simple-web(호출하는 서비스)보다 적지 않음
        • 그러나 실제 환경에서는 특정 지역에서 호출하는 서비스 인스턴스 보다 목표 서비스 인스턴스가 적게 배포될 수도 있음
          • 이로 인해 목표 서비스가 과부하를 겪을 수 있고, 시스템 전체의 부하가 의도한 것처럼 불균형하게 분산될 수 있음
      • 결론: 부하 특성과 토폴로지에 맞춰 로드 밸런싱을 튜닝하는 것이 중요

      • 지역 정보가 준비되면,
        us-west1-a 에 있는 simple-web 호출이
        동일 Zone인 us-west1-a 에 배포된 simple-backend 서비스로 갈 것으로 기대할 수 있음
        동일한 위치의 서비스를 호출하는 것을 선호
      • 예제에서는 simple-web의 모든 트래픽이 us-west1-a 에 있는 simple-backend-1 로 향함
      • simple-backend-2 서비스는 simple-web 과 다른 영역인 us-west-1b에 배포돼 있음.
        • 따라서 us-west1-a 에 있는 서비스가 실패하기 시작할 때만 simple-backend-2 로 향할 것으로 기대

      • 호출 테스트 1지역 정보를 고려하지 않고 simple-backend 모든 엔드포인트로 트래픽이 로드 밸런싱 됨
        # 신규 터미널 : 반복 접속 실행 해두기
        while true; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
        
        # 호출 : 이 예시 서비스 집합에서는 호출 체인을 보여주는 JSON 응답을 받느다
        curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"
        
        # 반복 호출 확인 : 파드 비중은 backend-2가 2개임
        for in in {1..10}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done
        for in in {1..50}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr

        • 이스티오에서 지역 인식 로드밸런싱이 작동하려면 헬스 체크를 설정해야 함
        • Health Check가 없으면 Istio가 다음 사항을 알지 못함
          • Istio는 로드 밸런싱 풀의 어떤 엔드포인트가 정상적이지 않은지 알지 못함
          • 또한 다음 지역으로 넘어가기 위해 어떤 휴리스틱을 사용해야 하는지 알지 못함
        • 이상값 감지
          • 엔드포인트의 동작과, 엔드포인트가 정상적으로 보이는지 여부를 수동적으로 감시
          • 엔드포인트가 오류를 반환하는지 지켜보다가, 오류가 반환되면 엔드포인트를 비정상으로 표시
      • simple-backend 서비스에 이상값 감지를 설정해 수동적인 헬스 체크 설정을 추가
        #
        cat ch6/simple-backend-dr-outlier.yaml
        apiVersion: networking.istio.io/v1beta1
        kind: DestinationRule
        metadata:
          name: simple-backend-dr
        spec:
          host: simple-backend.istioinaction.svc.cluster.local
          trafficPolicy:
            outlierDetection:
              consecutive5xxErrors: 1
              interval: 5s
              baseEjectionTime: 30s
              maxEjectionPercent: 100
        
        kubectl apply -f ch6/simple-backend-dr-outlier.yaml -n istioinaction
        
        # 확인
        kubectl get dr -n istioinaction simple-backend-dr -o jsonpath='{.spec}' | jq
        
        
        # 반복 호출 확인 : 파드 비중 확인
        for in in {1..10}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done
        for in in {1..50}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr
        
        
        # proxy-config : simple-web 에서 simple-backend 정보 확인
        docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local        
        docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json
        ...
                },
                "outlierDetection": {
                    "consecutive5xx": 1,
                    "interval": "5s",
                    "baseEjectionTime": "30s",
                    "maxEjectionPercent": 100,
                    "enforcingConsecutive5xx": 100,
                    "enforcingSuccessRate": 0
                },
        ...
        
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local'
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
        ...
                        "healthStatus": {
                            "edsHealthStatus": "HEALTHY"
                        },
                        "weight": 1,
                        "priority": 1,
                        "locality": {
                            "region": "us-west1",
                            "zone": "us-west1-b"
                        }
                    
        ...
        
        # 로그 확인
        kubectl logs -n istioinaction -l app=simple-backend -c istio-proxy -f
        kubectl stern -l app=simple-backend -n istioinaction
        ...
        배포 및 설정 확인

        반복 호출로 Pod 비중 확인 (9:1 , 6:4)

        이상 탐지 항목들을 확인할 수 있다. (기본 거절 시간: 30초)
        locality 적용이 안되어 실패


      • 호출 테스트 2 ⇒ 오동작 주입 후 확인
        • 트래픽이 가용 영역을 넘어가는 것을 보기 위해 simple-backend-1 서비스를 오동작 상태로 만들어보자.
        • simple-web 에서 simple-backend-1 호출하면 항상 HTTP 500 오류를 발생하게 하자
        # HTTP 500 에러를 일정비율로 발생
        cat ch6/simple-service-locality-failure.yaml
        ...
                - name: "ERROR_TYPE"
                  value: "http_error"           
                - name: "ERROR_RATE"
                  value: "1"                              
                - name: "ERROR_CODE"
                  value: "500"  
        ...
        kubectl apply -f ch6/simple-service-locality-failure.yaml -n istioinaction
        
        # simple-backend-1- Pod 가 Running 상태로 완전히 배포된 후에 호출 확인
        
        # 반복 호출 확인 : 파드 비중 확인
        for in in {1..10}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done
        for in in {1..50}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr
        
        
        # 확인
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local'        
        ENDPOINT            STATUS      OUTLIER CHECK     CLUSTER
        10.10.0.23:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
        10.10.0.24:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
        10.10.0.25:8080     HEALTHY     FAILED            outbound|80||simple-backend.istioinaction.svc.cluster.local
        
        # simple-backend-1 500에러 리턴으로 outliercheck 실패 상태로 호출에서 제외됨
        docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
        ...
                        "healthStatus": {
                            "failedOutlierCheck": true,
                            "edsHealthStatus": "HEALTHY"
                        },
                        ...
                        "healthStatus": {
                            "edsHealthStatus": "HEALTHY"
                        },
        • 이렇게 특정 지역의 서비스가 제대로 동작하지 않을 때 예상하는 지역 인식 로드 밸런싱 결과를 얻을 수 있다.
        • 이 지역 인식 로드 밸런싱은 단일 클러스터 내부에서 이뤄지는 것임을 유의하자
      • 다음 실습을 위해 simple-backend-1 을 정상화
        kubectl apply -f ch6/simple-service-locality.yaml -n istioinaction



  2. 6.3.2 More control over locality load balancing with weighted distribution : 가중치 분포로 지역 인식 LB 제어 강화
    • 지역 인식 로드밸런싱은 동작 방식 일부를 제어할 수도 있음
    • Istio의 기본 설정: 서비스 프록시는 모든 트래픽을 동일 지역의 서비스로 보내고, 장애나 비정상 엔드포인트가 있을 때만 다른 지역으로 넘김
      • 트래픽 일부를 여러 지역에 분산하고자 함: 기본 동작에 영향을 줄 수 있음. 이를 지역 가중 분포 locality weighted distribution 라고 함
      • 특정 지역의 서비스가 피크 peak 시간이나 계절성 트래픽으로 인해 과부하될 것으로 예상될 경우 사용할 수 있는 방법
    • ex. 특정 영역에서 리전이 처리 할 수 없는 부하 인입
      • 트래픽의 70%가 최인접 지역으로 가고, 30%가 인접 지역으로 가기를 기대
    • 앞선 실습처럼 simple-backend 서비스로 가는 트래픽 70%를 us-west1-a로, 30%를 us-west1-b로 보낼 것

    • 실습: lb에 가중치 적용
      #
      cat ch6/simple-backend-dr-outlier-locality.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: simple-backend-dr
      spec:
        host: simple-backend.istioinaction.svc.cluster.local
        trafficPolicy:
          loadBalancer: # 로드 밸런서 설정 추가
            localityLbSetting:
              distribute:
              - from: us-west1/us-west1-a/* # 출발지 영역
                to:
                  "us-west1/us-west1-a/*": 70 # 목적지 영역
                  "us-west1/us-west1-b/*": 30 # 목적지 영역
          connectionPool:      
            http:
              http2MaxRequests: 10
              maxRequestsPerConnection: 10
          outlierDetection:
            consecutive5xxErrors: 1
            interval: 5s
            baseEjectionTime: 30s
            maxEjectionPercent: 100
      
      kubectl apply -f ch6/simple-backend-dr-outlier-locality.yaml -n istioinaction
      
      
      # 반복 호출 확인 : 파드 비중 확인
      for in in {1..10}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done
      for in in {1..50}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr
      
      
      # endpoint 에 weight 는 모두 1이다. 위 70/30 비중은 어느곳의 envoy 에 설정 되는 걸까?...
      docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
      docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local'
      ENDPOINT            STATUS      OUTLIER CHECK     CLUSTER
      10.10.0.23:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
      10.10.0.24:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
      10.10.0.26:8080     HEALTHY     OK                outbound|80||simple-backend.istioinaction.svc.cluster.local
      반복 호출: 파드 비중 확인

      • 트래픽 라우팅에서는 서비스의 부분집합 간에 트래픽 비중을 제어할 수 있었고, 보통 전체 서비스 그룹 내에서 종류나 버전이 여럿일 때 사용
      • 위 예제에서는 서비스의 배포 토폴로지를 바탕으로 트래픽에 가중치를 부여했고, 부분집합과는 무관
      • 부분집합 라우팅과 가중치 부여는 상호 배타적인 개념이 아님
      • 이 둘은 중첩될 수 있으며, 5장에서 봤던 세밀한 트래픽 제어 및 라우팅을 이번 절에서 살펴본 지역 인식 로드 밸런서 위에 적용 할 수 있음


 


6.4  Transparent timeouts and retries (실습)

들어가며

  • 네트워크에 분산된 구성 요소에 의존하는 시스템을 구축할 때 가장 큰 문제는 지연 시간실패
  • Istio에서 로드 밸런싱과 지역을 사용해 이런 문제를 완화하는 방법
    • 이 네트워크 호출이 너무 길면 어떻게 되는가?
    • 또는 지연 시간이나 다른 네트워크 요인 때문에 간간이 실패한다면?
    • Istio는 이런 문제를 해결하는 데 어떻게 도움이 될 수 있을까?
  • Istio를 사용하면 다양한 종류의 타임아웃과 재시도를 설정해 네트워크에 내재된 신뢰성 문제를 극복할 수 있음
  1. 6.4.1 Timeouts: 지연 시간
    • 지연 시간: 분산 환경에서 가장 다루기 어려운 시나리오 중 하나
    • 처리 속도가 느려지면
      리소스를 오래 들고 있음
      → 서비스에서는 처리해야 할 작업이 적체
      연쇄 장애 상황까지 이어질 수 있음
    • 예기치 못한 시나리오 방지 방안
      • 커넥션이나 요청, 혹은 둘 다에서 타임아웃 구현이 필요.
    • 서비스 호출 사이의 타임아웃이 서로 상호작용하는 방법 (중요)
      • ex. 서비스 A가 서비스 B를 호출할 때 타임아웃은 1초
      • 서비스 B가 서비스 C를 호출할 때 타임이웃은 2초
      • 어떤 타임아웃이 먼저 작동하는가?
        • 가장 제한적인 타임아웃이 먼저 동작하므로, 서비스 B에서 서비스 C로의 타임아웃은 발동하지 않을 것
      • 일반적으로 아키텍처의 가장자리(트래픽이 들어오는 곳)에 가까울수록 타임아웃이 길고
        호출 그래프의 계층이 깊을수록 타임아웃이 짧은(혹은 더 제한적인)것이 합리적
      • 통상, 밖 → 안, backend에 위치할 수록 timeout 을 짧게 설정
    • Istio를 사용해 타임아웃 정책을 제어 (실습)
      • 환경을 재설정
        kubectl apply -f ch6/simple-web.yaml -n istioinaction
        kubectl apply -f ch6/simple-backend.yaml -n istioinaction
        kubectl delete destinationrule simple-backend-dr -n istioinaction
      • 호출 테스트 : simple-backend-1을 1초 delay로 응답
        # 호출 테스트 : 보통 10~20ms 이내 걸림
        curl -s http://simple-web.istioinaction.io:30000 | jq .code
        time curl -s http://simple-web.istioinaction.io:30000 | jq .code
        for in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done
        
        # simple-backend-1를 1초 delay로 응답하도록 배포
        cat ch6/simple-backend-delayed.yaml
        kubectl apply -f ch6/simple-backend-delayed.yaml -n istioinaction
        
        kubectl exec -it deploy/simple-backend-1 -n istioinaction -- env | grep TIMING
        TIMING_VARIANCE=10ms
        TIMING_50_PERCENTILE=150ms
        
        # 동작 중 파드에 env 직접 수정..
        kubectl exec -it deploy/simple-backend-1 -n istioinaction -- sh
        -----------------------------------
        export TIMING_50_PERCENTILE=1000ms
        exit
        -----------------------------------
        
        # 호출 테스트 : simple-backend-1로 로드밸런싱 될 경우 1초 이상 소요 확인
        for in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done
        ...
        curl -s http://simple-web.istioinaction.io:30000  0.01s user 0.01s system 6% cpu 0.200 total
        jq .code  0.00s user 0.00s system 3% cpu 0.199 total
        500
        ...
        호출 테스트 : 보통 10~20ms 이내
        호출 테스트 : simple-backend-1로 로드밸런싱 될 경우 1초 이상 소요 확인

      • Istio 는 지연시간 급증에 대비해 VirtualService 리소스로 요청별로 타임아웃 지정 가능
      • ex. 메시 내 클라이언트에서 simple-backend 로 향하는 호출의 타임아웃을 0.5초로 지정
        # 
        cat ch6/simple-backend-vs-timeout.yaml
        apiVersion: networking.istio.io/v1alpha3
        kind: VirtualService
        metadata:
          name: simple-backend-vs
        spec:
          hosts:
          - simple-backend
          http:
          - route:
            - destination:
                host: simple-backend
            timeout: 0.5s
            
        kubectl apply -f ch6/simple-backend-vs-timeout.yaml -n istioinaction
        
        #
        kubectl get vs -n istioinaction
        NAME                        GATEWAYS                 HOSTS                             AGE
        simple-backend-vs                                    ["simple-backend"]                14s
        simple-web-vs-for-gateway   ["simple-web-gateway"]   ["simple-web.istioinaction.io"]   6h11m
        
        
        # 호출 테스트 : 0.5s 이상 걸리는 호출은 타임아웃 발생 (500응답)
        for in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done
        ...
        curl -s http://simple-web.istioinaction.io:30000  0.01s user 0.01s system 2% cpu 0.537 total
        jq .code  0.00s user 0.00s system 0% cpu 0.535 total
        500
        ...
        
        # istio-proxy config 에서 위 timeout 적용 envoy 설정 부분 찾아 두자.
        virtualservice 로 타임아웃 지정(생성) 확인


  2. 6.4.2 Retries* : 재시도
  • 설정 초기화
    kubectl apply -f ch6/simple-web.yaml -n istioinaction
    kubectl apply -f ch6/simple-backend.yaml -n istioinaction
  • 서비스를 호출할 때 간간이 네트워크 실패를 겪는다면, 애플리케이션이 요청을 재시도하길 원할 수 있다.
  • 요청을 재시도하지 않으면, 서비스가 흔히 발새하고 예견할 수 있는 실패에 취약해져 사용자에게 좋지 않은 경험을 제공할 수 있다.
  • 한편으로 무분별한 재시도는 연쇄 장애를 야기하는 등 시스템 상태를 저하시킬 수 있으므로 적절히 균형을 맞춰야 한다.
  • 서비스가 실제로 과부화된 경우에는 재시도해봐야 문제가 악화시킬 뿐이다.
  • 이스티오의 재시도 옵션을 살펴보자.

  • 이스티오에서는 재시도가 기본적으로 활성화돼 있고, 두 번까지 재시도한다.
  • 동작을 세밀하게 튜닝하기에 앞서 기본 동작을 이해해야 한다.

  • 시작하기 위해 예제 애플리케이션에서 기본적인 재시도를 비활성화하자.
  • VirtualService 리소스에서 최대 재시도를 0으로 설정하면 된다.
    #
    docker exec -it myk8s-control-plane bash
    ----------------------------------------
    # Retry 옵션 끄기 : 최대 재시도 0 설정
    istioctl install --set profile=default --set meshConfig.defaultHttpRetryPolicy.attempts=0
    y
    exit
    ----------------------------------------
    
    # 확인
    kubectl get istiooperators -n istio-system -o yaml
    ...
        meshConfig:
          defaultConfig:
            proxyMetadata: {}
          defaultHttpRetryPolicy:
            attempts: 0
          enablePrometheusMerge: true
    ...
    
    # istio-proxy 에서 적용 부분은?
    Retry 옵션 끄기: 최대 재시도 0 설정

확인

 

  • 에러 발생 시 재시도 실습
    • 이제 주기적으로(75%) 실패하는 simple-backend 서비스 버전을 배포해보자.
    • 이 경우 엔드포인트 셋 중 하나(simple-backend-1)는 그림 6.12처럼 호출 중 75%에 HTTP 503 반환한다



      ERROR Type, Rate, Code 설정 및 호출테스트

      50x 응답


      • 기본적으로, 이스티오는 호출이 실패하면 두 번 더 시도한다. 이 기본 재시도는 특정 상황에서만 적용된다.
      • 일반적으로는 이들 기본 상황에서는 재시도해도 안전하다.
      • 이 상황들은 네트워크 커넥션이 수립되지 않아 첫 시도에서 요청이 전송될 수 없음을 의미하기 때문이다.
        • 커넥션 수립 실패 connect-failure
        • 스트림 거부됨 refused-stream
        • 사용 불가 gRPC 상태 코드 14
        • 취소됨 gRPC 상태 코드 1
        • 재시도할 수 있는 상태 코드들 이스티오에서 기본값은 HTTP 503
    • 우리는 앞서 살펴본 설정으로 기본 재시도 정책을 비활성화했다.
    • 다음 VirtualService 리소스를 사용해 simple-backend 로 향하는 호출에 재시도를 2회로 명시적으로 설정해보자.
      #
      cat ch6/simple-backend-enable-retry.yaml
      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: simple-backend-vs
      spec:
        hosts:
        - simple-backend
        http:
        - route:
          - destination:
              host: simple-backend
          retries:
            attempts: 2
      
      kubectl apply -f ch6/simple-backend-enable-retry.yaml -n istioinaction
      
      #
      docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/simple-web.istioinaction --name 80
      docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/simple-web.istioinaction --name 80 -o json
      ...
                     "name": "simple-backend.istioinaction.svc.cluster.local:80",
                      "domains": [
                          "simple-backend.istioinaction.svc.cluster.local",
                          "simple-backend",
                          "simple-backend.istioinaction.svc",
                          "simple-backend.istioinaction",
                          "10.200.1.161"
                      ],
                      "routes": [
                          {
                              "match": {
                                  "prefix": "/"
                              },
                              "route": {
                                  "cluster": "outbound|80||simple-backend.istioinaction.svc.cluster.local",
                                  "timeout": "0s",
                                  "retryPolicy": {
                                      "retryOn": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
                                      "numRetries": 2,
      ...
      
      # 호출테스트 : 모두 성공!
      # simple-backend-1 --(503, retry 후 정상 응답)--> simple-web --> curl(외부)
      for in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done
      
      # app, istio-proxy log 에서 503 로그 확인해보자.

      • 앞에서 봤듯이, 실패는 있지만 호출자에게는 드러나지 않는다. 이스티오의 재시도 정책을 활성화해 이런 오류를 우회하게끔 했기 때문이다.
      • HTTP 503은 기본적으로 재시도할 수 있는 상태 코드 중 하나다.
      • 다음 VirtualService 재시도 정책은 설정할 수 있는 재시도 파라미터를 보여준다.
        apiVersion: networking.istio.io/v1alpha3
        kind: VirtualService
        metadata:
          name: simple-backend-vs
        spec:
          hosts:
          - simple-backend
          http:
          - route:
            - destination:
                host: simple-backend
            retries:
              attempts: 2 # 최대 재시도 횟수
              retryOn: gateway-error,connect-failure,retriable-4xx # 다시 시도해야 할 오류
              perTryTimeout: 300ms # 타임 아웃
              retryRemoteLocalities: true # 재시도 시 다른 지역의 엔드포인트에 시도할지 여부

        • 다양한 재시도 설정으로 재시도 동작(얼마나 많이, 얼마나 깊게, 어느 엔드포인트로 재시도할 지)과 어떤 상태 코드일 때 재시도할지를 어느 정도 제어할 수 있다. 상술했듯이 모든 요청을 재시도할 수 있거나 해야 하는 것은 아니다.
        • 예를 들어 HTTP 500 코드를 반환하는 simple-backend 서비스를 배포하면, 기본 재시도 동작은 실패를 잡아내지 않는다.
        • 503 이외의 다른 에러 발생 시에도 retry 가 동작하는지 확인해보자.
          # 500 에러 코드 리턴
          cat ch6/simple-backend-periodic-failure-500.yaml
          ...
                  - name: "ERROR_TYPE"
                    value: "http_error"           
                  - name: "ERROR_RATE"
                    value: "0.75"                              
                  - name: "ERROR_CODE"
                    value: "500"
          ...
          
          kubectl apply -f ch6/simple-backend-periodic-failure-500.yaml -n istioinaction
          
          #
          kubectl exec -it deploy/simple-backend-1 -n istioinaction -- sh
          ---------------------------------------------------------------
          export ERROR_TYPE=http_error
          export ERROR_RATE=0.75
          export ERROR_CODE=500
          exit
          ---------------------------------------------------------------
          
          # envoy 설정 확인 : 재시도 동작(retryOn) 에 retriableStatusCodes 는 503만 있음.
          docker exec -it myk8s-control-plane istioctl proxy-config route deploy/simple-web.istioinaction --name 80 -o json
          ...
                                 "route": {
                                      "cluster": "outbound|80||simple-backend.istioinaction.svc.cluster.local",
                                      "timeout": "0s",
                                      "retryPolicy": {
                                          "retryOn": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
                                          "numRetries": 2,
                                          "retryHostPredicate": [
                                              {
                                                  "name": "envoy.retry_host_predicates.previous_hosts",
                                                  "typedConfig": {
                                                      "@type": "type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate"
                                                  }
                                              }
                                          ],
                                          "hostSelectionRetryMaxAttempts": "5",
                                          "retriableStatusCodes": [
                                              503
                                          ]
                                      },
                                      "maxGrpcTimeout": "0s"
                                  },
          ...
          
          
          # 호출테스트 : Retry 동작 안함.
          # simple-backend-1 --(500, retry 안함)--> simple-web --(500)> curl(외부)
          for in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done
          ...
          curl -s http://simple-web.istioinaction.io:30000  0.01s user 0.01s system 30% cpu 0.036 total
          jq .code  0.00s user 0.00s system 14% cpu 0.035 total
          200
          curl -s http://simple-web.istioinaction.io:30000  0.00s user 0.01s system 5% cpu 0.184 total
          jq .code  0.00s user 0.00s system 2% cpu 0.183 total
          500
          ...
        • HTTP 500은 재시도하는 상태 코드에 포함되지 않는다.
        • 모든 HTTP 500 코드(커넥션 수립 실패 및 스트림 거부 포함)를 재시도하는 VirtualService 재시도 정책을 사용해보자.
          #
          cat ch6/simple-backend-vs-retry-500.yaml
          apiVersion: networking.istio.io/v1alpha3
          kind: VirtualService
          metadata:
            name: simple-backend-vs
          spec:
            hosts:
            - simple-backend
            http:
            - route:
              - destination:
                  host: simple-backend
              retries:
                attempts: 2
                retryOn: 5xx # HTTP 5xx 모두에 재시도
          
          kubectl apply -f ch6/simple-backend-vs-retry-500.yaml -n istioinaction
          
          # 호출테스트 : 모두 성공!
          # simple-backend-1 --(500, retry)--> simple-web --(200)> curl(외부)
          for in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done
        • 사용할 수 있는 retryOn 설정은 엔보이 문서를 참조하자.
          https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#x-envoy-retry-on
      • 타임아웃에 따른 재시도
        • 재시도에는 자체적인 제한 시간(perTryTimeout) 이 있다.
        • 이 설정에서 주의할 점은 perTryTimeout에 총 시도 횟수곱한 값전체 요청 제한 시간(이전 절에서 설명)보다 작아야 한다는 것이다.
        • perTryTimeout * attempts < overall timeout
        • 예를 들어, 총 제한 시간이 1초이고 시도별 제한 시간이 500ms에 3회까지 재시도하는 재시도 정책은 의도대로 동작하지 않는다.
        • 재시도를 하기 전에 전체 요청 타임아웃이 발생할 것이다.
        • 또 재시도 사이에는 백오프 backoff 지연이 있다는 점도 유념하자.
        • perTryTimeout * attempts + backoffTime * (attempts-1) < overall timeout
        • 이 백오프 시간도 전체 요청 제한 시간 계산에 포함된다.
      • 작동 방식
        • 요청이 이스티오 서비스를 서비스 프록시를 거쳐 흐를 때, 업스트림으로 전달되는 데 실패하면 요청을 ‘실패 failed’로 표시하고 VirtualService 리소스에 정의한 최대 재시도 횟수까지 재시도한다.
        • 재시도 횟수가 2이면 실제로는 요청이 3회까지 전달되는데, 한 번은 원래 요청이고 두 번은 재시도다.
        • 재시도 사이에 이스티오는 25ms 를 베이스로 재시도를 ‘백오프’ 한다.
        • 재시도 및 백오프 동작을 설명하는 그림 6.13을 참조하자
          요청 실패 시 재시도 요청 흐름


        • 즉, 이스티오는 재시도에 시차를 주고자 연속적인 재시도에서 (25ms x 재시도 횟수)까지 백오프한다. (기다린다)
        • 현재 재시도 베이스는 고정돼 있다.
        • 그러나 다음 절에서 언급하겠지만, 이스티오가 노출하지 않는 엔보이는 API를 바꿀 수 있다.
        • 상술했듯이 이스티오의 기본 재시도 횟수는 2회다.
        • 시스템 내의 계층이 다르면 재시도 횟수도 다르도록 이 값을 재정의하고 싶을 수도 있다.
        • 기본값과 같이 재시도 횟수를 무턱대고 설정하면, 심각한 재시도 ‘천둥 무리 thundering herd’ 문제가 발생할 수 있다. (그림 6.14 참조)
        • 에를 들어 서비스 체인이 5단계 깊이로 연결돼 있고 각 단계가 두 번씩 재시도할 수 있다면, 들어오는 요청 하나에 대해 최대 32회의 요청이 발생할 수 있다.
        • 체인 끝부분의 리소스에 과부하가 걸린 상태에서는 이 추가적인 부하가 해당 리소스를 감당할 수 없게 만들어 쓰러뜨릴수 있다.
        • 이 상황을해결하는 한 가지 방법은 아키텍처 가장자리에서는 재시도 횟수를 1회 내지 0회로 제한하고, 중간 요소는 0회로 하며, 호출 스택 깊숙한 곳에서만 재시도하게 하는 것이다. 하지만 이 방법도 잘 작동하지는 않는다.
        • 또 다른 전략은 전체 재시도 횟수에 상한을 두는 것이다.
        • 재시도 예산 budget 를 이용해 조절할 수 있는데, 이 기능은 아직 이스티오 API에서 노출되지 않고 있다.
        • 이스티오에 이런 문제에 대한 우회로가 있기는 하지만, 이 책의 범위를 벗어나는 내용이다.
        • 마지막으로 재시도는 기본적으로 자기 지역의 엔드포인트에 시도한다. retryRemoteLocalities 설정은 이 동작에 영향을 준다.
        • true로 설정하면, 이스티오는 재시도가 다른 지역으로 넘어갈 수 있도록 허용한다.
        • 이상값 감지가 같은 지역의 엔드포인트가 오작동하고 있음을 알아내기 전에 이 설정이 유용할 수 있다.

       

      6.4.3 Advanced retries : Istio Extension API (EnvoyFilter)