1. 서론

 

istio를 처음 사용하면, 이전과 달리 설치가 및 설정 방법이 편해져서 사용하기 쉽습니다. 그럼에도 불구하고 istio를 운영하는 것은 여전히 어려운 일입니다. 그 이유는 istio에 문제가 생겼을 때 이를 해결하기 위해서는 istio 내부 아키텍처에 대한 이해가 필수적이기 때문입니다.

 

istio는 엄밀히 말해서 envoy proxy를 관리하는 컨트롤러라고 볼 수 있습니다. 따라서 istio 뿐만 아니라 envoy proxy의 내부 구조에 대해서도 잘 알고 있어야합니다. 이번 포스팅부터 진행되는 envoy internals 시리즈는 envoy 내부 구조와 흐름에 대해서 살펴보면서, 트러블 슈팅을 위한 인사이트를 갖는 것을 목적으로 하고 있습니다. 다만 모든 내용을 다루지는 않으며, istio를 이해하는데 있어 필수적인 부분에 대해서만 살펴보겠습니다. 이번 포스팅은 envoy 관련 첫번째 포스팅으로 envoy 구조와 내부 컴포넌트 동작 원리에 대해서 알아보도록 하겠습니다.

 


 

2. Envoy 컴포넌트

 

 

Envoy는 Proxy 프로그램으로 사용자와 Service 중간에서 Proxy 역할을 수행합니다. 이때 Client로부터 전달받는 트래픽은 Downstream, 전달받은 요청을 Service로 전달하는 트래픽을 Upstream이라고 부릅니다. 즉 Envoy를 기준으로 상위 서비스 전달은 Upstream Envoy로 흘러 들어오는 스트림은 Downstream입니다.

 

그렇다면 Downstream을 통해 전달되는 트래픽이 Envoy의 어떤 과정을 거쳐서 Upstream으로 Service에 전달될까요?

먼저 Envoy의 주요 컴포넌트에 대해서 먼저 알아보겠습니다.

 

 

 

Envoy 내부에서 가장 핵심이 되는 컴포넌트는 위 그림과 같습니다. 도식화된 그림을 살펴보면 여러개 Listener 그리고 요청을 전달하기 위한 Route 과정 그리고 해당 Route 과정을 통해서 Cluster에 전달되고 Cluster는 Load Balancing 정책에 따라서 자신이 보유하고 있는 Endpoint 중 하나를 선정합니다. 결과적으로는 해당 Endpoint에 매칭되는 Service에 트래픽이 전달됩니다. 

 

갑자기 여러가지 컴포넌트가 등장했는데요. 지금부터 하나하나씩 살펴보겠습니다.

 


2-1 Endpoint

 

 

먼저 살펴볼 것은 Endpoint입니다. Endpoint는 위 그림과 같이 Proxy를 통해 연결해야하는 최종 목적지 주소와 Port 번호를 의미합니다. 위와 같이 address는 IP일 수도 있고 혹은 도메인 네임일 수도 있습니다. 그 밖에 health check를 위한 설정 및 Load Balancing을 수행할 때 가중치 와 우선순위 등을 설정할 수 있습니다. 자세한 내용은 Envoy 공식 문서를 통해서 확인하시기 바랍니다.

 


 

2-2 Cluster

 

 

Service는 가용성 혹은 성능 향상의 목적으로 여러 서버에 동일한 Service를 배포합니다. 따라서 단일 Endpoint를 통해 여러개 Service를 관리할 수 있는 논리적인 집합 단위가 필요합니다.

 

Envoy Proxy에서는 Cluster 컴포넌트를 통해 Endpoint들을 그룹핑하여 관리할 수 있습니다. 해당 컴포넌트를 통해서 Endpoint 중에서 어디로 트래픽을 보낼지 결정하는 Load Balancing을 결정할 수 있습니다.

 

  clusters:
  - name: some_service
    connect_timeout: 0.25s
    type: STATIC
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: some_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 1234

 

