Envoy 내부 구조 · 이름 뒤에 서 있는 것들 · 이론
503 은 라우트가 아니라 클러스터의 말이다
한 줄 요약
라우트는 클러스터 이름까지만 말한다. 그 이름 뒤에 주소가 몇 개 서 있는지, 어떻게 알아내는지, 그중 무엇이 성한지, 성한 것이 모자라면 어떻게 할지는 전부 클러스터가 정한다.
왜 이게 필요했나
"라우트는 맞는데 503 이 납니다" 라는 신고는 라우팅 문제가 아니다. 라우트가 가리킨 클러스터에 보낼 만한 곳이 없다는 뜻이다. 그래서 프록시를 운영할 때 실제로 자주 보는 화면은 라우트 표가 아니라 클러스터 목록이다 — 어느 클러스터에 서버가 몇 대이고, 그중 몇 대가 성한가.
여기서 두 가지를 구분해야 한다. 엔드포인트를 알아내는 방법과 그중 무엇이 성한지 판단하는 방법은 서로 다른 축이다. 앞의 것은 클러스터의 type 이고, 뒤의 것은 헬스 체크다. 둘을 섞어 생각하면 "DNS 에서 빠졌는데 왜 아직 보내나" 같은 질문에서 길을 잃는다.
어떻게 동작하나
엔드포인트를 알아내는 네 가지.
| type | 어떻게 | 언제 |
| --- | --- | --- |
| STATIC | 설정에 주소를 그대로 적는다 | 주소가 고정일 때 |
| STRICT_DNS | 이름을 주기적으로 해석해 응답의 주소를 전부 엔드포인트로 | 헤드리스 서비스처럼 여러 주소가 돌아올 때 |
| LOGICAL_DNS | 해석 결과 중 하나만 붙들고 간다 | 연결을 오래 유지하는 큰 상대(예: 외부 API) |
| EDS | 컨트롤 플레인이 목록을 밀어 넣는다 | 서비스 메시. 파드가 뜨고 질 때마다 갱신 |
성한지 판단하는 두 가지. 이 둘은 방향이 반대다.
- 능동 헬스 체크(
health_checks) — 실제 요청과 상관없이 주기적으로 따로 찔러 본다. 트래픽이 없는 시간에도 상태를 알고, 고장 난 서버로 첫 요청이 가지 않는다. 대신 서버마다 주기적인 부하가 하나씩 더 생기고, 프록시가 많으면 그 부하가 프록시 수만큼 곱해진다. - 이상치 감지(
outlier_detection) — 실제 요청이 연달아 실패하는 것을 보고 빼낸다. 추가 부하가 없지만, 처음 몇 요청은 반드시 희생된다.
둘은 배타적이지 않다. 함께 쓰면 "찔러 보기로 미리 거르고, 그래도 새는 것은 결과로 거른다" 가 된다. /clusters 의 health_flags 에 각각 다른 표시가 나온다 — 능동 검사 실패는 /failed_active_hc 다.
성한 것이 모자랄 때. Envoy 에는 두 가지 장치가 있다.
하나는 패닉 모드다. 성한 비율이 임계값(기본 50%) 아래로 떨어지면 건강 정보를 무시하고 전부에게 보낸다. 처음 보면 이상하지만 판단은 단순하다 — 검사 쪽이 틀렸을 가능성이 있는데 아무 데도 안 보내면 확실한 장애이고, 보내면 일부라도 살 수 있다. 일어났는지는 cluster.<이름>.lb_healthy_panic 통계로 본다. 이 숫자가 올라가고 있다면 부하 분산은 이미 의미를 잃은 상태다.
다른 하나는 우선순위다. 엔드포인트 묶음마다 priority 를 주면 평소에는 0 순위만 쓰고, 0 순위의 성한 비율이 떨어진 만큼을 1 순위가 받는다. 0 순위가 전멸하면 전부 1 순위로 간다. 다른 지역의 예비 서버를 평소에는 놀리다가 장애 때만 쓰는 구성이 이렇게 만들어진다.
현장에서 만나는 모습
"DNS 에서 뺐는데 아직도 그 서버로 갑니다." STRICT_DNS 는 주기적으로 다시 해석하지만 그 주기가 지나기 전까지는 옛 목록을 쓴다. LOGICAL_DNS 라면 더 오래 붙들고 있을 수 있다. 빼는 일과 반영되는 일 사이에 시간이 있다는 것을 전제로 작업 순서를 짜야 한다.
"헬스 체크를 켰더니 백엔드 CPU 가 올랐습니다." 프록시 스무 대가 1초마다 찌르면 서버 입장에서는 초당 스무 번의 추가 요청이다. 주기와 프록시 수를 함께 계산하고, 헬스 체크 경로는 가볍게 만든다(데이터베이스를 건드리지 않는 경로로).
패닉 모드를 오해하는 경우. "다 죽었는데 왜 계속 보내지" 라는 질문이 나온다. 통계를 보면 답이 나와 있다. 이때 고칠 것은 Envoy 가 아니라 헬스 체크의 임계값이거나 백엔드다.
공식 문서: [Service discovery](https://www.envoyproxy.io/docs/envoy/v1.38.3/intro/arch_overview/upstream/service_discovery) · [Health checking](https://www.envoyproxy.io/docs/envoy/v1.38.3/intro/arch_overview/upstream/health_checking) · [Cluster configuration](https://www.envoyproxy.io/docs/envoy/v1.38.3/api-v3/config/cluster/v3/cluster.proto)
다음 실습에서 할 것
엔드포인트 셋짜리 클러스터를 만들고, 이름으로 찾는 클러스터를 하나 더 두고, 능동 헬스 체크가 고장 난 하나를 빼내는 것을 본다. 그다음 전부 고장 난 클러스터로 패닉 모드를, 우선순위를 준 클러스터로 예비 단계 넘김을 각각 확인하고, 마지막에는 네 클러스터의 목록 표를 통계에서 뽑아 만든다.