저는 직장에서 비정상적으로 작동하는 데이터베이스와 통신하는 서비스와 관련된 일련의 사고가 발생했을 때 완벽한 로드 밸런서를 찾는 데 관심을 갖게 되었습니다. 처음에는 데이터베이스의 안정성을 높이는 데 중점을 두었지만, 데이터베이스의 여러 읽기 엔드포인트 간에 요청을 보다 효과적으로 로드 밸런싱할 수 있었다면 서비스에 미치는 영향을 크게 줄일 수 있었을 것이라는 점이 분명해졌습니다.
최신 기술을 살펴볼수록 이 문제가 해결된 문제와는 거리가 멀다는 사실에 더욱 놀랐습니다. 로드 밸런서는 많지만 대부분 한두 가지 장애 모드에만 작동하는 알고리즘을 사용하며, 이번 사고에서는 다양한 장애 모드가 발생했습니다.
이 글에서는 고가용성을 위한 로드 밸런싱의 현재 상태, 가장 일반적인 도구의 문제 역학에 대한 이해, 그리고 앞으로 나아가야 할 방향에 대해 제가 배운 것을 설명합니다.
(면책 조항: 이 내용은 주로 사고 실험과 일상적인 관찰에 근거한 것이며, 관련 학술 문헌을 찾는 데 큰 행운을 얻지 못했습니다. 비평을 환영합니다!)
TL;DR
이 글에서 꼭 기억해 주셨으면 하는 점입니다:
- 서버 상태는 클러스터 상태의 맥락에서만 이해할 수 있습니다.
- 활성 상태 확인을 사용하여 서버를 내보내는 로드밸런서는 상태 확인이 실제 트래픽 상태를 대표하지 못할 때 불필요하게 트래픽을 잃을 수 있습니다.
- 실제 트래픽을 수동적으로 모니터링하여 지연 시간 및 장애율 지표를 공평한 부하 분산에 활용할 수 있습니다.
- 서버 상태의 작은 차이로 인해 부하 분산에 큰 차이가 발생하면 시스템이 예측할 수 없을 정도로 심하게 진동할 수 있습니다.
- 무작위성을 통해 몰링 및 기타 원치 않는 상호 연관 행동을 억제할 수 있습니다.
파운데이션
용어에 대한 간단한 참고 사항입니다: 이 글에서는 '연결', '노드' 등에 대한 언급 없이 서버와 대화하는 클라이언트를 언급하겠습니다. 특정 소프트웨어는 동시에 또는 동일한 요청 흐름에서 클라이언트와 서버의 역할을 동시에 수행할 수 있지만, 제가 설명한 시나리오에서는 앱 서버가 데이터베이스 서버의 클라이언트이므로 이 클라이언트-서버 관계에 초점을 맞출 것입니다.
따라서 일반적인 경우 N개의 클라이언트가 M개의 서버와 통신합니다:

또한 요청의 구체적인 내용은 무시하겠습니다. 간단히 설명하기 위해 클라이언트의 요청은 선택 사항이 아니며 폴백이 불가능하고 호출이 실패하면 클라이언트는 서비스 저하를 경험한다고 가정하겠습니다.
그렇다면 가장 큰 문제는 다음과 같습니다: 클라이언트가 요청을 받으면 호출할 서버를 어떻게 선택해야 할까요?
(꾸준한 스트림, 트래픽 폭주 또는 다양한 간격으로 요청을 전송할 수 있는 수명이 긴 연결이 아니라 요청을 살펴보고 있다는 점에 유의하세요. 또한 요청당 연결이 이루어졌는지 또는 연결을 재사용하는지 여부는 전체적인 결론에 특별히 중요하지 않습니다).
왜 모든 클라이언트가 모든 서버와 통신하게 하는지 궁금하실 텐데요, 이를 일반적으로 "클라이언트 측 로드 밸런싱"이라고 합니다(이 글의 용어에서는 로드 밸런서를 클라이언트라고도 부릅니다). 왜 클라이언트가 이 작업을 수행하게 할까요? 모든 서버를 전용 로드 밸런서 뒤에 배치하는 것은 매우 일반적입니다.

문제는 전용 로드 밸런서 노드가 하나만 있으면 단일 장애 지점이 발생한다는 것입니다. 그렇기 때문에 이러한 노드를 세 개 이상 두는 것이 일반적이었습니다. 하지만 이제 클라이언트는 어느 로드 밸런서와 통신할지 선택해야 하고, 각 로드 밸런서 노드는 여전히 각 요청을 전송할 서버를 선택해야 합니다! 이렇게 하면 문제가 해결되는 것이 아니라 문제가 두 배가 됩니다. ("이제 두 가지 문제가 생겼습니다.")
전용 로드 밸런서가 나쁘다는 말은 아닙니다. 어떤 로드 밸런서에 연결할 것인지에 대한 문제는 일반적으로 DNS 로드 밸런싱으로 해결되며, 라우팅, 로깅, 메트릭 등을 위해 보다 중앙 집중화된 지점을 사용하는 것에 대해 많은 장점이 있습니다. 하지만 여전히 특정 장애 모드의 희생양이 될 수 있고 일반적으로 클라이언트 측 부하 분산보다 유연성이 떨어지기 때문에 문제를 우회할 수는 없습니다.
가치
그렇다면 로드 밸런서에서 중요하게 생각하는 것은 무엇일까요? 무엇을 최적화하고 있을까요?
필요에 따라 어느 정도 순서대로 진행됩니다:
- 서버 또는 네트워크 장애가 전체 서비스 가용성에 미치는 영향 감소
- 서비스 지연 시간을 낮게 유지
- 서버 간에 부하를 고르게 분산
- 다른 서버에 여유 용량이 있는 경우 서버에 과도한 스트레스를 주지 마세요.
- 예측 가능성: 서비스의 여유 공간을 쉽게 확인할 수 있습니다.
- 부하 분산 고르지 않게 서버의 용량이 시간 또는 서버별로 다를 수 있는 경우(균등 분배가 아닌 공평한 분배)
- 서버 시작 직후 갑자기 트래픽이 급증하거나 대량의 트래픽이 발생하면 서버가 예열할 시간이 부족할 수 있습니다. 동일한 트래픽 수준까지 점진적으로 증가해도 괜찮을 수 있습니다.
- 업데이트 설치와 같은 비서비스 CPU 로드는 단일 서버에서 사용 가능한 CPU의 양을 줄일 수 있습니다.
순진한 솔루션
모든 것을 해결하기 전에 몇 가지 간단한 해결책을 살펴봅시다. 모든 것이 정상일 때 요청을 균등하게 분배하려면 어떻게 해야 할까요?
- 라운드 로빈
- 무작위 선택
- 상태를 추적하지 않고 통계적으로 균등 분포에 접근합니다(조정/CPU 트레이드오프).
- 정적 선택
- 각 클라이언트는 모든 요청에 대해 하나의 서버를 선택하기만 하면 됩니다.
- DNS 부하 분산은 이를 효과적으로 수행합니다: 클라이언트가 서비스의 도메인 이름을 하나 이상의 주소로 확인하면 클라이언트의 네트워크 스택이 그 중 하나를 선택하여 캐시합니다. 대부분의 전용 부하 분산 장치에서 수신 트래픽이 이렇게 분산되므로 클라이언트는 서버가 여러 개 있다는 사실을 알 필요가 없습니다.
- 랜덤과 비슷하며 1) DNS TTL이 존중되고 2) 클라이언트 수가 서버보다 훨씬 많을 때(요청 속도가 비슷할 때) 정상적으로 작동합니다.
이러한 구성에서 서버 중 하나가 다운되면 어떻게 될까요? 서버가 3개라면 요청 3건 중 1건은 실패합니다. 67%의 성공률은 꽤나 나쁜 수치입니다. (심지어 "9"도 아닙니다!) 이 시나리오에서 완벽한 로드 밸런서와 나머지 두 서버의 용량이 충분하다고 가정할 때 가능한 최상의 성공률은 100%입니다. 어떻게 하면 거기에 도달할 수 있을까요?