위 설정은 Envoy proxy 공식 문서의 설정 예시입니다. Cluster 하위에 Endpoint 목록을 지정하도록 되어 있는 것을 확인할 수 있습니다. 달리 말하면 Cluster와 Endpoint 간에는 의존성이 존재함을 확인할 수 있습니다. 위 설정에는 Endpoint 지정외에도 다양한 설정을 지정할 수 있습니다. 가령 Circuit Breaker 설정 HTTP Connection과 DNS refresh와 Resolving 정책 등의 부가적인 옵션을 해당 컴포넌트를 통해서 설정할 수 있습니다. 자세한 옵션 설정은 Envoy 공식 문서를 통해서 확인하시기 바랍니다.

 


 

2-3 Listener

 

 

Listener는 Envoy Proxy가 어떤 address의 어떤 port로 접속하는 요청에 대해서 Proxy 처리를 수행할 것인지를 설정합니다. 가령 위와같이 지정했다면, 해당 Envoy Proxy가 위치한 서버로 접속하는 80 Port 요청에 대해서 Envoy Proxy가 트래픽을 전달받고 후속 작업을 처리하게됩니다. 즉 Listener는 Envoy Proxy로 흐름을 전달하는 문지기 역할이라고 볼 수 있습니다.

 

 

Listener를 통해 트래픽이 전달되었다면, 이를 Cluster에 전달하기 위해서는 여러 내부 과정을 거쳐야합니다. Listener에는 Listener Filters와 Filter Chains(Network Filters)를 지니고 있습니다. 따라서 실제 트래픽이 전달되었을 때 Listener 내부에 위치한 Filter들을 통과하면서 사용자 요청을 분석하고 어떤 Cluster로 전달해야할지 등을 결정합니다. 그렇다면 Listener Filter와 Filter Chains는 무엇이 다를까요?

 

Listener Filters는 Connection에 대한 Metadata를 조작하거나 추가하는 데 사용되며, 변경된 정보를 토대로 Filter Chains에 존재하는 무수한 Filter 중에서 해당 요청을 처리하는데 적합한 Filter를 선정하는데 사용됩니다. 즉 실제 사용자 요청을 처리하는 것은 FIlter Chains에 존재하는 Filter이지만 해당 Filter를 사용하기 위해서 사전에 보조적인 작업을 담당하는 것이 Listener FIlter라고 볼 수 있습니다.

 

참고로 Envoy에서 제공하는 Listener Filter 목록은 위와 같으며, 개별 Filter의 역할은 다음과 같습니다.

 

Filter 역할
HTTP Inspector Application에서 전달한 Traffic을 분석하여 해당 네트워크 요청이 HTTP인지 확인합니다. 또한 HTTP 요청이 맞다면, HTTP 1.1 요청인지 혹은 HTTP 2 요청인지를 분석합니다.

이를 토대로 추후 네트워크 요청에 적합한 Filter Chain을  찾는데 사용됩니다.
Original Destination IpTable에 의해서 redirect된 소켓의 원래 목적지 값 주소를 알기 위해 SO_ORIGINAL_DST 값을 읽는 역할을 수행합니다.  해당 값은 Envoy 처리 이후 Connection Local address로 설정하는데 사용됩니다.
Original Source Client가 Envoy의 주소로 Downstream 연결을 시도하면,  Envoy는 Upstream과 통신을 위해서는  Source IP를 Envoy의 주소로 변경이 필요합니다. 따라서 해당 과정을 통해 연결의 목적지 주소를 Source 주소로 복제하는데 사용합니다.
Proxy Protocol 해당 Listener Filter는 HA Proxy Protocol을 지원하기 위한 역할을 수행합니다.
TLS Inspector HTTP Inspector와 유사하게 해당 요청이 TLS 요청인지를 확인합니다. 이를 토대로 추후 네트워크 요청에 적합한 Filter Chain을 찾는데 사용됩니다.

 

Listener Filter를 통해서 Connection 요청 Metadata를 조작하거나 어떤 요청인지를 분석하고난 이후에는 Filter Chains(Network Filters)에 위치한 FIlter들을 통과하면서 사용자의 요청에 적합한 Filter를 찾아서 수행합니다.

 

 

