23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
Kubernetes 의 Node 개수는 Pod가 요청하는 CPU, Memory 의 크기에 따라 결정됩니다.
Pod가 많은 CPU, Memory 를 요청할 수록 많은 불필요하게 많은 Node가 필요하며, 너무 적을 경우 안정적인 서비스 운영이 어렵습니다.
이번 글에서는 Pod의 리소스 요청값(=requests) 를 최적화 하는 방법에 대해서 소개하려고 합니다.
Kubernetes에 배포될 Pod 를 정의할때 아래와 같은 requests 와 limits 값을 정해야 합니다.
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
requests 는, Pod가 Node에 스케줄링될 때 필요한 공간 입니다.
Node에 requests 만큼의 CPU, Memory 가 남아있을 경우 Pod가 스케줄링되며, 만일 부족하다면 다른 Node에 스케줄링되거나,
Cluster Autoscaler 등이 구성되어 있다면 새로운 Node가 생성되고 Pod가 스케줄링 됩니다.
가능한 Node가 없다면 Pending 상태로 대기합니다.
limits 은 Pod가 실제 사용할수 있는 최대 리소스입니다.
requests.cpu=100m, limits.cpu=200m 이라면 Pod는 100m의 여유가 있는 Node에 스케줄링 되지만, 실제 동작시에는 최대 200m 까지 사용할 수 있습니다.
따라서 특정 Node의 모든 Pod 의 sum(limits) 값이 Node의 실제 CPU 보다 클 수 있습니다.
따라서 다수의 Pod가 동시에 requests 이상의 CPU를 사용할 경우 Node의 CPU가 부족해질수 있고, throttling 으로 인한 전체적인 성능저하가 발생할수 있습니다.
만일 Memory가 부족하다면 OOMKilled가 (Out of Memory) 발생할수 있습니다.
이중 비용(=Node수)과 직결되는건 requests 값 입니다. requests 가 너무 클 경우 불필요한 Node로 인한 비용 낭비가 발생할 수 있습니다.
반대로 너무 적을 경우 하나의 Node에 너무 많은 Pod가 스케줄링되어 throttling 및 OOMKilled가 빈번하게 발생할 수 있습니다.
그렇다면 어떻게 적절한 Requests 값을 찾을수 있을까요?
실제 Pod가 사용하는 리소스 사용량을 측정하고 이를 기반으로 Requests 값을 정하는 것입니다. (사실 당연한 얘기)
VPA (Vertical Pod Autoscaler) 와 Kubecost 는 이러한 방식의 Recommender 를 가지고 있습니다.
전체적인 Architecture는 거의 유사한데, metric server 로부터 Pod의 실사용량을 수집하고, 이를 기반으로 requests 값을 추천하는 방식입니다.
사실 VPA나 Kubecost 의 계산방식은 유사합니다. 1) "기준값"을 결정하고, 2) "margin"을 추가하는 방식입니다.
예를 들어 설명해 보겠습니다. 3일간 측정한 Pod의 CPU 및 Memory 실사용량이 아래와 같다고 가정하겠습니다.
CPU- avg=2core, max=4core
Memory- avg=1GB, max=2GB
첫번째로 "기준값"을 정해야 합니다.
기준값은 Pod가 동작하는데 필요한 최소한의 값(또는 대표하는 값)정도로 생각할 수 있습니다.
이 경우, 2core~4core 사이의 값이 될 수 있습니다. 대부분의 CPU 사용율이 avg(=2core) 정도이고,
일주일에 1~2회 정도만 max(=4core) 까지 사용한다면 기준값은 2core가 적절할 수 있습니다.
만일 max 까지 사용하는 경우가 빈번하다면 기준값을 4core로 하는것이 적절할 수 있겠죠. 경우에 따라 2core~4core 사이의 어떤 값이 적절할 수 있습니다.
또 다른 기준으로, production 환경이라면 서비스 안정성을 위해 max 를 기준값을 가져가고, dev/staging 환경이라면 비용절감을 위해서 avg 를 기준값을 가져갈 수 있습니다.
결국에는 서비스의 특성과 SLA 등을 고려해서 적절한 "기준값" 을 정해야 합니다.
두번째로 "margin" 을 추가합니다.
margin은 이름처럼 약간의 버퍼입니다. 예를 들어 Memory의 경우 max(=2GB)를 기준값으로 정하더라도
이보다 더 많은 Memory를 사용할 경우 OOMKilled 가 발생하여 서비스에 영향을 미칠수 있습니다.
이러한 현상을 방지하기 위해 "margin"을 추가해야 합니다.
역시나 production 환경이라면 서비스 안정성을 위해 margin 을 크게 가져가고, dev/staging 환경이라면 비용절갑을 위해서 margin을 작게 가져갈수 있습니다.
반복되는 내용이지만, 서비스의 특성과 SLA 등을 고려해서 적절한 "margin" 을 정해야 합니다.
결국 최종 추천되는 requests 값은 (기준값) x (margin) 입니다.
VPA나 Kubecost의 차이점이라면, 기준값을 구하는 방식과 margin 의 크기입니다.
VPA Recommender 의 동작을 설명한 공식문서가 없어서, 코드 및 구글링을 통해 확인한 내용입니다.
혹시 이후에 로직이 변경되거나 일부 틀린 내용이 있을수 있습니다. 참고로 VPA Recommender 를 활용하여 최적화를 좀더 편리하게 해주는 Goldilocks 라는 패키지도 있습니다 (참고)
VPA Recommender 의 세부 로직을 살펴보겠습니다.
VPA Recommender는 사전에 정의된 3가지 profile 을 제공하며, 각각은 target-percentile 라는 값이 다릅니다.
여기서 target-percentile 은 "분위수"의 의미이며, 기준값을 구하는데 사용됩니다.
측정된 값중에서 frual 은 상위 50%, performance 는 상위 95%의 값을 사용하겠다는 의미입니다.
profile | target-percentile |
|---|---|
frual | 50 |
standard | 90 |
performance | 95 |
참고로 target-percentile 값을 customizing 할 수 있기 때문에, 꼭 사전에 정의된 profile 을 사용할 필요는 없습니다.
또한 histogram-decay-half-life 라는 것을 적용하여 오래된 데이터의 가중치를 절반으로 낮추는 동작을 합니다.
이를 통해 상위 N%의 값을 계산할때, 최신 데이터를 중요하게 반영합니다. default 는 24h 입니다.
VPA의 default magin은 0.15 입니다. 기준값에 15%의 margin 을 추가합니다. (recommendation-margin-fraction)
측정 기간의 default는 8d 입니다.
정리하면, VPA의 default 추천 로직은 아래와 같습니다.
8d 동안의 데이터를 수집
최신의 데이터를 중요하게 반영하여, percentile 값 계산
15% 의 margin 추가
위에서 설명한 모든 값들은 customzing이 가능합니다.
kubecost 에 대해서 잘 모르신다면 이전글을 참고해 주세요
Kubecost의 세부 로직을 살펴보겠습니다.
VPA와 유사하게 사전에 정의된 3가지 profile 을 제공하며, 각각은 targetUtilization 라는 값이 다릅니다.
여기서 targetUtilization 은 margin을 더한 추천값의 비율입니다.
Development 는 10020/80=25%, Production 은 10035/65=53%, High Availability 는 100*50/50%=100%의 margin 을 더한다는 의미입니다.
Profile | targetUtilization |
|---|---|
Development | 80% |
Production | 65% |
High Availability | 50% |
여기서 High Availability 는 너무 극단적인 margin (100%)이 아닌가 하는 생각이 들긴 하지만,
인프라 Scaling 이 자유롭지 않고, 서비스 안정성이 정말 중요한 상황에는 이렇게 정하는 경우도 있으니 추가된거라 생각됩니다.
역시나 targetUtilization 값을 customizing 할 수 있기 때문에, 꼭 사전에 정의된 profile 을 사용할 필요는 없습니다.
Kubecost 는 기준값을 구하는 algorithm으로 quantile 또는 max 를 사용할 수 있습니다.
max는 최대값을 의미하며, quantile 은 VPA의 target-percentile 와 동일한 의미 입니다. default 는 max 입니다.
참고로 일반적인 데이터분석시, outlier 를 제외하고자 할때, average 이나 max 대신, median(=중앙값) 또는 percentile 을 대표값으로 사용합니다.
max 값이 outlier인지, 정상적인 값인지를 판단해서 결정하면 좋을것 같습니다.
측정 기간의 default는 3d 입니다.
정리하면, Kubecost의 default 추천 로직은 아래와 같습니다.
3d 동안의 데이터를 수집
max 값 계산
20~50% 의 margin 추가
역시나 모든 값들은 customzing이 가능합니다.
둘 간의 계산방식은 기본적으로는 동일 합니다. percentile 또는 max 값을 통해 기준값을 정하고, margin 을 더하는 방식입니다.
사전 정의된 profile 을 비교해보면, VPA는 기준값(percentile) 을 변경하고, kubecost는 margin 을 변경하는 방식입니다.
차이점은 VPA는 histogram-decay 를 통해 최신의 데이터를 중요하게 반영한다는 것입니다.
아무래도 VPA는 태생이 Scaler 이고, 현재 상황에 맞게 AutoScaling 을 해주는것이 목적이기 때문에 최신의 데이터를 중요하게 반영하는 로직이 추가된것 같습니다.
서비스의 특성과 배포 환경을 고려해서 적절한 기준값과 margin을 결정해야 합니다. VPA와 kubecost의 경우를 봤을때, 기준값은 50~100% 의 percentile 값, margin 은 15~100% 정도의 값을 사용합니다.
일단 사용하는 Tool에서 사전에 정의된 profile 중 하나를 선택해서 사용하고,
이후에 서비스 특성에 맞춰 측정기간, 기준값(percentile/max) 및 margin 등을 지속적으로 최적화하는 활동이 필요합니다.
이를 위해서는 requests 값이 적절한지 지속적으로 모니터링하는 환경이 구성되어 있으면 더욱 좋습니다.
limits 값 또한, 기준값과 margin 을 다르게 가져갈뿐, 동일한 방식으로 계산이 가능합니다.
모든 것이 가상화 되면서 유연하고, 편리하기도 하지만, 운영자의 관심과 노력이 더욱 중요해지는 것 같다는 생각이 듭니다.
혹시 더 나은 방식이나 오픈소스가 있다면 알려주시면 감사하겠습니다~
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.