건강 정의
일반적인 해결책은 상태 확인입니다. 상태 확인을 통해 로드밸런서는 특정 서버 또는 네트워크 장애를 감지하고 확인에 실패한 서버에 요청을 보내지 않도록 할 수 있습니다.
일반적으로 각 서버가 얼마나 '정상'인지를 알고자 하는 이유는 핵심 질문에 답하는 데 예측 가치가 있을 수 있기 때문입니다: "이 서버에 이 요청을 보내면 나쁜 응답을 보낼 가능성이 있는가?"라는 질문에 대한 예측 가치가 있기 때문입니다. 더 높은 수준의 질문도 있습니다: "이 서버에 트래픽을 더 많이 보내면 서버가 비정상 상태가 될 가능성이 있는가?"라는 더 높은 수준의 질문도 있습니다. (또는 덜 보내면 정상으로 돌아올까요?) 이를 다른 말로 표현하면, 비정상적인 경우는 부하에 따라 달라질 수 있는 반면 부하와 무관한 경우도 있으므로 비정상적인 상태가 관찰될 때 트래픽 라우팅 방법을 예측하려면 그 차이를 아는 것이 필수적입니다.
넓게 보면 '건강'은 예측을 위해 외부 상태를 모델링하는 방식이라고 할 수 있습니다. 그렇다면 무엇이 건강하지 않은 상태일까요? 그리고 이를 어떻게 측정할 수 있을까요?
유리한 지점 선택하기
자세히 알아보기 전에 우리가 사용할 수 있는 매우 다른 두 가지 관점이 있다는 점을 알아두는 것이 중요합니다:
- 서버의 내재적 상태: 서버 애플리케이션이 실행 중이고, 응답하고, 모든 자체 종속성과 대화할 수 있으며, 심각한 리소스 경합 상태에 있지 않은지 여부입니다.
- 클라이언트가 관찰한 서버의 상태: 서버의 상태뿐만 아니라 서버 호스트의 상태, 개입하는 네트워크의 상태, 심지어 클라이언트가 서버에 유효한 주소로 구성되어 있는지 여부까지 포함합니다.
실용적인 관점에서 볼 때, 클라이언트가 서버에 접속할 수 없다면 서버의 내재적 상태는 중요하지 않습니다. 따라서 대부분 클라이언트에서 관찰되는 서버 상태를 살펴볼 것입니다. 하지만 여기에는 약간의 미묘한 차이가 있습니다: 서버에 대한 요청 속도가 증가하면 네트워크나 호스트가 아니라 서버 애플리케이션이 병목 현상이 발생할 가능성이 높습니다. 서버에서 지연 시간이나 장애율이 증가하기 시작하면 서버가 요청 부하로 인해 어려움을 겪고 있다는 의미이며, 추가적인 요청 부담으로 인해 서버의 상태가 악화될 수 있음을 의미합니다. 또는 서버의 용량이 충분하고 클라이언트가 최적이 아닌 라우팅으로 인해 일시적이고 부하와 무관한 네트워크 문제만 관찰하고 있는 것일 수도 있습니다. 이 경우 트래픽 부하를 추가해도 상황이 바뀌지 않을 가능성이 높습니다. 일반적인 경우 이러한 경우를 구분하기 어려울 수 있으므로 일반적으로 클라이언트의 관찰 내용을 상태의 기준으로 사용합니다.
건강의 척도는 무엇인가요?
그렇다면 클라이언트는 호출을 통해 서버의 상태에 대해 무엇을 알 수 있을까요?
- 지연 시간: 응답이 돌아오는 데 얼마나 걸리나요? 이는 더 세분화할 수 있습니다: 연결 설정 시간, 응답의 첫 바이트까지의 시간, 응답 완료까지의 시간, 최소, 평균, 최대, 다양한 백분위수. 이는 네트워크 상태와 서버 부하 독립적 및 부하 종속적 소스를 각각 통합한 것입니다(대부분의 경우).
- 실패율: 요청 중 실패로 끝나는 비율은 몇 퍼센트인가요? (실패의 의미에 대해서는 잠시 후에 자세히 설명합니다.)
- 동시성: 현재 얼마나 많은 요청이 전송 중인가요? 서버가 백업되었거나 클라이언트가 어떤 이유로 서버에 더 많은 요청을 보내기로 결정했기 때문에 서버와 클라이언트 동작의 영향을 합쳐서 한 서버에 더 많은 인플라이트 요청이 있을 수 있습니다.
- 대기열 크기: 클라이언트가 통합 대기열이 아닌 서버별로 대기열을 유지하는 경우 대기열이 길어지면 상태가 좋지 않거나 클라이언트의 로딩이 불균등하다는 것을 나타낼 수 있습니다.
대기열 크기와 동시 요청 수를 통해 모든 측정값이 그 자체로 상태를 나타내는 것은 아니지만 로딩을 나타낼 수도 있음을 알 수 있습니다. 직접 비교할 수는 없지만 클라이언트는 더 건강하고 부하가 적은 서버에 더 많은 요청을 보내기를 원할 수 있으므로 이러한 메트릭은 지연 시간 및 장애율과 같은 보다 본질적인 메트릭과 함께 사용할 수 있습니다.
이는 모두 클라이언트 관점에서 측정한 수치입니다. 서버가 자체적으로 사용률을 보고하도록 하는 것도 가능하지만 이 글에서는 크게 다루지 않습니다.
이 모든 항목은 서로 다른 시간 간격으로 측정할 수도 있습니다: 가장 최근 값, 슬라이딩 윈도우(또는 롤링 버킷), 감쇠 평균 또는 이 중 여러 가지를 조합하여 측정할 수도 있습니다.
실패 정의
이러한 상태 지표 중 가장 중요한 것은 아마도 실패율일 것입니다: 대부분의 사용 사례에서 호출자는 어떤 종류의 실패보다는 느린 성공을 원합니다. 그러나 실패에는 여러 가지 종류가 있으며 서버의 상태에 대해 서로 다른 것을 의미할 수 있습니다.
통화 시간이 초과되면 네트워크 또는 라우팅 문제로 인해 지연 시간이 길어지거나 서버에 과부하가 걸린 것일 수 있습니다. 그러나 통화가 빠르게 실패하는 경우에는 매우 다른 의미가 있습니다: DNS 구성 오류, 서버 고장, 잘못된 경로 등 매우 다양한 의미가 있습니다. 서버가 부하가 많은 상황에서 의도적으로 빠른 장애를 일으키기 위해 로드 쉐딩을 사용하는 경우가 아니라면 빠른 장애는 부하와 관련이 없을 가능성이 높습니다(이 경우 더 많은 부하로 인해 더 이상 스트레스를 받지 않을 수 있습니다).
전송 수준 장애뿐만 아니라 애플리케이션 수준 장애를 살펴볼 때는 호출을 실패로 표시하는 기준을 신중하게 선택하는 것이 중요합니다. 예를 들어, 시간 초과 등으로 인해 반환되지 않는 HTTP 호출은 명백히 실패이지만 오류 상태 코드(4xx 또는 5xx)가 포함된 잘 구성된 응답은 서버 문제를 나타내지 않을 수 있습니다. 개별 요청이 전체 서버 상태를 대표하지 않는 데이터 종속 500 서버 오류를 트리거할 수 있습니다. 잘못된 요청을 보낸 호출자로 인해 404 또는 403 응답이 폭증하는 경우가 종종 있지만 이는 해당 호출자만 영향을 받는 것이므로 이를 근거로 서버가 건강하지 않다고 판단하는 것은 현명하지 않습니다. 반면에 읽기 시간 초과가 잘못된 요청으로 인한 것일 가능성은 다소 낮습니다.
건강 검진은 어떻게 하나요?
지금까지는 주로 클라이언트가 이미 수행 중인 요청에서 서버 상태에 대한 정보를 수동적으로 수집할 수 있는 방법에 대해 이야기했습니다. 또 다른 접근 방식은 액티브 상태 확인을 사용하는 것입니다.
AWS의 Elastic Load Balancer(ELB) 상태 확인이 그 예입니다. 로드 밸런서가 30초마다 각 서버의 일부 HTTP 엔드포인트를 호출하도록 구성할 수 있으며, ELB가 5xx 응답을 받거나 2번 연속으로 타임아웃되면 정상적인 요청에 대한 고려 대상에서 해당 서버를 제외합니다. 하지만 계속 상태 확인 호출을 수행하며 서버가 10회 연속 정상 응답하면 다시 로테이션에 포함됩니다.
이것은 히스테리시스를 사용하여 호스트가 너무 쉽게 서비스를 시작하고 종료하지 않도록 하는 방법을 보여줍니다. (히스테리시스의 친숙한 예로는 에어컨의 온도 조절기가 원하는 온도 주변에서 "허용 범위"를 유지하는 방식을 들 수 있습니다.) 이는 일반적인 접근 방식이며 서버가 완전히 건강하거나 건강하지 않고 상태가 자주 바뀌지 않는 시나리오에서 합리적으로 잘 작동할 수 있습니다. 상태 확인과 정상 트래픽 모두에 영향을 미치는 약 40% 미만의 낮은 장애율이 지속적이고 덜 일반적인 상황에서는 기본 구성의 ELB는 호스트가 서비스를 중단할 정도로 연속적인 장애가 자주 발생하지 않습니다.
상태 확인은 로드 밸런서에 잘못된 영향을 미치지 않도록 신중하게 설계해야 합니다. 다음은 상태 확인 호출이 제공할 수 있는 몇 가지 응답 유형입니다:
- 연기 테스트: 실제 전화를 한 번 걸어 예상되는 응답이 돌아오는지 확인합니다.
- 기능 종속성 검사: 서버가 모든 종속성을 호출하고 그 중 하나라도 실패하면 실패를 반환합니다.
- 가용성 확인: 서버가 다음에 응답할 수 있는지 확인합니다. any 통화, 예를 들어
GET /ping
수익률 200 OK
의 응답 본문과 pong
상태 확인은 가능한 한 실제 트래픽을 대표하는 것이 중요합니다. 그렇지 않으면 허용되지 않는 오탐 또는 오탐이 발생할 수 있습니다. 예를 들어 서버에 여러 개의 API 경로가 있는데 그 중 하나의 경로만 종속성 실패로 인해 중단된 경우 해당 서버는 정상인가요? 스모크 테스트 상태 점검에서 해당 경로만 걸리면 클라이언트는 서버가 완전히 고장난 것으로 간주하고, 반대로 해당 경로만 작동하는 경우 클라이언트는 서버가 완벽하게 정상인 것으로 간주할 수 있습니다.
기능 점검은 더 포괄적일 수 있지만, 선택적 종속성 하나라도 다운되면 서버(또는 모든 서버!)가 다운된 것으로 쉽게 표시될 수 있으므로 반드시 더 나은 것은 아닙니다. 이는 운영 모니터링에는 유용하지만 부하 분산에는 위험하므로 많은 사람들이 간단한 가용성 검사만 구성합니다.
능동적 상태 확인은 일반적으로 서버가 일부 요청에는 지속적으로 응답하지만 다른 요청에는 응답하지 않는 성능 저하 상태에 있을 수 있으므로 시간이 지나면서 추적하더라도 서버의 상태에 대한 이진 보기만 제공합니다. 반면에 수동적으로 트래픽 상태를 모니터링하면 최소한 클라이언트가 요청 중 실패를 수신하는 비율을 알 수 있고, 중요한 것은 이러한 수동 모니터링을 통해 트래픽 상태에 대한 종합적인 보기를 얻을 수 있기 때문에 스칼라 (또는 훨씬 더 미묘한) 상태 보기를 제공합니다. (물론 두 가지 유형의 점검 모두 지연 시간 정보를 추적할 수 있으며, 이러한 구분은 실패율 메트릭에만 적용됩니다.)
바이너리 상태 확인 및 이상 징후 탐지
이러한 이분법적 보기는 서버 간 상태 비교를 허용하지 않기 때문에 심각한 문제를 일으킬 수 있습니다. 단순히 단일 호출 유형에 따라 '업' 또는 '다운'으로 그룹화되기 때문에 대표적이지 않을 수 있습니다. 여러 개의 상태 확인 호출이 있더라도 API가 확장되고 클라이언트 요구 사항이 변경됨에 따라 서버의 상태를 계속 대표한다고 보장할 수 없습니다. 더 심각한 문제는 상호 연관된 장애로 인해 불필요한 연쇄 장애가 발생할 수 있다는 점입니다. 다음 시나리오를 살펴보세요:
- 호스트의 100%가 활성 상태 검사를 통과한 경우, 이상적인 로드 밸런서는 모든 호스트로 라우팅해야 합니다.
- 90%가 통과하는 경우, 나머지 클러스터가 의심할 여지 없이 부하를 처리할 수 있으므로 10%가 실패하는 이유는 중요하지 않으므로 그 90%에만 라우팅하세요.
- 10%만 통과하는 경우... 모든 호스트에게라우팅 -통과하는 10%의 건강 검진에 베팅하는 것보다 건강 검진이 잘못되었거나 관련 없는 것에 베팅하는 것이 더 낫습니다.
- 0%가 통과하면 모든 호스트로 라우팅합니다. 라우팅하지 않은 요청은 100% 실패합니다.
호스트의 합격 비율이 0에 가까워질수록 호스트 외부에 문제가 있거나 상태 검사에 문제가 있을 가능성이 높아집니다. 상태 확인이 테스트 계정에 종속되어 있는데 테스트 계정이 삭제되었다고 가정해 보세요. 또는 종속성 하나가 다운되었지만 대부분의 요청은 계속 처리할 수 있습니다. 그럼에도 불구하고 모든 상태 확인이 실패하여 들어오는 요청이 완벽하게 서비스되고 있음에도 불구하고 ELB가 모든 호스트를 서비스에서 제외합니다.
여기서 분명한 것은 건강은 상대적이라는 것입니다: 모든 서버에 문제가 있어도 한 서버는 이웃 서버보다 더 건강할 수 있습니다. 부울 대신 스칼라를 사용하면 더 쉽게 알 수 있습니다.
기본적으로 로드 밸런서가 일종의 간단한 이상 징후 감지를 수행하기를 원할 것입니다. 서버의 일부가 비정상적으로 작동하는 경우 해당 서버를 제외하고 운영팀에 알림을 보내면 됩니다. 대부분 또는 전부가 이상하게 작동하는 경우? 소수의 서버에 모든 부하를 몰아넣어 상황을 악화시키지 말고, 더 심하게는 서버를 아예 사용하지 마세요.
여기서 핵심은 서버 상태를 원자 단위가 아닌 전체 클러스터를 고려하여 평가하는 것입니다. 지금까지 제가 본 것 중 가장 근접한 것은 Envoy의 로드 밸런서로, 기본적으로 50% 이상의 호스트가 상태 검사에 실패하면 모든 호스트를 계속 서비스하는 '패닉 임계값'이 있습니다. 로드 밸런서에서 상태 확인을 사용하는 경우 이러한 접근 방식을 사용하는 것이 좋습니다.
서버의 30~70%가 점검에 실패할 때 어떻게 해야 하는지에 대한 질문은 건너뛰고 넘어간 것을 보셨을 것입니다. 이 상황은 실제 장애를 나타낼 수 있으며, 부하 의존적이거나 부하 독립적일 수 있습니다. 로드 밸런서가 영리한 A/B 트래픽 부하 실험을 통해 알아내려고 해도 어떤 상황에 해당하는지 알 수 있을지 확신할 수 없습니다. 더 나쁜 것은 상대적으로 적은 수의 서버에 모든 부하를 분산시키면 해당 서버가 다운될 수 있다는 것입니다. 이러한 상황에서는 부하 분산 외에 할 수 있는 일이 많지 않으며, 그 중간 범위 내에서 해당 서버를 계속 서비스하는 설계나 서버를 제거하는 설계 중 어느 쪽을 잘못이라고 할 수 있을지 모르겠습니다(저도 이러한 프로덕션 인시던트 중 한 명이었고 당시에는 명확하지 않았기 때문입니다).
이러한 능동적 접근 방식과 수동적 접근 방식의 또 다른 차이점은 능동적 확인을 사용하면 트래픽 속도에 관계없이 서버 상태에 대한 정보가 일정한 속도로 업데이트된다는 점입니다. 이는 트래픽이 느릴 때는 장점이 될 수 있고, 트래픽이 많을 때는 단점이 될 수 있습니다. (초당 10,000건의 요청이 있는 경우 5초의 장애는 긴 시간이 될 수 있습니다.) 반면 수동 검사에서는 장애 감지 속도가 요청 속도에 비례합니다.
하지만 순수한 수동 상태 확인에는 한 가지 큰 단점이 있습니다. 서버가 다운되면 로드 밸런서가 서버를 서비스에서 빠르게 제거합니다. 이는 더 이상 트래픽이 없다는 것을 의미하며, 트래픽이 없다는 것은 서버의 상태에 대한 클라이언트의 관점이 변하지 않는다는 것을 의미합니다: 서버 상태는 영원히 0으로 유지됩니다.
물론 이를 처리하는 방법에는 클라이언트 시작 또는 클라이언트 서버 목록에서 단일 서버 교체와 같은 다른 무데이터 엣지 케이스도 처리할 수 있는 몇 가지 방법이 있습니다. 패시브 검사를 사용하는 경우 이러한 모든 문제를 특별히 해결해야 합니다.