기본적으로 제공하는 FIlter Chains 목록은 위와 같습니다. 해당 항목들은 L3/L4 Filter 기능을 담당하며, 사용자 요청에 적합한 Filter를 찾아서 처리하고 목적지로 전달하는데 사용합니다. 만약 위 Filters 중 사용자 요청을 처리할 수 없는 경우에는 Envoy에서 제공하는 Default Chain이 사용되며, 만약 Default Chain 설정을 하지 않았다면 해당 Connection은 종료됩니다. 참고로 envoy proxy 기동시 위와 같이 모든 Filter가 등록되는 것은 아니며 순서 또한 다를 수 있습니다. 위 Filter 목록 중 필요한 Filter만 선별적으로 등록 가능합니다. 이에 대해서는 추후 살펴보겠습니다.

 

개별 FIlter의 기능 설명은 공식 문서를 참고하기 바라며, 여기서는 HTTP connection manager에 대해 중점으로 다루어 보고자 합니다.

 


2-3-1 HTTP Connection manager

Envoy에서 HTTP를 담당하는 Network Level의 Filter로써 Filter Chain의 가장 마지막에 위치합니다. 해당 Filter의 주요 기능은 raw byte를 HTTP 메시지 convert를 담당하며, 내부적으로 HTTP L7 Filter들이 존재하여 부가적인 작업을 수행합니다. 따라서 HTTP 요청이 전달되었을 때, Listener Filters 이후 Filter Chain을 수행하는 과정에서 HTTP Connection manager가 요청을 처리할 경우 내부적으로 sub filters를 적용하여 부가작업을 수행합니다.

 

HTTP Connection manager가 담당하는 기능에 대해서 몇 가지 살펴보도록 하겠습니다.

 

1) HTTP header 조작

 - 여러가지 Security 이유로 인해 Envoy를 통해서 특정 header를 삭제하거나 값을 변경할 수 있습니다. 가령 use_remote_address 옵션을 true로 변경했을 경우 connection manager는 실제 전달되는 remote address를 x-forwared-for http header에 사용합니다. 그밖에 다양한 header에 대해서 조작이 가능합니다. 

 

2) Retry 설정

- HTTP 요청에 대해서 내부적으로 연결이 실패했을 때 얼만큼 Retry할 것인지를 설정할 수 있습니다.

 

3) Redirect

- 요청 서비스에서 Redirect 응답이 왔을 때 Proxy 내부에서 해당 3xx 응답을 기반으로 Redirect를 수행할 수 있습니다.

 

4) Timeout

- HTTP 요청에 대해서 응답이 지정 시간동안 없을 경우 요청을 취소할 수 있습니다.

 

위와 같은 기능 외 HTTP Connection manager에는 L7 Filters들이 있어서 해당 Filters를 통해 부가적인 작업을 수행할 수 있다고 말했습니다. 여기에는 다음과 같은 Filter들이 해당됩니다.

 

 

각 Filter에 대한 설명은 Envoy 공식 문서를 참고하시기 바라며, 참고로 위 Filter 중에 Router Filter의 경우는 사용자가 지정한 router 규칙에 일치하는 URL로 접근하였을 경우 지정된 Cluster로 Forwarding을 담당하는 Filter입니다.

 

그렇다면, 지금까지 설명을 바탕으로 HTTP 요청에 대한 Envoy Proxy 내부의 네트워크 흐름을 다시 한번 짚어보겠습니다.

 

1) Listener에 구성된 address와 port에 상응하는 요청이 들어오면, Listener 내부적으로 Listener Filters로 전달합니다.

2) Listener Filters를 순회하면서 Connection Metadata를 조작하고 이후 Network Filters로 전달합니다.

3) Filter Chains(Network Filters)를 순회하면서 사용자 요청을 처리하는데 적합한 Filter를 찾고 해당 Filter가 요청을 처리합니다.

(※ 위 예제에서는 HTTP 요청이 들어왔음을 가정했으므로 HTTP Connection Manager가 이를 담당합니다.)

