본문 바로가기
기타/기타

[proxy] Envoy 이해하기 - Routing

by 사바라다 2025. 4. 8.
반응형

개요

안녕하세요. 오늘은 Envoy의 3번째 시간입니다. 이번시간에는 Envoy에서 사용할 수 있는 다양한 Routing 방법에 대해서 실습해보는 시간을 가져보도록 하겠습니다. 예제는 실전에서 주로 사용하는 예제를 기준으로 가져왔습니다.

Path 기반 라우팅

가장 먼저 Path 기반의 라우팅을 살펴보도록 하겠습니다. Path 기반의 라우팅은 Backend Cluster를 N개 등록하고 path에 따라서 라우팅되는 Cluster를 다르게 가져가는 방법입니다. 해당 방법을 통해서 apigateway 처럼 사용하 수 있습니다. 이 방법을 통해 리버스 라우팅을 할 수 있게됩니다. 각 서비스마다 path를 다르게 가져가는 방법입니다.

테스트

➜  02-routing-proxy curl -X GET http://localhost:10000/v1 -i

HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 19
etag: W/"13-fPIWo1EVMLABSBGW9/pl2LXKw10"
date: Sun, 06 Apr 2025 14:50:31 GMT
x-envoy-upstream-service-time: 2
server: envoy
➜  02-routing-proxy curl -X GET http://localhost:10000/v2 -i
HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 21
etag: W/"15-Nn1XsUyKc4jVtphLkGFDAggLjgA"
date: Sun, 06 Apr 2025 14:50:33 GMT
x-envoy-upstream-service-time: 12
server: envoy

Hello from backend-2!%

설정

docker-compose.yaml

  backend:
    build: ./backend
    ports:
      - "8080:8080"

  backend-2:
    build: ./backend-2
    ports:
      - "8081:8080"```


envoy.yaml
```yaml
route_config:
    name: local_route
    virtual_hosts:
    - name: backend_service
      domains: ["*"]
      routes:
      - match: { prefix: "/v1" }
        route: { cluster: backend }
      - match: { prefix: "/v2" }
        route: { cluster: backend-2 }

clusters:
  - name: backend
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    load_assignment:
      cluster_name: backend
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: backend
                port_value: 8080
  - name: backend-2
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    load_assignment:
      cluster_name: backend-2
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: backend-2
                port_value: 8080

가중치 기반 트래픽 분산 (Weighted Routing)

실서버 배포를 할 때 신규 Cluster에 100%의 트래픽을 바로 넘기면 장애가 있는 코드였다면 영향도가 전체 유저에게 영향을 가게 되고 이것은 유저 경험적으로 안좋은 영향을 끼칩니다. 따라서 안정적인 배포를 위해서 Canary 등을 이용해서 일부의 트래픽만 먼저 받아보곤 합니다.

이때 사용할 수 있는 것이 Weighted Routing 입니다. envoy는 각 cluster에 weight를 줌으로써 일부의 트래픽만 라우팅할 수 있습니다.

envoy.yaml

route_config:
    name: local_route
    virtual_hosts:
    - name: backend_service
      domains: ["*"]
      routes:
      - match: { prefix: "/v1" }
        route: 
          weighted_clusters: 
            clusters: 
              - name: backend
                weight: 80
              - name: backend-2
                weight: 20

아래는 k6를 통해서 부하 테스트를 진행해보았고 정상적으로 약 20%의 요청이 backend_2로 redirection 된다는 것을 알 수 있었습니다.

k6 stress test result

Host 기반 라우팅

Host 기반 라우팅은 host header의 값을 보고 라우팅하는 방법입니다. 해당 방법은 다양하게 사용할 수 있는데 아래의 응용이 일반적입니다.

  1. 멀티 테넌시 시스템
    • 하나의 서버에서 고객사마다 다른 도메인을 사용하도록 구성할 때 쓸 수 있습니다.
      • user1.myservice.comtenant_service_user1
      • user2.myservice.comtenant_service_user2
    • 고객사마다 분리된 백엔드 서버를 두고 envoy가 라우팅 할 수 있습니다.
  2. 하나의 API Gateway로 여러 서비스 연결
    • 여러 독립적인 서비스를 하나의 Gateway에서 도메인별로 분기
      • auth.example.com → 인증 서비스
      • shop.example.com → 쇼핑몰 서비스
      • admin.example.com → 관리자 서비스
  3. 프론트엔드/백엔드 분리된 웹앱
    1. FE, BE 각각의 도메인을 따로 두고 프록시 처리
      • www.example.com → 프론트엔드 (React, Vue)
      • api.example.com → 백엔드 (REST API)

envoy.yaml

route_config:
    name: local_route
    virtual_hosts:
      - name: service_a
        domains: ["a.example.com"]
        routes:
          - match: { prefix: "/" }
            route: { cluster: backend }

      - name: service_b
        domains: ["b.example.com"]
        routes:
          - match: { prefix: "/" }
            route: { cluster: backend-2 }

 

Header 기반 라우팅

추가로 envoy를 사용하면 Header 기반의 라우팅을 사용할 수 있습니다. Header 기반의 라우팅은 특정 Header가 있거나 없다면 특별한 서버로 라우팅하는 방식의 라우팅이 가능합니다. 이를 이용하면 A/B Test를 이를 기반으로 만들어 특정 유저에게만 노출하는 등의 작업이 가능하게 됩니다.

  1. 새 기능을 소수 사용자에게만 테스트해보고 싶을 때
    • x-user-group: beta → 베타 사용자
    • x-user-group: control → 기존 사용자
  • Envoy가 헤더를 읽고 다른 백엔드로 보내버림
route_config:
    name: local_route
    virtual_hosts:
      - name: service_a
        domains: ["*"]
        routes:
          - match:
              prefix: "/"
              headers:
                - name: "x-user-group"
                  exact_match: "beta"
            route:
              cluster: backend
          - match:
              prefix: "/"
            route:
              cluster: backend-2

 

마무리

오늘은 이렇게 Envoy에서 제공해주는 다양한 Routing에 대해서 알아보는 시간을 가져보았습니다.

다음시간에는 xDS API를 사용해서 hot reload를 테스트 해보도록 하겠습니다.

감사합니다.

참조

[1] https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_routing

반응형

댓글