개요
안녕하세요. 오늘은 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 된다는 것을 알 수 있었습니다.
Host 기반 라우팅
Host 기반 라우팅은 host header의 값을 보고 라우팅하는 방법입니다. 해당 방법은 다양하게 사용할 수 있는데 아래의 응용이 일반적입니다.
- 멀티 테넌시 시스템
- 하나의 서버에서 고객사마다 다른 도메인을 사용하도록 구성할 때 쓸 수 있습니다.
user1.myservice.com
→tenant_service_user1
user2.myservice.com
→tenant_service_user2
- 고객사마다 분리된 백엔드 서버를 두고 envoy가 라우팅 할 수 있습니다.
- 하나의 서버에서 고객사마다 다른 도메인을 사용하도록 구성할 때 쓸 수 있습니다.
- 하나의 API Gateway로 여러 서비스 연결
- 여러 독립적인 서비스를 하나의 Gateway에서 도메인별로 분기
auth.example.com
→ 인증 서비스shop.example.com
→ 쇼핑몰 서비스admin.example.com
→ 관리자 서비스
- 여러 독립적인 서비스를 하나의 Gateway에서 도메인별로 분기
- 프론트엔드/백엔드 분리된 웹앱
- FE, BE 각각의 도메인을 따로 두고 프록시 처리
www.example.com
→ 프론트엔드 (React, Vue)api.example.com
→ 백엔드 (REST API)
- FE, BE 각각의 도메인을 따로 두고 프록시 처리
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를 이를 기반으로 만들어 특정 유저에게만 노출하는 등의 작업이 가능하게 됩니다.
- 새 기능을 소수 사용자에게만 테스트해보고 싶을 때
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
'기타 > 기타' 카테고리의 다른 글
[proxy] Envoy 이해하기 - 실습 (Listener, Cluster, Route, Filter의 개념) (0) | 2025.04.05 |
---|---|
[proxy] Envoy 이해하기 - 기본 이론편 (1) | 2025.03.28 |
[기타] String으로 정렬하기 - 기본적인 룰, 시간, ULID (0) | 2025.02.26 |
[기타] 날짜와 시간 표현의 국제 표준인 ISO 8601에 대해서 자세히 알아보자. (RFC3339, ISO8601, JavaTime) (0) | 2024.07.02 |
ChatGPT 알아보기 - Token (0) | 2023.06.04 |
댓글