4) HTTP Connection Manager 내부에 있는 Sub Filters를 순회합니다.

5) L7 필터 마지막에 위치한 Router Filter는 사용자의 Routing Path 요청과 적합한 Cluster를 찾고 해당 Cluster에게 트래픽을 Forwarding 하는 역할을 수행합니다. 

6) Cluster는 내부에 설정된 로드밸런싱 정책등을 고려하여 적합한 Endpoint를 선정하며, 해당 Endpoint에 매칭되는 Service로 트래픽이 전달됩니다.

 


 

2-4 Envoy 컴포넌트 등록 방법

 

 

지금까지 Envoy 내부에 존재하는 컴포넌트를 기반으로 Envoy 네트워크 흐름에 대해서 살펴봤습니다. 그렇다면 Cluster, Listener, Endpoint 등은 어떻게 등록할 수 있을까요?

 

Envoy에서는 2가지 방식으로 컴포넌트 정보를 등록하거나 수정할 수 있습니다. 첫 번째 방식은 Static 방식이고 두 번째 방식은 Dynamic 방식입니다. 

 


2-4-1 Static 등록 방식

 

Static 방식은 말 그대로 Envoy 기동 시점에 사용자가 지정한 Config 파일 정보를 기반으로 내부 컴포넌트를 등록하는 방식입니다. 따라서 Envoy가 이해할 수 있는 형태로 내부 컴포넌트 설정을 기술해야합니다. Envoy에서는 YAML 형태로 이를 지정할 수 있으며, 아래 예제를 통해서 간단히 살펴보겠습니다.

 

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 127.0.0.1, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: some_service }
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
  - name: some_service
    connect_timeout: 0.25s
    type: STATIC
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: some_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 1234

 

해당 설정은 Envoy 공식 문서에 존재하는 예제입니다. 지금까지 살펴본 Envoy 컴포넌트에 대한 개념을 잘 숙지했다면, 위 예제의 큰 구조를 쉽게 파악할 수 있습니다. 

 

먼저 Listener를 보면 listener_0이라는 이름으로 1개의 Listener가 등록되어있고, 내부에는 filter_chains 항목을 통해 Network Filter인 HTTP Connection Manager를 등록하는 것을 확인할 수 있습니다. 또한 Routes 설정을 통해 /으로 들어오는 모든 prefix에 대해서 some_service라는 Cluster로 전달하도록 지정했음을 확인할 수 있습니다. 이를 토대로 Listener로 들어오는 모든 HTTP 설정에 대해서 some_service Cluster로 트래픽이 전달되도록 Router Filter가 지정될 것임을 알 수 있습니다.

 

Clusters 항목을 보면, 이전에 Route에서 지정한 some_service 이름으로 등록되어있음을 확인할 수 있고 내부적으로 endpoint를 등록하여 Cluster로 트래픽이 전달되었을 때 내부적으로 어떤 endpoint로 전달할 수 있는지를 알 수 있습니다. 추가적으로 ROUND_ROBIN 정책을 적용하여 트래픽 부하를 고르게 분산하도록 지정되어있음을 확인할 수 있습니다.

 


 

2-4-2 Dynamic 등록 방식

 

Static 등록 방식은 Config 파일에 직접 기술하여 해당 정보를 토대로 envoy proxy를 구성하는 방법입니다. 하지만 Listener, Endpoint와 Cluster 정보가 수시로 바뀌는 상황에서는 Static 등록 방식을 사용하기에 적합하지 않습니다. 그 이유는 변경할 때마다 해당 Config 파일 수정이 필요하며, envoy proxy 또한 reload 해야하기 때문입니다.

 

따라서 envoy proxy에서는 Static 등록 방식 이외에 Dynamic 방식을 제공하여 envoy proxy 기동 중에도 내부 컴포넌트 설정을 변경할 수 있도록 인터페이스를 제공하였습니다. 이를 xDS API라고 부르며, FIle 동기화, REST 혹은 gRPC  방식이 존재합니다. 참고로 아직 살펴보지는 않았지만 istio에서는 gRPC 통신을 이용하여 envoy proxy의 정보를 동적으로 변경합니다.

 

