수학: 오케스트레이터로 마이크로서비스 애플리케이션 확장
게시 됨: 2022-03-11마이크로서비스 애플리케이션 아키텍처가 계속해서 소프트웨어 설계를 침범하는 것은 놀라운 일이 아닙니다. 개발 및 팀 관리를 용이하게 하면서 부하를 분산하고, 고가용성 배포를 생성하고, 업그레이드를 관리하는 것이 훨씬 더 편리합니다.
그러나 컨테이너 오케스트레이터 없이는 이야기가 완전히 같지 않습니다.
모든 주요 기능, 특히 자동 크기 조정을 사용하기 쉽습니다. 하루 종일 변동하는 컨테이너 배포를 보고 현재 부하를 처리할 수 있는 크기로 부드럽게 조정되어 다른 작업에 시간을 할애할 수 있다는 것은 얼마나 큰 축복입니까? 우리는 컨테이너 모니터링 도구가 보여주는 것에 대해 자랑스럽게 생각합니다. 한편, 우리는 몇 가지 설정을 구성했습니다. 예, 그것이 (거의) 마법을 만드는 데 필요한 전부입니다!
그렇다고 자랑스러워할 이유가 없다는 것은 아닙니다. 사용자가 좋은 경험을 하고 있고 대규모 인프라로 돈을 낭비하지 않고 있다고 확신합니다. 이것은 이미 상당한 수준입니다!
그리고 물론, 거기에 도달하기까지의 여정은 얼마나 컸는지! 결국 구성해야 할 설정이 많지 않더라도 시작하기 전에 일반적으로 생각하는 것보다 훨씬 까다롭기 때문입니다. 최소/최대 복제본 수, 업스케일/다운스케일 임계값, 동기화 기간, 휴지 지연 등 모든 설정은 매우 밀접하게 연결되어 있습니다. 하나를 수정하면 다른 하나에 영향을 미칠 가능성이 가장 높지만 여전히 애플리케이션/배포와 인프라 모두에 적합한 균형 잡힌 조합을 정렬해야 합니다. 그러나 인터넷에서 요리책이나 마법의 공식을 찾을 수 없습니다. 필요에 따라 크게 달라지기 때문입니다.
우리 대부분은 모니터링하는 동안 찾은 항목에 따라 나중에 조정하는 "임의" 또는 기본값으로 먼저 설정합니다. 그래서 생각하게 되었습니다. 우리가 더 나은 조합을 찾는 데 도움이 되는 보다 "수학적" 절차를 수립할 수 있다면 어떨까요?
컨테이너 오케스트레이션 매개변수 계산
애플리케이션을 위한 자동 크기 조정 마이크로서비스에 대해 생각할 때 실제로 우리는 두 가지 주요 점에서 개선을 모색하고 있습니다.
- 로드가 급격히 증가하는 경우 배포 를 빠르게 확장 할 수 있는지 확인(사용자가 시간 초과 또는 HTTP 500에 직면하지 않도록)
- 인프라 비용 절감 (즉, 인스턴스에 과부하가 걸리지 않도록 유지)
이는 기본적으로 확장 및 축소를 위해 컨테이너 소프트웨어 임계값을 최적화하는 것을 의미합니다. (Kubernetes의 알고리즘에는 둘에 대한 단일 매개변수가 있습니다).
모든 인스턴스 관련 매개변수가 고급 임계값에 연결되어 있음을 나중에 보여드리겠습니다. 이것은 계산하기 가장 어려운 것이므로 이 기사를 참조하십시오.
참고: 클러스터 전체에 설정되는 매개변수에 대해서는 적절한 절차가 없지만 이 기사의 끝에서 계산하는 동안 고려하는 소프트웨어(정적 웹 페이지)를 소개합니다. 인스턴스의 자동 크기 조정 매개변수. 그렇게 하면 값을 변경하여 영향을 고려할 수 있습니다.
확장 임계값 계산
이 방법이 작동하려면 애플리케이션이 다음 요구 사항을 충족하는지 확인해야 합니다.
- 로드는 애플리케이션의 모든 인스턴스에 고르게 분산 되어야 합니다(라운드 로빈 방식).
- 요청 시간은 컨테이너 클러스터의 로드 확인 간격 보다 짧아야 합니다.
- 많은 수의 사용자 (나중에 정의됨)에서 프로시저를 실행하는 것을 고려해야 합니다.
이러한 조건의 주된 이유는 알고리즘이 부하를 사용자별로 계산하지 않고 분포로 계산하기 때문입니다(나중에 설명).
모든 가우시안 얻기
먼저 급격한 부하 증가 또는 최악의 시나리오에 대한 정의를 공식화해야 합니다. 나에게 좋은 번역 방법 은 짧은 시간 내에 많은 수의 사용자가 리소스를 소모하는 작업을 수행하도록 하는 것입니다. 그리고 다른 사용자 또는 서비스 그룹이 다른 작업을 수행하는 동안 발생할 가능성이 항상 있습니다. 따라서 이 정의에서 시작하여 수학을 추출해 보겠습니다. (아스피린을 준비하십시오.)
몇 가지 변수 소개:
- $N_{u}$, "많은 사용자"
- $L_{u}(t)$, "자원 소모 작업"을 수행하는 단일 사용자에 의해 생성된 로드($t=0$는 사용자가 작업을 시작하는 순간을 가리킴)
- $L_{tot}(t)$, 총 부하(모든 사용자가 생성)
- $T_{tot}$, "짧은 기간"
수학 세계에서 많은 수의 사용자가 동시에 같은 작업을 수행하는 경우 시간 경과에 따른 사용자 분포는 가우스(또는 정규) 분포를 따르며 공식은 다음과 같습니다.
\[G(t) = \frac{1}{\sigma \sqrt{2 \pi}} e^{\frac{-(t-\mu)^2}{2 \sigma^2}}\]여기:
- µ 는 예상 값입니다.
- σ 는 표준편차
그리고 다음과 같이 그래프로 표시됩니다($µ=0$ 포함).
아마도 당신이 수강한 일부 수업을 연상시킬 것입니다. 새로운 것은 아닙니다. 그러나 여기서 우리는 첫 번째 문제에 직면합니다. 수학적으로 정확하려면 $-\infty$에서 $+\infty$까지의 시간 범위를 고려해야 합니다. 이는 분명히 계산할 수 없습니다.
그러나 그래프를 보면 $[-3σ, 3σ]$ 구간 외부의 값이 0에 매우 가깝고 크게 변하지 않는다는 것을 알 수 있습니다. 우리의 목표는 애플리케이션 확장을 테스트하는 것이기 때문에 많은 사용자의 변형을 찾고 있기 때문에 더욱 그렇습니다.
또한 $[-3σ, 3σ]$ 구간에는 사용자의 99.7%가 포함되어 있으므로 작업하기에 충분한 합계에 가깝고 $N_{u}$에 1.003을 곱하면 됩니다. 차이점. 이 간격을 선택하면 $µ=3σ$가 됩니다($t=0$에서 작업할 것이기 때문에).
$T_{tot}$에 대한 대응과 관련하여 $6σ$($[-3σ, 3σ]$)와 같도록 선택하는 것은 사용자의 95.4%가 $[- 2σ, 2σ]$, $4σ$ 지속. 따라서 $T_{tot}$를 $6σ$와 같게 선택하면 사용자의 4.3%만 시간의 절반을 추가하게 되며, 이는 실제로 대표성이 아닙니다. 따라서 우리는 $T_{tot}=4σ$를 선택하고 다음을 추론할 수 있습니다.
\(σ=\frac{T_{tot}}{4}\) 및 \(µ=\frac{3}{4} * T_{tot}\)
그 가치는 방금 모자에서 꺼낸 것입니까? 네. 그러나 이것이 그들의 목적이며 이것은 수학적 절차에 영향을 미치지 않습니다. 이러한 상수는 우리를 위한 것이며 우리의 가설과 관련된 개념을 정의합니다. 이것은 단지 우리가 그것들을 설정했으므로 최악의 시나리오가 다음과 같이 번역될 수 있다는 것을 의미합니다.
$N{u}$의 99.7%에 의해 생성된 로드, $L{u}(t)$ 소비 작업을 수행하고 그 중 95.4%가 $T{tot}$ 기간 내에서 수행합니다.
(웹 앱을 사용할 때 기억할 가치가 있는 사항입니다.)
이전 결과를 사용자 분포 함수(가우스)에 주입하면 다음과 같이 방정식을 단순화할 수 있습니다.
\[G(t) = \frac{4 N_{u}}{T_{tot} \sqrt{2 \pi}} e^\frac{-(4t-3T_{tot})^2}{T_{tot }^2}\]지금부터 $σ$와 $µ$를 정의한 상태에서 $t \in [0, \frac{3}{2}T_{tot}]$ 구간($6σ$ 지속)에 대해 작업합니다.