건강 정리
위의 내용을 요약합니다:
- 수동적인 트래픽 모니터링은 능동적인 점검보다 더 포괄적이고 미묘한 상태를 파악할 수 있습니다.
- 상태를 평가할 수 있는 여러 축이 있습니다.
- 서버의 상태는 클러스터를 기준으로만 이해할 수 있습니다.
하지만 이 정보로 무엇을 할 수 있을까요? 지연 시간 단축, 장애 최소화, 고른 부하 분산이라는 목표를 달성하기 위해 이 모든 실수치를 어떻게 결합할 수 있을까요?
먼저 장애 모드 제품군을 살펴본 다음 일반적인 상태 인식 부하 분산 접근 방식에 대해 논의하고 마지막으로 몇 가지 가능한 향후 방향을 나열하고자 합니다.
조율되지 않은 행동은 놀라운 결과를 초래할 수 있습니다. 대기업 사무실에서 직원들에게 이메일을 보낸다고 상상해 보세요: "오늘 2번 강당에서 전 직원을 대상으로 마사지를 제공합니다! 언제든 오세요." 사람들이 언제 올 것 같나요? 제 생각에는 하루 중 몇 시간대에 많은 인파가 몰릴 것 같습니다:
이렇게 고르지 않은 분포로 인해 마사지 테라피스트가 일할 사람이 없을 때도 있고, 줄이 너무 길어 사람들이 포기하고 나중에 다시 시도조차 하지 않는 경우도 있습니다. 둘 다 바람직하지 않습니다. 전혀 조율되지 않은 상태에서, 즉 조율이 전혀 이루어지지 않은 상태에서 사람들은 어떻게든 그룹을 지어 나타납니다! 이 시나리오에서 우발적인 상호 연관 행동은 일반적인 도구를 사용하면 쉽게 방지할 수 있습니다: 바로 등록 시트입니다. (소프트웨어 영역에서 가장 가까운 아날로그는 작업을 수락하고 자체적으로 편리하게 일정을 잡고 결과를 비동기적으로 반환하는 일괄 처리 시스템입니다.)
API 트래픽에는 여러 가지 유사한 현상이 존재하며, 종종 ' 천둥처럼 몰려드는 문제'라는 이름으로 함께 그룹화되기도 합니다. 대표적인 예로 수백 개의 애플리케이션 노드가 참조하는 캐시 서비스를 들 수 있습니다. 캐시 항목이 만료되면 애플리케이션은 새로운 데이터로 값을 다시 만들어야 하며, 이를 위해서는 추가 작업과 함께 다른 서버에 대한 추가 네트워크 호출이 필요합니다. 수백 개의 앱 노드가 동시에 인기 있는 캐시 항목이 만료되는 것을 관찰하면(모두 이 데이터에 대한 요청을 지속적으로 받고 있기 때문에) 모두 동시에 캐시 항목을 다시 생성하려고 시도하고 동시에 새로운 데이터 생성을 담당하는 백엔드 서비스를 호출하게 됩니다. 이는 낭비적일 뿐만 아니라(가장 좋은 경우 캐시 수명 당 한 번만 앱 노드 하나만 이 작업을 수행해야 합니다.) 일반적으로 캐시 뒤에 숨어 있는 백엔드 서버가 다운될 수도 있습니다.
캐시 만료 시 발생하는 집단 문제를 해결하기 위한 고전적인 해결책은 캐시 항목을 모든 곳에서 동일한 시점에 만료하는 대신 호출자별로 확률적으로 일찍 만료하는 것입니다. 가장 간단한 접근 방식은 클라이언트가 캐시를 참조할 때마다 만료 날짜에서 작은 임의의 숫자를 뺀 지터를 추가하는 것입니다. 이 기술을 개선한 XFetch는 지터에 편향성을 부여하여 새로 고침을 가능한 마지막 순간까지 지연시킵니다.
또 다른 익숙한 문제는 많은 수의 서비스 사용자가 API를 호출하는 정기 작업을 설정할 때 발생합니다. 백업 서비스의 모든 사용자가 자정(현지 시간대 또는 UTC 기준)에 백업을 업로드하는 크론 작업을 설치하면 백업 서버는 UTC 자정에 과부하가 걸리고 낮에는 거의 사용되지 않게 됩니다.
다시 말하지만, 표준 솔루션이 있습니다: 새 사용자를 온보딩할 때 각 사용자에 대해 무작위로 선택한 시간을 사용하여 설치하도록 권장되는 크론탭 파일을 생성합니다. 백업 소프트웨어 자체에서 처음 설치할 때 임의의 시간을 선택하여 크론탭 파일을 작성하는 경우에는 중앙 조정 지점 없이도 이 방법이 작동할 수 있습니다. (어떤 이유로 중앙 등록 시트를 사용할 수 없는 경우 마사지 시나리오에서도 비슷한 접근 방식을 사용할 수 있습니다: 직원들이 각자 하루 중 한가한 시간을 무작위로 선택하고, 그 시간이 반드시 자신의 일정에 가장 적합한 시간이 아니더라도 그 시간에 방문하면 됩니다.)
이 두 가지 솔루션, 즉 지터링 만료와 무작위 스케줄링은 모두 무작위성을 조정되지 않으면서도 상호 연관된 동작에 대한 대응책으로 활용합니다. 이는 중요한 원칙입니다: 무작위성은 상관관계를 억제합니다. 로드 밸런싱과 관련된 몇 가지 문제를 해결할 때 이 원리가 다시 등장할 것입니다.
또한 마사지 시나리오를 통해 중앙 조정 지점에 의존하는 대안적인 접근 방식도 살펴볼 수 있습니다. 이는 강력한 서버로 구성된 소규모 클러스터를 전용 부하 분산 장치로 사용하는 것의 장점 중 하나로, 각 서버는 다수의 클라이언트가 각각 가지고 있는 것보다 트래픽 흐름을 더 높은 수준에서 볼 수 있습니다. 조정을 강화하는 또 다른 방법은 서버가 응답에 기생 메타데이터로 사용률을 자체 보고하도록 하는 것입니다. 항상 가능한 것은 아니지만 서버가 사용률을 보고하면 클라이언트는 다른 방법으로는 액세스할 수 없는 집계된 정보를 얻을 수 있습니다. 이를 통해 클라이언트 측 로드 밸런서는 전용 로드 밸런서가 가질 수 있는 종류의 정보를 보다 전체적으로 파악할 수 있습니다. 보너스로, 서버와 네트워크 장애를 구분하는 데 도움이 될 수 있으며, 부하 의존적 해석과 부하 독립적 해석에 영향을 줄 수 있습니다.
이러한 시스템 역학 측면을 염두에 두고 로드 밸런서가 상태 정보를 사용하는 방법을 다시 살펴보겠습니다.
로드 밸런싱에 상태 사용
로드 밸런서는 일반적으로 상태 정보 사용을 두 가지 문제로 구분합니다:
- 요청 후보가 될 서버를 결정한 다음
- 각 요청에 대해 어떤 후보를 선택할지 결정하기
고전적인 접근 방식에서는 이들을 완전히 분리된 두 계층으로 취급합니다. 예를 들어 AWS의 ELB, ALB, NLB는 부하 분산에 다양한 알고리즘 (랜덤, 라운드 로빈, 결정론적 랜덤, 최소 우수)을 사용하지만, 주로 활성 상태 확인을 기반으로 하는 별도의 메커니즘이 있어 어떤 서버가 선택 프로세스에 참여할 수 있는지 결정합니다. (문서에 따르면 NLB는 서버를 쫓아낼지 여부를 결정하기 위해 일부 수동 모니터링을 사용하는 것 같지만 자세한 내용은 알려지지 않았습니다.)
무작위, 라운드 로빈, 결정론적 무작위(예: 플로우 해시)는 상태를 완전히 무시합니다: 서버가 접속 중이거나 접속이 끊긴 상태입니다. 반면에 가장 뛰어난 알고리즘은 수동적인 상태 메트릭을 사용합니다. (이 서버 선택 알고리즘조차도 클러스터에서 서버를 제거하는 데 사용되는 활성 상태 확인과는 완전히 분리되어 있습니다.). 최하위("요청 동시성이 가장 낮은 서버 선택")는 요청 할당에 수동 상태 메트릭을 사용하는 여러 접근 방식 중 하나이며, 각각 앞서 언급한 메트릭 중 하나를 최적화하는 데 기반합니다: 지연 시간, 실패율, 동시성, 대기열 크기.
선택 알고리즘
일부 부하 분산 선택 알고리즘은 메트릭에 가장 적합한 값을 가진 서버를 선택합니다. 이는 표면적으로는 합리적입니다: 현재 요청이 성공할 가능성이 가장 높고 빠르게 처리되기 때문입니다. 그러나 이는 모빙이라는 현상을 초래할 수 있습니다: 지연 시간이 선택한 상태 지표이고 한 서버가 다른 서버보다 약간 낮은 지연 시간을 보이는 경우(모든 클라이언트에서 볼 때), 모든 클라이언트는 적어도 해당 서버가 부하를 겪기 시작하고 심지어 장애가 발생할 때까지 모든 트래픽을 해당 서버로 보내게 됩니다. 서버에 문제가 발생하기 시작하면 유효 지연 시간이 증가하고 다른 서버가 전 세계에서 가장 양호한 서버라는 타이틀을 얻게 될 수도 있습니다. 이러한 현상은 주기적으로 반복될 수 있으며, 초기 상태의 아주 작은 차이로 인해 촉발될 수 있습니다.