그렇다면 xDS는 어떠한 종류가 있으며, 어떤 컴포넌트와 매칭되어 변경을 수행할 수 있을까요? 이에 대해서 간단히 알아보도록 하겠습니다.

 

 

 

이전에 살펴봤던 주요 컴포넌트 Listener, Cluster, Endpoint를 갱신할 수 있는 Discovery Service가 제공됩니다. 따라서 envoy proxy에서 요구하는 spec에 맞게 gRPC 혹은 REST 호출을 보내면 개별 컴포넌트에 해당하는 Discovery Service를 통해서 내부 컴포넌트 설정을 변경할 수 있습니다. 

 

 

 

참고로 istio에서는 위와 같이 중앙에 envoy를 관리하는 Management Server가 있으며, Envoy의 xDS를 통해서 중앙에서 Configuration을 등록과 수정등을 자유롭게 할 수 있습니다.

 

위와 같은 Discovery Service외에도 VHDS, SRDS, LDS, SDS, RTDS, ECDS등 다양한 Discovery Service가 존재하며, 이는 envoy 공식 문서를 통해서 참고하시기 바랍니다.

 


 

ADS

 

이번에는 xDS 관련하여 또 하나 살펴볼 주요 내용 중 하나인 ADS(Aggregated xDS)에 대해서 살펴보겠습니다. 먼저 ADS는 무엇이고 왜 사용할까요?

 

Envoy 내부 동작 구조에 대해서 자세히 살펴보지 않았지만, 우선 가볍게 짚고 넘어가자면 Envoy 내부의 쓰레딩 모델은 기본적으로 Lock 없이 데이터를 주고 받으며, 데이터 동기화는 Eventually Consistency를 전제로 설계되어있습니다. 즉 이말은 데이터를 전달한다고 해서 바로 반영하는 것은 아니고 완벽한 동기화가 일시에 이루어지지 않음을 의미합니다.

 

그리고 이러한 구조는 다음과 같은 상황을 맞이할 수 있습니다.

 

 

 

이전에 살펴봤듯이 Endpoint와 Cluster는 의존 관계를 맺고 있음을 확인했습니다. 즉 Cluster는 Endpoint의 논리적 집합이었음을 이전 내용을 통해 확인했습니다.

 

그리고 이러한 상황에서 만약 위와 같이 Endpoint와 Cluster가 추가되어서 이를 갱신하는 상황이 발생한다고 가정했을 때, EDS를 통한 갱신이 CDS보다 먼저 이루어진다면 어떻게 될까요?

 

Envoy 입장에서는 EDS를 통해서 전달된 Endpoint의 대상이 Cluster-A라고 전달받았지만, 아직 CDS를 통해 Cluster 정보를 전달받지 못한 상황이므로 일정 기간 동안에는 Cluster 정보에 대한 동기화가 진행되지 않는 이상현상이 발생됩니다. 

 

따라서 이러한 이슈를 해결하고자 등장한 것이 Aggregated Discovery Service입니다.

 

 

ADS는 Single gRPC 스트림으로 구성된 서비스로써 envoy에 전달되는 resource의 순서를 적용하려는 사용자를 위해 집계된 xDS를 단일 gRPC 스트림으로 전달할 수 있습니다. 따라서 위의 경우 ADS와 CDS의 의존 관계에 있을 때에도 이를 집계한 결과를 단일 스트림 형태로 envoy 전달하기 때문에 일관성을 달성할 수 있는 특징을 지니고 있습니다.

 

  "dynamic_resources": {
    "lds_config": {
      "ads": {},
      "initial_fetch_timeout": "0s",
      "resource_api_version": "V3"
    },
    "cds_config": {
      "ads": {},
      "initial_fetch_timeout": "0s",
      "resource_api_version": "V3"
    },
    "ads_config": {
      "api_type": "GRPC",
      "set_node_on_first_message_only": true,
      "transport_api_version": "V3",
      "grpc_services": [
        {
          "envoy_grpc": {
            "cluster_name": "xds-grpc"
          }
        }
      ]
    }
  },

 