총 사용자 로드는 얼마입니까?
Auto-scaling 마이크로서비스의 두 번째 단계는 $L_{tot}(t)$를 계산하는 것입니다.
$G(t)$는 분포 이므로 특정 시점의 사용자 수를 검색하려면 적분을 계산해야 합니다(또는 누적 분포 함수를 사용). 그러나 모든 사용자가 동시에 작업을 시작하는 것은 아니므로 $L_{u}(t)$를 도입하고 방정식을 사용 가능한 공식으로 줄이려고 하면 정말 엉망이 될 것입니다.
그래서 이것을 더 쉽게 하기 위해 우리는 작은 모양의 유한 합을 사용하여 적분을 근사하는 수학적 방법인 리만 합을 사용할 것입니다(여기서 직사각형을 사용할 것입니다). 모양(세분)이 많을수록 결과가 더 정확합니다. 세분화 사용의 또 다른 이점은 세분화 내의 모든 사용자가 동시에 작업을 시작한 것으로 간주할 수 있다는 사실입니다.
리만 합으로 돌아가면 적분과 연결되는 다음과 같은 속성이 있습니다.
\[\int_{a}^{b} f( x )dx = \lim_{n \rightarrow \infty } \sum_{k=1}^{n} ( x_{k} - x_{k-1} ) f( x_{k} )\]$x_k$는 다음과 같이 정의됩니다.
\[x_{ k } = a + k\frac{ b - a }{ n }, 0 \leq k \leq n\]다음과 같은 경우에 해당합니다.
- $n$은 세분화의 수입니다.
- $a$는 하한이며 여기에서는 0입니다.
- $b$는 상한입니다. 여기서 $\frac{3}{2}*T_{tot}$입니다.
- $f$는 그 면적을 근사화하는 함수(여기서는 $G$)입니다.
참고: 세분화에 있는 사용자의 수는 정수가 아닙니다. 이것이 두 가지 전제 조건에 대한 이유입니다. 많은 수의 사용자가 있어야 하고(소수 부분이 너무 영향을 미치지 않도록), 부하가 모든 인스턴스에 고르게 분산되어야 합니다.
또한 리만 합 정의의 오른쪽에서 세분화의 직사각형 모양을 볼 수 있습니다.
이제 우리는 Riemann sum 공식을 얻었으므로 $t$ 시간의 로드 값은 모든 세분화된 사용자 수의 합에 해당 시간 의 사용자 로드 함수를 곱한 값이라고 말할 수 있습니다. 이것은 다음과 같이 쓸 수 있습니다.
\[L_{ tot }( t ) = \lim_{n \rightarrow \infty} \sum_{ k=1 }^{ n } ( x_{k} - x_{k-1} )G( x_{k} ) L_{ 유 }( t - x_{k} )\]변수를 대체하고 공식을 단순화하면 다음이 됩니다.
\[L_{ tot }( t ) = \frac{6 N_{u}}{\sqrt{2 \pi}} \lim_{n \rightarrow \infty} \sum_{ k=1 }^{ n } (\ frac{1}{n}) e^{-{(\frac{6k}{n} - 3)^{2}}} L_{ u }( t - k \frac{3 T_{tot}}{2n } )\]그리고 짜잔 ! 로드 기능을 만들었습니다!
확장 임계값 찾기
끝내기 위해 임계값을 변경하는 이분법 알고리즘을 실행하여 인스턴스당 로드가 로드 기능 전체에서 최대 한도를 초과하지 않는 가장 높은 값을 찾기만 하면 됩니다. (이것은 앱에서 수행하는 작업입니다.)
기타 오케스트레이션 매개변수 추론
확장 임계값($S_{up}$)을 찾으면 다른 매개변수를 계산하기가 매우 쉽습니다.
$S_{up}$부터 최대 인스턴스 수를 알 수 있습니다. (로드 함수의 최대 로드를 찾아 인스턴스당 최대 로드로 나누어 반올림할 수도 있습니다.)
최소 인스턴스 수($N_{min}$)는 인프라에 따라 정의되어야 합니다. (AZ당 최소 하나의 복제본을 갖는 것이 좋습니다.) 그러나 로드 함수도 고려해야 합니다. 가우스 함수가 상당히 빠르게 증가함에 따라 처음에는 로드 분포가 더 강력하므로(레플리카당) 이 효과를 완화하기 위해 최소 복제본 수를 늘릴 수 있습니다. (이렇게 하면 $S_{up}$가 증가할 가능성이 높습니다.)
마지막으로 최소 복제본 수를 정의한 후에는 다음을 고려하여 축소 임계값($S_{down}$)을 계산할 수 있습니다. $N_{min}+1$ ~ $N_{min}$, 축소 직후 확장 임계값이 트리거되지 않도록 해야 합니다. 허용되면 요요 효과가 발생합니다. 다시 말해:
\[( N_{ 분 } + 1) S_{ 아래로 } < N_{ 분 }S_{ 위로 }\]또는:
\[S_{ 아래로 } < \frac{N_{ 분 }}{N_{분}+1}S_{ 위로 }\]또한 축소하기 전에 클러스터가 대기하도록 더 오래 구성할수록 $S_{down}$를 더 높은 한계에 더 가깝게 설정하는 것이 더 안전하다는 것을 인정할 수 있습니다. 다시 한 번, 자신에게 맞는 균형을 찾아야 합니다.
Autoscaler와 함께 Mesosphere Marathon 오케스트레이션 시스템을 사용할 때 축소에서 한 번에 제거할 수 있는 최대 인스턴스 수는 AS_AUTOSCALE_MULTIPLIER
($A_{mult}$)에 연결되며, 이는 다음을 의미합니다.
사용자 로드 기능은 어떻습니까?
예, 그것은 약간의 문제이며 수학적으로 해결하기 가장 쉬운 문제는 아닙니다.
이 문제를 해결하려면 응용 프로그램의 단일 인스턴스를 실행하고 서버 부하가 할당된 최대값에 도달할 때까지 동일한 작업을 반복적으로 수행하는 사용자 수를 늘리는 것입니다(단, 초과는 아님). 그런 다음 사용자 수로 나누어 요청의 평균 시간을 계산합니다. 사용자 로드 기능에 통합하려는 모든 작업에 대해 이 절차를 반복하고 약간의 타이밍을 추가하면 완료됩니다.
나는 이 절차가 각 사용자 요청이 처리에 대해 일정한 부하를 갖는다는 것을 의미한다는 것을 알고 있지만(분명히 잘못된 것임), 많은 사용자가 동시에 동일한 처리 단계에 있지 않기 때문에 이러한 효과를 생성할 것입니다. . 따라서 이것이 수용 가능한 근사치라고 생각하지만, 이는 다시 한 번 많은 수의 사용자를 다루고 있음을 암시합니다.
CPU 플레임 그래프와 같은 다른 방법을 사용해 볼 수도 있습니다. 그러나 사용자 행동을 리소스 소비와 연결하는 정확한 공식을 만드는 것은 매우 어려울 것이라고 생각합니다.
app-autoscaling-calculator
소개
그리고 이제 전체에 걸쳐 언급된 작은 웹 앱의 경우: 로드 기능, 컨테이너 오케스트레이터 구성 및 기타 일반 매개변수를 입력으로 사용하고 확장 임계값 및 기타 인스턴스 관련 수치를 반환합니다.
프로젝트는 GitHub에서 호스팅되지만 라이브 버전도 사용할 수 있습니다.
다음은 테스트 데이터(Kubernetes에서)에 대해 실행한 웹 앱에서 제공한 결과입니다.
마이크로서비스 확장: 더 이상 어둠 속에서 더듬거리지 마세요
마이크로서비스 애플리케이션 아키텍처와 관련하여 컨테이너 배포는 전체 인프라의 중심점이 됩니다. 또한 오케스트레이터와 컨테이너가 더 잘 구성될수록 런타임이 더 원활해집니다.
DevOps 서비스 분야의 사람들은 항상 애플리케이션에 대한 조정 매개변수를 조정하는 더 나은 방법을 찾고 있습니다. 자동 크기 조정 마이크로 서비스에 대해 보다 수학적 접근 방식을 취합시다!