모빙 행동에는 시스템의 여러 결함이 복합적으로 작용합니다:
- 지연 시간은 지연된 상태 지표입니다. 동시성(비행 중 요청 수)을 대신 사용하면 서버에 더 많은 요청이 할당되는 즉시 클라이언트 측에서 동시성 메트릭이 즉시 업데이트되므로 클라이언트가 몹되지 않습니다. 댐핑을 사용하더라도 측정이 지연되면 원치 않는 진동이나 공진이 발생할 수 있습니다.
- 고객은 상황을 전체적으로 파악할 수 없기 때문에 원치 않는 상호 연관된 행동을 유발하는 조정되지 않은 방식으로 행동하고 있습니다.
- 서버 상태의 작은 차이는 로드 밸런싱 동작에 큰 차이를 만들어냅니다. 후자에서 전자로 피드백이 발생하므로 초기 조건에 매우 민감한 카오스 시스템에 대한 한 가지 설명에 부합합니다.
제가 보기에 해결책은 다음과 같습니다:
- 가능하면 빠른 상태 메트릭을 사용하세요. 실제로 매우 일반적인 부하 분산 선택 알고리즘은 모든 요청을 대기 중인 요청이 가장 적은 서버로 보내는 것입니다. (연결 중심인지 요청 중심인지에 따라 최소 연결 또는 최소 미해결이라고도 합니다. 일부 연결은 수명이 길고 수명 기간 동안 많은 요청을 전달합니다.) 이와는 대조적으로 지연 시간이 가장 짧은 서버를 선택하는 알고리즘은 본 적이 없는데, 아마도 바로 이런 이유 때문일 것입니다.
- 소수의 서버로 전용 부하 분산 장치를 사용하거나 서버에서 보고된 사용률을 통합하여 상황을 대략적으로 파악하거나 무작위성을 사용하여 원치 않는 상관 관계를 억제합니다.
- 거의 동일한 입력에 대해 거의 동일한 동작을 하는 알고리즘을 사용합니다. 지속적으로 가변적인 동작을 가질 필요는 없지만 무작위성을 사용하여 이에 근접한 동작을 구현할 수 있습니다.
리소스 할당에 대한 일반적인 접근 방식(로드 밸런서에 국한되거나 중심이 되지는 않지만 확실히 관련성이 있음)을 설명하는 논문 ' 두 가지 무작위 선택의 힘'에 설명된 두 가지 선택이라는 최선 선택의 대안이 널리 사용되고 있습니다. 이 접근 방식에서는 두 개의 후보가 선택되고 더 나은 상태를 가진 후보가 사용됩니다. 이는 모든 서버의 장기적인 상태가 동일한 값에 가까워지면 균등한 분포에 가까워지지만, 상태의 작은 지속적 차이로도 부하 분산이 크게 불균형해질 수 있습니다. 피드백이 없는 간단한 시뮬레이션이 이를 잘 보여줍니다:
;; Select the index of one of N servers with health ranging ;; from 1000 to 1000-N, +/-N (defn selecttc [n] (let [spread n ;; top and bottom health ranges overlap by ~half ;; Compute health of a server, by index health (fn [i] (+ (- 1000 i spread) (* 2 spread (rand)))) ;; Randomly choose two servers, without replacement [i1 i2] (take 2 (shuffle (range n)))] ;; Pick the index of the healthier server (if (< (health i1) (health i2)) i2 i1)))
5개의 호스트로 10,000,000번 실행하고 횟수 보고 ;; 각 호스트 인덱스 선택 (정렬 키 (주파수 (반복적으로 10000000 #(selecttc 5)))) ;;= ([0 2849521] [1 2435167] [2 2001078] [3 1566792] [4 1147442))를 수행했습니다.
부하 증가가 상태 메트릭에 영향을 미치지 않는다고 가정하면, 호스트의 대략적인 상태 순위가 비슷할 때 가장 상태가 좋은 호스트와 그렇지 않은 호스트 간에 요청 부하가 2.5배 차이가 납니다. 호스트 0의 상태 범위는 995-1005이고 호스트 4는 991-1001로, 절대적인 차이는 1~2%에 불과하지만 이 약간의 편향이 부하 불균형으로 확대된다는 점에 유의하세요.
2가지 선택은 모빙을 줄이기는 하지만(피드백이 발생하는 경우처럼 편향이 없을 때는 꽤 잘 작동합니다), 지연된 상태 메트릭에 사용하기에 적절한 선택 메커니즘이 아니라는 것은 분명합니다. 또한 이 논문은 동일한 옵션 세트가 주어졌을 때 최대 부하 감소에 초점을 맞춘 것으로 보이는데, 상태 인식 부하 분산 장치의 경우에는 그렇지 않습니다.
반면, 선다형은 피드백이 즉각적이고 자기 수정이 가능하기 때문에 최하위 등급과 잘 어울립니다. 최하위 우수는 그 자체로 정량화된 작은 값을 가질 수 있다는 점에서 어려운 문제입니다. 연결이 하나 열려 있는 서버가 두 개 있는 서버보다 두 배 더 건강한가요? 0과 1은 어떨까요? 최하위값은 요청 부하와 관련하여 클라이언트가 상대적으로 적어서(예: 전용 부하 분산 장치에서) 비교하기 쉬운 경우(예: 17 대 20) 작업하기가 더 쉽습니다. 평균값이 작으면 동점자를 위한 무작위화가 매우 중요해지므로 목록의 첫 번째 서버가 항상 기본적으로 요청을 받는 경우, 각 클라이언트가 하나의 연결만 열려 있는데 300명의 클라이언트가 그 한 서버에 몰리는 경우가 발생할 수 있기 때문입니다. 무작위화를 사용하는 2선택은 최하위 불연속값으로 인한 모빙에 대한 자연스러운 해독제 역할을 합니다.
아직 학문적이지만 매우 유망한 옵션은 가중치 무작위 선택입니다. 각 서버에는 상태 메트릭에서 파생된 가중치가 할당되고 해당 가중치에 따라 서버가 선택됩니다. 예를 들어 서버의 가중치가 7, 3, 1이면 각각 70%, 30%, 10%의 확률로 매번 서버가 선택될 수 있습니다. 이 알고리즘을 사용하려면 굶주림 함정을 피하기 위해 주의를 기울여야 하며, 가중치를 도출할 때는 다른 서버의 90%의 체력을 가진 서버가 상대적으로 20%만 가중치를 받을 수 있도록 잘 선택된 비선형 함수를 사용해야 합니다. 회사에서 이 접근 방식을 실험 중이며 로컬 통합 실험을 통해 큰 기대를 걸고 있지만 아직 실제 트래픽으로 테스트된 것을 보지 못했습니다. 향후 새로운 로드 밸런싱 알고리즘에 대한 포스팅에서 더 자세히 다룰 예정입니다.
상태 메트릭 결합
저는 여러 상태 지표를 사용하는 방법에 대한 질문을 미루고 있었습니다. 제 생각에는 이것이 가장 어려운 부분이며 전체 문제의 핵심에 해당합니다: 애플리케이션의 상태를 어떻게 정의할 것인가?
지연 시간, 장애율, 동시 접속자 수를 추적한다고 가정해 보겠습니다. 이 모든 것이 중요하기 때문입니다. 이 세 가지를 어떻게 결합할까요? 지연 시간이 10배 증가하는 것보다 실패율이 5% 증가하는 것이 더 나쁠까요? (100배?) 다른 서버가 엄청난 지연 시간 급증을 보일 때 어느 시점에서 90%의 가용 서버로 기회를 잡으시겠습니까? 두 가지 일반적인 전략이 떠오릅니다.
각 메트릭에 대해 허용 가능한 임계값을 정의하고, 허용 가능한 장애율이 있는 서버만 선택하고, 없는 경우 허용 가능한 지연 시간이 있는 서버 중에서 선택하는 등의 계층적 접근 방식을 취할 수 있습니다. 허용 가능한 풀이 너무 작으면 다음 계층 아래의 서버도 고려하도록 스필오버 임계값을 정의할 수도 있습니다. (이 아이디어는 Envoy의 우선순위 수준과 어느 정도 유사합니다.)
또는 일부 연속 함수에 따라 메트릭을 결합하는 병합 메트릭을 사용할 수도 있습니다. 일부에 더 많은 가중치를 부여할 수도 있습니다. 저는 현재 각 건강 지표에 대해 [0,1] 가중치 계수를 도출하고 이를 함께 곱하고 일부는 더 큰 거듭제곱(제곱 또는 세제곱)으로 높여 더 많은 가중치를 부여하는 실험을 하고 있습니다. (병합된 메트릭 결합기를 사용하더라도 계층화된 접근 방식과 같은 것을 구현하기 위해 매우 큰 거듭제곱을 사용할 수 있다고 생각합니다.)
또한 이러한 메트릭이 어떻게 함께 변화할 수 있는지 고려하여 서버 및 연결 상태에 대한 고급 모델링을 통해 얻을 수 있는 이점을 살펴볼 가치가 있습니다. 불량 상태에 진입하여 장애 응답을 매우 빠르게 내보내는 서버를 생각해 보세요. 유일한 상태 메트릭이 지연 시간인 경우 이 서버는 이제 클러스터에서 가장 건강한 서버처럼 보이므로 더 많은 트래픽을 수신하게 됩니다. 이를 부하 분산 캡처 효과라고 합니다. 빠르다고 해서 항상 건강한 것은 아닙니다! 구성에 따라 병합 접근 방식은 이 불량 서버에 대한 트래픽을 충분히 억제할 수도 있고 그렇지 않을 수도 있으며, 낮은 장애율을 우선시하는 계층화된 접근 방식은 이 서버를 완전히 배제할 수도 있습니다.
일반적으로 지연 시간과 실패율은 명확하지 않은 방식으로 서로 연관되어 있습니다. "실패를 빠르게 토해내는" 시나리오 외에도 시간 초과 대 시간 초과가 아닌 실패의 문제도 있습니다. 지연 시간이 긴 조건에서 클라이언트는 여러 타임아웃 오류를 발생시킵니다. 이러한 오류는 '실패' 그 자체일까요, 아니면 지연 시간이 지나치게 긴 응답일까요? 지연 시간 메트릭, 실패율 메트릭 또는 둘 다에 영향을 미칠까요? 잘못된 DNS 레코드 및 기타 빠른 연결 실패로 인한 실패와 비교하세요. 제 권장 사항은 성공 또는 시간 초과를 나타내는 것으로 알려진 실패(예: SocketTimeoutException 등 Java에서 이와 유사한 경우)의 지연 시간 수치만 기록하는 것입니다. (한 동료는 지연 시간 평균을 악화시키는 실패에 대해서만 지연 시간 값을 기록하는 대안을 제안했습니다.)
라이프사이클
위의 내용은 대부분 클라이언트가 정적 서버 모음과 통신하고 있다고 가정합니다. 그러나 서버는 한 번에 하나씩 또는 대규모 그룹으로 교체됩니다. 새 서버가 클러스터에 추가되면 부하 분산 장치는 즉시 전체 트래픽을 처리하지 않고 일정 기간 동안 트래픽을 천천히 증가시켜야 합니다. 이 워밍업 기간을 통해 서버가 완전히 최적화될 수 있습니다: 디스크 및 명령어 캐시 워밍업, Java의 핫스팟 최적화 등이 이루어집니다. HAProxy는 이를 위해 슬로우 스타트 기능을 구현합니다. 이 시기는 워밍업 외에도 불확실성이 존재하는 시기이기도 합니다: 클라이언트는 서버에 대한 기록이 없으므로 서버에 대한 의존도를 제한하면 위험을 줄일 수 있습니다.
메트릭 조합 접근 방식을 사용하는 경우 서버 수명을 0에 가까운 상태에서 시작하여 1분 정도에 걸쳐 최대 상태까지 올라가는 페수 상태 메트릭으로 사용하는 것이 편리할 수 있습니다. (알고리즘에 따라 정확히 0에서 시작하는 것은 위험할 수 있습니다. 클라이언트가 서버 세트가 한꺼번에 완전히 교체되었음을 알게 되거나 다른 클러스터를 가리키도록 재구성되어 잠시 모든 서버가 0 상태인 것으로 간주될 수 있기 때문입니다). 서버 목록의 전체 교체를 처리하는 메커니즘은 클라이언트 시작을 처리하는 데도 충분할 것입니다.
로드 쉐딩
요청 부하가 많은 서비스가 CPU 부하 및 기타 리소스 경합을 줄이기 위해 일부 또는 모든 요청에 대해 매우 빠르게 실패로 응답하려고 시도하는 로드 쉐딩에 대해서만 간략히 설명했습니다. 때로는 최선의 노력만으로는 충분하지 않거나 서비스를 확장할 수 있을 만큼 충분히 오래 유지해야 하는 경우가 있습니다. 부하 분산은 지금 50%의 트래픽에 대해 장애를 처리하면 나중에 100%의 트래픽에 성공적으로 대응할 수 있고, 지금 모든 트래픽을 처리하려고 하면 서비스가 완전히 중단될 수 있다는 생각에 기반한 도박입니다. 그렇다면 언제, 얼마나 해야 하는지 어떻게 알 수 있을까요?
로드 밸런서가 부하를 충분히 분산할 수 있다면 Hystrix 또는 동시성 제한과 같은 기능을 앞에 배치하는 것만으로도 충분할 수 있습니다. 제가 볼 수 있는 한 가지 이점은 일부 서버의 상태가 좋지 않을 때 정상 서버의 추가 부하를 관리할 때입니다. 서버의 20%만 정상이라면 정상 서버가 평소보다 5배의 부하를 감당해야 하는 것이 합리적일까요? 로드 밸런서는 초과 부하를 10배 정도로 제한하고, 한 서버가 비정상으로 표시된 9개 서버의 '부하 분담'을 담당하도록 요청하지 않는 것이 합리적일 수 있습니다. 이것이 가능하긴 하지만 바람직한 방법일까요? 잘 모르겠습니다. 여전히 초과 한도를 설정해야 하고, 설정이 쉽게 시대에 뒤떨어질 수 있으며(예: 트래픽이 적은 기간에는 관련성이 떨어질 수 있음), 완전히 적응할 수 있는 방식이 아니라는 점에서 그렇지 않습니다.
결론
위의 내용을 바탕으로 일반적인 고가용성 환경에서 부하 분산을 위한 기존의 많은 옵션이 정상 조건과 일부 오류 조건에서는 부하 분산에 효과적이지만, 그 외의 조건에서는 모빌리티, 장애에 대한 불충분한 대응, 상호 연관된 성능 저하 상태에 대한 과잉 반응 등으로 인해 여러 가지로 부족한 경향이 있다고 생각합니다.
이상적인 고가용성 부하 분산 장치는 정상 작동을 위해 액티브 상태 확인을 하지 않고, 대신 현재 진행 중인 요청과 지연 시간 및 장애율의 감소(또는 롤링) 메트릭을 비롯한 다양한 상태 메트릭을 수동적으로 추적합니다. 이러한 지표를 추적하는 클라이언트는 주기적으로 활성 상태 점검 결과만 관찰하는 클라이언트보다 이상 징후 탐지에 훨씬 유리한 위치에 있습니다.
물론 진정으로 이상적인 부하 분산 장치는 요청 부하가 증가하더라도 시스템이 이론적 한계에 도달할 때까지 모든 요청을 가능한 한 성공적이고 신속하게 처리하는 완벽한 효율성을 구현하며, 그 시점에서 서서히 부하가 증가하는 것이 아니라 갑자기 장애를 일으키거나 부하를 줄이기 시작합니다. 이 문제를 '있었으면 하는 문제'로 분류하고 싶지만, 로드 밸런서가 서버 장애를 외부에 숨기는 데 특히 능숙한 경우 모니터링 도구를 검토해야 할 필요성을 강조합니다.
제가 생각하는 주요 미해결 문제는 이러한 상태 지표를 결합하여 혼란스러운 행동과 이 게시물에서 언급한 다른 문제를 최소화하면서 일반적으로 적용 가능한 방식으로 서버 선택에 사용하는 방법입니다. 현재 저는 다인자 가중 무작위 선택에 베팅하고 있지만, 실제 환경에서 어떻게 작동하는지는 아직 지켜봐야 합니다.