dynamic_resources는 위와 같이 기존 Config yaml에 위와 같이 설정할 수 있습니다. 예를들어 위와 같이 설정을 지정할 수 있습니다. 내용을 살펴보면 lds와 cds는 ads를 통해서 해당 내용을 전달받을 수 있으며, ads는 xds-grpc 클러스터를 통해서 해당 정보를 가져오도록 지정되어 있습니다.

 

참고로 위 설정은 istio를 통해 배포된 Pod에 속한 envoy proxy의 설정 파일 중 일부를 발췌한 내용이며, 해당 설정에 대한 자세한 내역은 차후 포스팅을 통해 다루어보겠습니다.

 


3. xDS API 

 

xDS API는 istio와 연계하여 Service Discovery를 수행하는데 있어 주요하게 사용됩니다. 따라서 xDS API의 종류와 동작 방법에 대해서 보다 자세히 살펴보고자 합니다.

 

먼저 xDS 지원 방식 부터 살펴보겠습니다. xDS 지원 방식은 총 3가지(File 동기화, HTTP, gRPC)입니다. 

 

 

File 동기화 방식은 위와 같이 envoy에서 File의 상태를 관찰하고 설정이 적용된 File에서 변경이 일어났을 경우 envoy에서 이를 인지하여 내부 컴포넌트의 설정을 동기화하는 방식입니다. 

 

 

반면 gRPC와 HTTP 방식은 config 정보를 전달하는 Management Server가 중앙에 존재합니다. 따라서 envoy에서는 Management Server에 요청하여 config 정보를 전달받고 전달받은 정보를 토대로 자신의 내부 컴포넌트 설정을 동기화합니다.

 

HTTP 방식은 주기적인 polling을 통해서 Management Server로부터 변경된 데이터 항목을 전달받아 갱신합니다. 반면 gRPC는 bidirectional streaming 통신을 통해 데이터를 주고 받는 차이점이 존재합니다. 해당 통신 방법에 대해서 궁금하신 분은 제 블로그 아래 내용을 참고 부탁드립니다.

 

https://cla9.tistory.com/177?category=993774 

 

3. gRPC는 왜 빠를까? (통신 방식) - 2

서론 지난 포스팅에서는 gRPC에서 사용되는 protobuf와 REST 통신에서 사용되는 JSON 크기와 Serialization/Deserialization 관점에서 성능을 비교해봤습니다. 이번에는 gRPC에서 제공하는 통신 방법에 대해서

cla9.tistory.com

 

envoy에서 널리 사용하는 방식은 gRPC 방식이며, istio 또한 gRPC 방식을 통해 xDS 정보를 전달받습니다. 따라서 본 포스팅에서는 gRPC 방식에 보다 초점을 맞추어 살펴보겠습니다.

 


 

3-1 xDS gRPC 

 

 

 

앞서 envoy에서 gRPC를 활용한 xDS 방식은 envoy와 config를 전달하는 Management Server 사이에 bidirectional streaming 통신을 사용한다고 설명했습니다. 따라서 해당 방식은 Connection이 끊기지 않고 지속 연결된 상태라고 봐도 무방합니다.

 

이러한 상황에서 처음 Management Server에 envoy가 연결되면, 위와 같이 Discovery Request를 Management Server에 전달합니다. 그러면 Management Server에서는 envoy가 요청하는 Config에 대해서 전체 목록을 전달하게되고, envoy는 해당 설정을 전달받아 Config 업데이트를 수행합니다.

 

 

 

이후 Config 업데이트가 완료되면, envoy는 이전에 Management Server로부터 전달받은 Config 항목에 대한 응답을 전달합니다. 만약 Config 내용을 정상적으로 업데이트를 수행했을 경우에는 ACK를 응답하고 그렇지 않을 경우에는 NACK를 응답합니다. (※  ACK와 NACK의 구조와 동작방식에 대해서는 envoy 공식 문서에서 자세히 다루고 있으니 참고바랍니다.)

 

