Skip to content

Commit

Permalink
Use recommendationMission to control recommendation lifecycle
Browse files Browse the repository at this point in the history
  • Loading branch information
qmhu committed May 12, 2022
1 parent 929595b commit b5d9670
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 180 deletions.
26 changes: 14 additions & 12 deletions cmd/craned/app/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
autoscalingapi "github.com/gocrane/api/autoscaling/v1alpha1"
ensuranceapi "github.com/gocrane/api/ensurance/v1alpha1"
predictionapi "github.com/gocrane/api/prediction/v1alpha1"

"github.com/gocrane/crane/cmd/craned/app/options"
"github.com/gocrane/crane/pkg/controller/analytics"
"github.com/gocrane/crane/pkg/controller/cnp"
Expand Down Expand Up @@ -282,29 +283,30 @@ func initializationControllers(ctx context.Context, mgr ctrl.Manager, opts *opti
}

if utilfeature.DefaultMutableFeatureGate.Enabled(features.CraneAnalysis) {
if err := (&analytics.Controller{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
RestMapper: mgr.GetRESTMapper(),
Recorder: mgr.GetEventRecorderFor("analytics-controller"),
}).SetupWithManager(mgr); err != nil {
klog.Exit(err, "unable to create controller", "controller", "AnalyticsController")
}

configSet, err := recommend.LoadConfigSetFromFile(opts.RecommendationConfigFile)
if err != nil {
klog.Errorf("Failed to load recommendation config file: %v", err)
os.Exit(1)
}
if err := (&recommendation.Controller{

if err := (&analytics.Controller{
Client: mgr.GetClient(),
ConfigSet: configSet,
Scheme: mgr.GetScheme(),
RestMapper: mgr.GetRESTMapper(),
Recorder: mgr.GetEventRecorderFor("recommendation-controller"),
Recorder: mgr.GetEventRecorderFor("analytics-controller"),
ConfigSet: configSet,
ScaleClient: scaleClient,
PredictorMgr: predictorMgr,
Provider: historyDataSource,
}).SetupWithManager(mgr); err != nil {
klog.Exit(err, "unable to create controller", "controller", "AnalyticsController")
}

if err := (&recommendation.Controller{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
RestMapper: mgr.GetRESTMapper(),
Recorder: mgr.GetEventRecorderFor("recommendation-controller"),
}).SetupWithManager(mgr); err != nil {
klog.Exit(err, "unable to create controller", "controller", "RecommendationController")
}
Expand Down
Binary file added docs/images/analytics-arch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions docs/tutorials/analytics-and-recommendation.zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 分析和推荐

分析和推荐提供了一套自动化的成本优化能力,它帮助用户自动的发现问题并提供优化的方案。就像电脑/手机助手一样,它会定期的扫描、分析你的集群并给出推荐建议。目前,我们提供了两种优化能力:

- **资源推荐**: 基于应用的历史资源使用推荐 Container 合适的 requests 和 limits
- **弹性推荐**: 筛选所有的工作负载,推荐出适合做弹性的工作负载并给出弹性建议

## 架构

![analytics-arch](../images/analytics-arch.png)

## 一次分析的过程

1. 用户创建 Analytics 对象,通过 ResourceSelector 选择需要分析的资源,支持选择多类型(基于Group,Kind,Version)的批量选择
2. 并行分析每个选择的资源,尝试进行分析推荐,每次分析过程分成筛选和推荐两个阶段:
1. 筛选:排除不满足推荐条件的资源。比如对于弹性推荐,排除没有 running pod 的workload
2. 推荐:通过算法计算分析,给出推荐结果
3. 如果通过筛选,创建 Recommendation 对象,将推荐结果展示在 Recommendation.Status
4. 未通过筛选的原因和状态展示在 Analytics.Status
5. 根据运行间隔等待下次分析

## 名词解释

### 分析

分析定义了一个扫描分析任务。支持两种任务类型:资源推荐和弹性推荐。Crane 定期运行分析任务,并产生推荐结果。

### 推荐

推荐展示了一个优化推荐的结果。推荐的结果是一段 YAML 配置,根据结果用户可以进行相应的优化动作,比如调整应用的资源配置。

### 参数配置

不同的分析采用不同的计算模型,Crane 提供了一套默认的计算模型以及一套配套的配置,用户可以通过修改配置来定制推荐的效果。支持修改全局的默认配置和修改单个分析任务的配置。
83 changes: 83 additions & 0 deletions docs/tutorials/hpa-recommendation.zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# 弹性推荐

通过弹性推荐,你可以发现集群中适合弹性的资源,并使用 Crane 推荐的弹性配置创建自动弹性器: EffectiveHPA

## 创建弹性分析

创建一个**弹性分析** `Analytics`,这里我们通过 deployment: `craned` and `metric-adapter` 作为一个例子

```bash
kubectl apply -f https://raw.githubusercontent.com/gocrane/crane/main/examples/analytics/analytics-hpa.yaml
kubectl get analytics -n crane-system
```

## 查看分析结果



## 弹性推荐计算模型

### 筛选阶段

1. 低副本数的工作负载: 过低的副本数可能弹性需求不高,关联配置: ehpa.deployment-min-replicas | ehpa.statefulset-min-replicas | ehpa.workload-min-replicas
2. 存在一定比例非 Running Pod 的工作负载: 如果工作负载的 Pod 大多不能正常运行,可能不适合弹性,关联配置: ehpa.pod-min-ready-seconds | ehpa.pod-available-ratio
3. 低 CPU 使用量的工作负载: 过低使用量的工作负载意味着没有业务压力,此时通过使用率推荐弹性不准,关联配置: ehpa.min-cpu-usage-threshold
4. CPU 使用量的波动率过低: 使用量的最大值和最小值的倍数定义为波动率,波动率过低的工作负载通过弹性降本的收益不大,关联配置: ehpa.fluctuation-threshold

### 推荐

推荐阶段通过以下模型推荐一个 EffectiveHPA 的 Spec。每个字段的推荐逻辑如下:

**推荐 TargetUtilization**

原理: 使用 Pod P99 资源利用率推荐弹性的目标。因为如果应用可以在 P99 时间内接受这个利用率,可以推断出可作为弹性的目标。

1. 通过 Percentile 算法得到 Pod 过去七天 的 P99 使用量: pod_cpu_usage_p99
2. 对应的利用率:target_pod_cpu_utilization = pod_cpu_usage_p99 / pod_cpu_request
3. 为了防止利用率过大或过小,target_pod_cpu_utilization 需要小于 ehpa.min-cpu-target-utilization 和大于 ehpa.max-cpu-target-utilization

**推荐 minReplicas**

原理: 使用 workload 过去七天内每小时负载最低的利用率推荐 minReplicas。

1. 计算过去7天 workload 每小时使用量中位数的最低值: workload_cpu_usage_medium_min
2. 对应的最低利用率对应的副本数: minReplicas = workload_cpu_usage_medium_min / pod_cpu_request / ehpa.max-cpu-target-utilization
3. 为了防止 minReplicas 过小,minReplicas 需要大于等于 ehpa.default-min-replicas

**推荐 maxReplicas**

原理: 使用 workload 过去和未来七天的负载推荐最大副本数。

1. 计算过去七天和未来七天 workload cpu 使用量的 P95: workload_cpu_usage_p95
2. 对应的副本数: max_replicas_origin = workload_cpu_usage_p95 / pod_cpu_request / target_cpu_utilization
3. 为了应对流量洪峰,放大一定倍数: max_replicas = max_replicas_origin * ehpa.max-replicas-factor

**推荐CPU以外 MetricSpec**

1. 如果 workload 配置了 HPA,继承相应除 CpuUtilization 以外的其他 MetricSpec

**推荐 Behavior**

1. 如果 workload 配置了 HPA,继承相应的 Behavior 配置

**预测**

1. 尝试预测工作负载未来七天的 CPU 使用量,算法是 DSP
2. 如果预测成功则添加预测配置
3. 如果不可预测则不添加预测配置,退化成不具有预测功能的 EffectiveHPA


## 弹性分析计算配置

- ehpa.deployment-min-replicas: 默认值 1,小于该值的工作负载不做弹性推荐
- ehpa.statefulset-min-replicas: 默认值 1,小于该值的工作负载不做弹性推荐
- ehpa.workload-min-replicas: 默认值 1,小于该值的工作负载不做弹性推荐
- ehpa.pod-min-ready-seconds: 默认值 30,定义了 Pod 是否 Ready 的秒数
- ehpa.pod-available-ratio: 默认值 0.5,Ready Pod 比例小于该值的工作负载不做弹性推荐
- ehpa.default-min-replicas: 默认值 2,最小 minReplicas
- ehpa.max-replicas-factor: 默认值 3,计算 maxReplicas 的倍数
- ehpa.min-cpu-usage-threshold: 默认值 10, 小于该值的工作负载不做弹性推荐
- ehpa.fluctuation-threshold: 默认值 1.5, 小于该值的工作负载不做弹性推荐
- ehpa.min-cpu-target-utilization: 默认值 30
- ehpa.max-cpu-target-utilization: 默认值 75
- ehpa.reference-hpa: 默认值 true,继承现有的 HPA 配置
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.17

require (
github.com/go-echarts/go-echarts/v2 v2.2.4
github.com/gocrane/api v0.4.0
github.com/gocrane/api v0.4.1-0.20220507041258-d376db2b4ad4
github.com/google/cadvisor v0.39.2
github.com/mjibson/go-dsp v0.0.0-20180508042940-11479a337f12
github.com/prometheus/client_golang v1.11.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ github.com/gocrane/api v0.3.0 h1:ziH+zYQy/shiqQ6yskMs67e+bQ9WmPp8eCVhLW85NFQ=
github.com/gocrane/api v0.3.0/go.mod h1:GxI+t9AW8+NsHkz2JkPBIJN//9eLUjTZl1ScYAbXMbk=
github.com/gocrane/api v0.4.0 h1:1IWP3gbkp3T4kX68w4+PfqUr4Cb/gaJrihLYg6aKOLY=
github.com/gocrane/api v0.4.0/go.mod h1:GxI+t9AW8+NsHkz2JkPBIJN//9eLUjTZl1ScYAbXMbk=
github.com/gocrane/api v0.4.1-0.20220507041258-d376db2b4ad4 h1:vGDg3G6y661KAlhjf/8/r8JCjaIi6aV8szCP+MZRU3Y=
github.com/gocrane/api v0.4.1-0.20220507041258-d376db2b4ad4/go.mod h1:GxI+t9AW8+NsHkz2JkPBIJN//9eLUjTZl1ScYAbXMbk=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand Down
Loading

0 comments on commit b5d9670

Please sign in to comment.