로컬 라우팅
로컬 라우팅 (Locality-Aware Routing)
다운스트림 서비스와 같은 리전과 존에 있는 업스트림 서비스로 트래픽 전송을 우선시하도록 로컬 인식 라우팅(locality-aware routing)을 활성화하는 방법을 설명하는 문서예요.
출처: 문서
본문
이 주제는 Consul이 다운스트림 서비스와 같은 리전 및 존에 있는 업스트림 서비스로 트래픽을 보내는 것을 우선시할 수 있도록 로컬 인식 라우팅을 활성화하는 방법을 설명해요.
참고 엔터프라이즈
이 기능은 Consul Enterprise에서 사용할 수 있어요.
소개 (Introduction)
기본적으로 Consul은 클러스터의 모든 정상 업스트림 인스턴스에 트래픽을 분산해요. 인스턴스가 서로 다른 네트워크 존에 있더라도 마찬가지예요. Consul 서버 에이전트와 서비스 메시에 등록된 서비스에 대해 CSP(클라우드 서비스 제공자) 로컬리티를 지정할 수 있는데, 이는 여러 이점을 제공해요:
- Consul은 메시를 통해 트래픽을 라우팅할 때 가장 가까운 업스트림 인스턴스를 우선시해요.
- 업스트림 서비스 인스턴스가 비정상이 되면 Consul은 다운스트림 서비스와 같은 리전에 있는 인스턴스로의 페일오버를 우선시해요. Consul의 페일오버 전략에 대한 추가 정보는 페일오버(Failover)를 참고하세요.
올바르게 구현되면 로컬 업스트림으로 트래픽을 라우팅함으로써 다른 리전으로 요청을 보낼 때 발생하는 지연 시간과 전송 비용을 줄일 수 있어요.
워크플로 (Workflow)
가상 머신에 배포된 네트워크의 경우 다음 단계를 완료해 로컬 업스트림 서비스로 트래픽을 라우팅해요:
- Consul 클라이언트 에이전트에 리전과 존을 지정한다. 이렇게 하면 서비스가 등록된 Consul 에이전트에 구성된 리전과 존을 서비스가 상속받을 수 있다.
- 서비스 인스턴스의 로컬리티를 지정한다. 이 단계는 선택 사항이며, 커스텀 네트워크 토폴로지를 정의할 때나 배포 환경이 특정 서비스 인스턴스에 대해 로컬리티를 명시적으로 설정해야 할 때만 필요하다.
- 파티션 내에서 트래픽을 로컬로 라우팅하도록 서비스 메시 프록시를 구성한다.
컨테이너 오케스트레이션 플랫폼 (Container orchestration platforms)
consul-k8s 또는 consul-ecs를 사용해 Consul을 Kubernetes 또는 ECS 환경에 배포했다면, 서비스 인스턴스 로컬리티 정보는 호스트 머신에서 상속돼요. 따라서 커스텀 배포를 구현하지 않는 한 컨테이너화된 플랫폼에서 리전과 존을 지정할 필요가 없어요.
Kubernetes에서 Consul은 Kubernetes 노드의 topology.kubernetes.io/region 및 topology.kubernetes.io/zone 레이블을 사용해 서비스 인스턴스에 대한 지리 정보를 자동으로 채워요. AWS ECS에서 Consul은 AWS_REGION 환경 변수와 ECS 작업 메타데이터의 AvailabilityZone 속성을 사용해요.
요구 사항 (Requirements)
같은 존과 리전에 있는 각 외부 업스트림 인스턴스 집합이 각자의 존에 있는 다운스트림 서비스 인스턴스의 요청을 처리할 충분한 용량을 가질 때만 로컬 인식 라우팅을 활성화해야 해요. 로컬 인식 라우팅은 잘못 사용하면 서비스 용량에 부정적인 영향을 줄 수 있는 고급 기능이에요. 활성화되면 Consul은 모든 트래픽을 가장 가까운 서비스 인스턴스 집합으로 라우팅하고, 가장 가까운 집합에 정상 인스턴스가 없을 때만 페일오버해요.
Consul 에이전트의 로컬리티 지정 (Specify the locality of your Consul agents)
Consul 클라이언트의 locality 구성은 클라이언트에 등록된 모든 서비스에 적용돼요.
- Consul 클라이언트 에이전트 구성 파일에
locality블록을 구성해요.locality블록은region과zone매개변수를 포함하는 맵이에요. 매개변수는 네트워크에 정의된 리전과 존의 값과 일치해야 해요. 추가 정보는 에이전트 구성 참조의locality를 참고하세요. - 구성을 적용하려면 에이전트를 시작하거나 재시작해요. 지침은 Consul 에이전트 시작을 참고하세요.
다음 예시에서 에이전트는 AWS의 us-west-1 리전과 us-west-1a 존에서 실행되고 있어요:
locality = {
region = "us-west-1"
zone = "us-west-1a"
}
서비스 인스턴스의 로컬리티 지정 (선택 사항) (Specify the localities of your service instances)
이 단계는 대부분의 시나리오에서 선택 사항이에요. 추가 정보는 워크플로를 참고하세요.
- 다운스트림(클라이언트)과 업스트림 서비스 모두의 서비스 정의에
locality블록을 구성해요.locality블록은region과zone매개변수를 포함하는 맵이에요. 서비스용 프록시를 시작하면 Consul이 로컬리티를 프록시에 전달해 그에 따라 트래픽을 라우팅할 수 있게 해요. 매개변수는 네트워크에 정의된 리전과 존의 값과 일치해야 해요. 추가 정보는 서비스 구성 참조의locality를 참고하세요. - 서비스에 프록시도 구성되어 있는지 확인해요. 추가 정보는 서비스 메시 프록시 정의를 참고하세요.
구성을 적용하려면 서비스를 등록하거나 재등록해요. 지침은 서비스 및 헬스 체크 등록을 참고하세요.
다음 예시에서 web 서비스는 AWS의 us-west-1 리전과 us-west-1a 존에서 사용할 수 있어요:
service {
id = "web"
locality = {
region = "us-west-1"
zone = "us-west-1a"
}
connect = { sidecar_service = {} }
}
/agent/service/register API 엔드포인트를 통해 서비스를 수동으로 등록한다면 페이로드에 locality 구성을 지정할 수 있어요. 추가 정보는 API 문서의 서비스 등록(Register Service)을 참고하세요.
서비스 메시 프록시가 로컬로 트래픽을 라우팅하도록 활성화 (Enable service mesh proxies to route traffic locally)
메시의 모든 프록시에 대한 기본 라우팅 동작을 구성하고 특정 서비스에 대한 라우팅 동작을 구성할 수 있어요.
기본 라우팅 동작 구성 (Configure default routing behavior)
proxy defaults 구성 항목에서 PrioritizeByLocality 블록을 구성하고 failover 모드를 지정해요. 이 구성은 메시의 프록시가 서비스 구성에 정의된 리전과 존을 사용해 트래픽을 라우팅할 수 있게 해줘요. 구성에 대한 자세한 내용은 proxy defaults 참조의 PrioritizeByLocality를 참고하세요.
HCL — proxy-defaults.hcl
Kind = "proxy-defaults"
Name = "global"
PrioritizeByLocality = {
Mode = "failover"
}
JSON — proxy-defaults.json
{
"kind": "proxy-defaults",
"name": "global",
"prioritizeByLocality": {
"mode": "failover"
}
}
Kubernetes — proxy-defaults.yaml
apiversion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
name: global
spec:
prioritizeByLocality:
mode: failover
consul config write CLI 명령을 실행하거나, Kubernetes CRD를 적용하거나, /config HTTP API 엔드포인트를 호출해 구성을 적용해요.
Consul CLI
$ consul config write proxy-defaults.hcl
Kubernetes
$ kubectl apply -f proxy-defaults.yaml
HTTP API
$ curl --request PUT --data @proxy-defaults.hcl http://127.0.0.1:8500/v1/config
개별 서비스에 대한 라우팅 동작 구성 (Configure routing behavior for individual service)
- service resolver 구성 항목을 만들고 다음 필드를 지정해요:
Name: 다운스트림 클라이언트가 로컬 인식 라우팅을 사용해야 하는 대상 업스트림 서비스의 이름.PrioritizeByLocality: 이 블록은 메시의 프록시가 서비스 구성에 정의된 리전과 존을 사용해 트래픽을 라우팅할 수 있게 해줘요. 블록 안의mode를failover로 설정해요. 구성에 대한 자세한 내용은 service resolver 참조의PrioritizeByLocality를 참고하세요.
HCL — api-resolver.hcl
Kind = "service-resolver"
Name = "api"
PrioritizeByLocality = {
Mode = "failover"
}
JSON — api-resolver.json
{
"kind": "service-resolver",
"name": "api",
"prioritizeByLocality": {
"mode": "failover"
}
}
Kubernetes — api-resolver.yaml
apiversion: consul.hashicorp.com/v1alpha1
kind: ServiceResolver
metadata:
name: api
spec:
prioritizeByLocality:
mode: failover
consul config writeCLI 명령을 실행하거나, Kubernetes CRD를 적용하거나,/configHTTP API 엔드포인트를 호출해 구성을 적용해요.
$ consul config write api-resolver.hcl
$ kubectl apply -f api-resolver.yaml
$ curl --request PUT --data @api-resolver.hcl http://127.0.0.1:8500/v1/config
Kubernetes 테스트 클러스터에서 로컬리티를 명시적으로 구성 (Configure locality on Kubernetes test clusters explicitly)
로컬 Kubernetes 클러스터나 topology.kubernetes.io 레이블이 설정되지 않은 환경에서 로컬 인식 라우팅을 테스트할 수 있도록 각 Kubernetes 노드에 대해 로컬리티를 명시적으로 구성할 수 있어요.
kubectl label node 명령을 실행하고 인자로 로컬리티를 지정해요. 다음 예시는 노드에 us-east-1 리전과 us-east-1a 존을 지정해요:
kubectl label node $K8S_NODE topology.kubernetes.io/region="us-east-1" topology.kubernetes.io/zone="us-east-1a"
이 값을 설정한 후 클러스터의 후속 서비스 및 프록시 등록은 로컬 Kubernetes 노드에서 값을 상속해요.
경로 확인 (Verify routes)
각 다운스트림 서비스 인스턴스에서 가장 가까운 정상 업스트림 인스턴스 집합으로의 경로가 가장 즉시 관찰 가능한 라우팅 변경 사항이에요.
Consul은 Envoy의 내장 overprovisioning_factor와 이상 탐지(outlier detection) 설정을 구성해 페일오버 동작을 강제해요. 그러나 Envoy는 클러스터 내 페일오버나 엔드포인트 트래픽에 특화된 세밀한 메트릭을 제공하지 않아요. 결과적으로 환경 내 네트워크 트래픽을 노출하는 외부 관찰 도구를 사용하는 것이 경로 변경을 관찰하는 가장 좋은 방법이에요.
로컬 인식 라우팅 및 페일오버 구성을 확인하려면 다운스트림 프록시에 대한 Envoy xDS 구성 덤프를 검사할 수 있어요. Kubernetes에서 xDS 구성 덤프를 얻는 방법에 대한 자세한 내용은 consul-k8s CLI 문서를 참고하세요. 다른 워크로드의 경우 Envoy 관리 인터페이스를 사용하고 EDS 포함을 확인하세요.
EndpointsConfigDump의 업스트림 ClusterLoadAssignment 아래 각 엔드포인트 집합의 priority를 검사해요. 또는 동일한 우선순위가 /clusters?format=json 관리 엔드포인트의 출력에 표시되어야 해요.
{
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
"cluster_name": "web.default.dc1.internal.161d7b5a-bb5f-379c-7d5a-1fc7504f95da.consul",
"endpoints": [
{
"lb_endpoints": [
{
"endpoint": {
"address": {
"socket_address": {
"address": "10.42.2.6",
"port_value": 20000
}
},
"health_check_config": {}
},
...
},
...
],
"locality": {}
},
{
"lb_endpoints": [
{
"endpoint": {
"address": {
"socket_address": {
"address": "10.42.3.6",
"port_value": 20000
}
},
"health_check_config": {}
},
...
},
...
],
"locality": {},
"priority": 1
},
{
"lb_endpoints": [
{
"endpoint": {
"address": {
"socket_address": {
"address": "10.42.0.6",
"port_value": 20000
}
},
"health_check_config": {}
},
...
},
...
],
"locality": {},
"priority": 2
}
],
...
}
관찰 가능한 페일오버 강제하기 (Force an observable failover)
테스트 목적으로 페일오버를 강제하려면, 로컬 존 인스턴스가 없다면 다운스트림의 로컬 존 또는 리전에 있는 업스트림 서비스 인스턴스를 0으로 확장해요.
다음 동작에 유의하세요:
- Consul은
0에서 시작해 오름차순으로 페일오버를 우선시해요. 가장 높은 우선순위인0은 xDS 출력에서 명시적으로 보이지 않아요. 이는0이 해당 필드의 기본값이기 때문이에요. - Envoy 페일오버 구성이 마련된 후 페일오버의 구체적인 시점은 Consul이 아니라 다운스트림 Envoy 프록시에 의해 결정돼요. Consul 헬스 상태가 Envoy의 페일오버 동작(이상 탐지에도 의존)과 직접적으로 일치하지 않을 수 있어요.
예상한 동작이 보이지 않으면 문제 해결(Troubleshooting)을 참고하세요.
로드 밸런싱 및 페일오버 동작 조정 (Adjust load balancing and failover behavior)
property override Envoy 확장을 적용해 전역 또는 서비스별 로드 밸런싱 및 페일오버 동작을 조정할 수 있어요. property override 확장은 Consul이 생성하는 Envoy 리소스의 개별 속성을 설정하고 제거할 수 있게 해줘요. 추가 정보는 Envoy 프록시 속성 구성을 참고하세요.
- service defaults 또는 proxy defaults 구성 항목에
EnvoyExtensions구성 블록을 추가해요. EnvoyExtensions구성에서 다음 설정을 구성해요:- 구성을 적용해요. 자세한 내용은 구성 항목 적용을 참고하세요.
기본적으로 Consul은 overprovisioning_factor를 100000으로 설정해 전체 페일오버를 강제하고, max_ejection_percent를 100으로 설정해요. 이 필드를 수정하기 전에 Envoy 문서를 참고하세요.
문제 해결 (Troubleshooting)
예상한 우선순위가 보이지 않으면 Consul 에이전트에 로컬리티가 구성되어 있는지, proxy defaults 또는 service resolver 구성 항목에서 PrioritizeByLocality가 활성화되어 있는지 확인해요. PrioritizeByLocality가 활성화되어 있지만 로컬 프록시에 로컬리티 구성이 없으면 Consul은 정책을 적용할 수 없음을 알리는 경고 로그를 출력해요:
`no local service locality provided, skipping locality failover policy`