이때 응답 메시지는 별개의 포맷을 활용하지 않고 다음 Discovery Request를 전달할 때, 응답을 포함하여 전달됩니다. 해당 Discovery Request 메시지는 Config 업데이트 완료 이후 Management Server에 Config가 변경되었을 때, 동기화된 Config 내역을 다시 전달받기 위해 요청하는 메시지입니다. 따라서 Management Server에 Config가 변경되거나 새로운 Resource가 추가되었을 경우 envoy에게 Discovery Response를 전달함으로써 동기화 작업이 이루어집니다.

 


 

3-2 SotW(State of the world), Delta xDS

 

 

지금까지 envoy gRPC 동작 과정에 대해서 가볍게 살펴봤는데, 이번에는 Management Server에서 Discovery Response를 응답 메시지를 전달하는데 있어서 선택할 수 있는 2가지 방법에 대해서 살펴보겠습니다.

 

첫 번째 방법은 SotW(State of the world) 방식입니다.

 

 

가령 envoy가 Cluster 정보를 동기화 하기 위해 xDS로 연결되었으며 이미 한차례 Cluster 동기화되었다고 가정해봅시다. 이때 SotW 방식은 동기화된 Cluster 정보 중 하나가 변경되었을 경우에 전체 Cluster 정보를 전달하는 방식을 의미합니다. 해당 방식은 구현이 간단한 반면에 전체 데이터 중 일부만 변경되었음에도 불구하고 전체 정보를 전달하기 때문에 많은 Network overhead가 발생할 수 있습니다.

 

 

참고로 이때 DiscoveryResponse 응답 포맷은 위와같으며, 여기서 resources를 통해서 전체 resource 정보가 전달됩니다.

 

 

두 번째 방법은 Delta 방식입니다.

 

 

해당 방식은 변경된 Config 정보만을 선별하여 전체를 전달하는 것이 아니라 변경분 (Delta 혹은 incremental)만 전달하는 방식을 의미합니다. 

 

 

이때 Delta Discovery Response 응답 포맷은 위와 같으며, resources 항목은 변경된 항목만 추가됩니다. 또한 기존에 존재하는 Resource가 삭제되었을 경우에는 removed_resources를 통해서 이를 envoy에게 전달합니다.

 

지금까지 SotW, Delta 두 가지 방식에 대해서 살펴봤습니다. 그렇다면 두 방식은 어떻게 지정할 수 있을까요?

 

 

위 설정과 같이 envoy configuration에서 api_type을 지정할 때, GRPC로 지정 혹은 DELTA_GRPC로 지정하면 입력 값에 따라서 동작 방식이 결정됩니다.

 

 

 

지금까지 gRPC 방식에서 Config 정보를 전달하는 두 가지 방법에 대해서 살펴봤습니다. 그렇다면 istio에서는 어떤 방식을 기본적으로 사용할까요? istio에서는 기본적으로는 SotW 방식을 사용하고 있으며, 사이드카 컨테이너를 주입할 때 사용자가 지정한 ISTIO_DELTA_XDS 값을 통해서 Delta 방식으로 변경할 수 있습니다. 하지만 현재는 값을 변경한다고 할지라도 실제 데이터를 전달할 때 Delta 값만을 전달하지 않습니다. 

 


 

4. 마무리

 

지금까지 Envoy 내부 주요 컴포넌트 및 설정 방식에 대해 살펴봤습니다. istio는 envoy를 얼만큼 잘 이해하고 있느냐에 따라서 istio에 대한 전문성을 확보한다고 생각합니다. 또한 istio가 문제가 생겼을 때 트러블 슈팅할 때는 envoy 설정에 대한 이해를 기반으로 진행되어야합니다. 따라서 이번 포스팅의 내용은 간략하지만 중요한 부분을 다루고 있습니다.

 

다음 포스팅에서는 Envoy 내부 구조에 대해서 조금 더 자세히 알아보도록 하겠습니다.

+ Recent posts