什么是evaluator

大家都知道,Kubernetes中使用resourcequota对配额进行管理。配额的管理涉及两个步骤:1、计算请求所需要的资源;2、比较并更新配额。所以解读resourcequota将分为两次进行。
evaluator就是用来计算请求所需要的资源的。

GenericEvaluator

GenericEvaluator实现了evaluator,是一个基础的evaluator。
我们先来看下GenericEvaluator的定义,在/pkg/quota/generic/evaluator.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
type GenericEvaluator struct {
// Name used for logging
Name string
// The GroupKind that this evaluator tracks
InternalGroupKind unversioned.GroupKind
// The set of resources that are pertinent to the mapped operation
InternalOperationResources map[admission.Operation][]api.ResourceName
// The set of resource names this evaluator matches
MatchedResourceNames []api.ResourceName
// A function that knows how to evaluate a matches scope request
MatchesScopeFunc MatchesScopeFunc
// A function that knows how to return usage for an object
UsageFunc UsageFunc
// A function that knows how to list resources by namespace
ListFuncByNamespace ListFuncByNamespace
// A function that knows how to get resource in a namespace
// This function must be specified if the evaluator needs to handle UPDATE
GetFuncByNamespace GetFuncByNamespace
// A function that checks required constraints are satisfied
ConstraintsFunc ConstraintsFunc
}

其中:

  • Name: 表示该Evaluator的名称;
  • InternalGroupKind: 表明该Evaluator所处理资源的内部的类型;
  • InternalOperationResources: 表明该Evaluator所支持的请求的类型,如Create, Update等及这些操作所支持的资源;
  • MatchedResourceNames: 表明该Evaluator所对应的资源名称,如ResourceCPU, ResourcePods等;
  • MatchesScopeFunc: resourcequota的scope判断函数。resourcequota只处理满足scope判断函数的请求(即只统计部分对象的配额),目前有Terminating, NotTerminating, BestEffort, NotBestEffort这些Scope;
  • UsageFunc: 用来计算对象所占资源;
  • ListFuncByNamespace: 对象List函数;
  • GetFuncByNamespace: 对象获取函数;
  • ConstraintsFunc: 对对象申请的资源进行合理性检查,如requests<limits。

Matches()

Matches()方法判断该Evaluator及resourceQuota是否需要处理该请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Matches returns true if the evaluator matches the specified quota with the provided input item
func (g *GenericEvaluator) (resourceQuota *api.ResourceQuota, item runtime.Object) bool {
if resourceQuota == nil {
return false
}
// verify the quota matches on resource, by default its false
matchResource := false
//***如果resourceQuota中的项有该evaluator处理时所需要的项,则更新matchResource为true***//
for resourceName := range resourceQuota.Status.Hard {
if g.MatchesResource(resourceName) {
matchResource = true
break
}
}
// by default, no scopes matches all
matchScope := true
for _, scope := range resourceQuota.Spec.Scopes {
matchScope = matchScope && g.MatchesScope(scope, item)
}
return matchResource && matchScope
}
// MatchesResource returns true if this evaluator can match on the specified resource
func (g *GenericEvaluator) MatchesResource(resourceName api.ResourceName) bool {
for _, matchedResourceName := range g.MatchedResourceNames {
if resourceName == matchedResourceName {
return true
}
}
return false
}
// MatchesScope returns true if the input object matches the specified scope
func (g *GenericEvaluator) MatchesScope(scope api.ResourceQuotaScope, object runtime.Object) bool {
return g.MatchesScopeFunc(scope, object)
}

Usage()

Usage()方法可以计算object所需要的资源。

1
2
3
4
//***计算资源使用量***//
func (g *GenericEvaluator) Usage(object runtime.Object) api.ResourceList {
return g.UsageFunc(object)
}

UsageStats()

UsageStats()可以计算出某命名空间下某类对象的资源使用情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func (g *GenericEvaluator) UsageStats(options quota.UsageStatsOptions) (quota.UsageStats, error) {
// default each tracked resource to zero
result := quota.UsageStats{Used: api.ResourceList{}}
for _, resourceName := range g.MatchedResourceNames {
result.Used[resourceName] = resource.MustParse("0")
}
//***获取资源***//
items, err := g.ListFuncByNamespace(options.Namespace, api.ListOptions{
LabelSelector: labels.Everything(),
})
if err != nil {
return result, fmt.Errorf("%s: Failed to list %v: %v", g.Name, g.GroupKind(), err)
}
for _, item := range items {
// need to verify that the item matches the set of scopes
matchesScopes := true
for _, scope := range options.Scopes {
if !g.MatchesScope(scope, item) {
matchesScopes = false
}
}
// only count usage if there was a match
//***计算并累加资源使用量***//
if matchesScopes {
result.Used = quota.Add(result.Used, g.Usage(item))
}
}
return result, nil
}

PodEvaluator

上小节介绍了Evaluator,在这小节将以PodEvaluator。PodEvaluator可以计算Pod的所需资源量。
PodEvaluator定义在/pkg/quota/evaluator/core/pods.go中,其本身就是一个Evaluator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//***pod资源统计器***//
func NewPodEvaluator(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Evaluator {
computeResources := []api.ResourceName{
api.ResourceCPU,
api.ResourceMemory,
api.ResourceRequestsCPU,
api.ResourceRequestsMemory,
api.ResourceLimitsCPU,
api.ResourceLimitsMemory,
}
//***与pod相关的所有资源***//
allResources := append(computeResources, api.ResourcePods)
//***用来获取具体namespace下的pods***//
listFuncByNamespace := listPodsByNamespaceFuncUsingClient(kubeClient)
if f != nil {
listFuncByNamespace = generic.ListResourceUsingInformerFunc(f, unversioned.GroupResource{Resource: "pods"})
}
return &generic.GenericEvaluator{
Name: "Evaluator.Pod",
InternalGroupKind: api.Kind("Pod"),
//***支持的操作有Create,需要更新allResourcces***//
InternalOperationResources: map[admission.Operation][]api.ResourceName{
admission.Create: allResources,
// TODO: the quota system can only charge for deltas on compute resources when pods support updates.
// admission.Update: computeResources,
},
GetFuncByNamespace: func(namespace, name string) (runtime.Object, error) {
return kubeClient.Core().Pods(namespace).Get(name)
},
ConstraintsFunc: PodConstraintsFunc,
大专栏  resourcequota分析(一)-evaluator-v1.5.2line"> MatchedResourceNames: allResources,
MatchesScopeFunc: PodMatchesScopeFunc,
UsageFunc: PodUsageFunc,
ListFuncByNamespace: listFuncByNamespace,
}
}

这里要着重说下listFuncByNamespace,有listPodsByNamespaceFuncUsingClient和ListResourceUsingInformerFunc两种,而且ListResourceUsingInformerFunc优先级更高,具体由NewPodEvaluator()的参数来控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//***生成pod list获取函数***//
func listPodsByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
// unfortunately, dynamic client works with Unstructured objects, and when we calculate Usage, we require
// structured objects.
//***可以获取某namespace下的pods***//
return func(namespace string, options api.ListOptions) ([]runtime.Object, error) {
itemList, err := kubeClient.Core().Pods(namespace).List(options)
if err != nil {
return nil, err
}
results := make([]runtime.Object, 0, len(itemList.Items))
for i := range itemList.Items {
results = append(results, &itemList.Items[i])
}
return results, nil
}
}
1
2
3
4
5
6
7
8
9
10
// ListResourceUsingInformerFunc returns a listing function based on the shared informer factory for the specified resource.
func ListResourceUsingInformerFunc(f informers.SharedInformerFactory, groupResource unversioned.GroupResource) ListFuncByNamespace {
return func(namespace string, options api.ListOptions) ([]runtime.Object, error) {
informer, err := f.ForResource(groupResource)
if err != nil {
return nil, err
}
return informer.Lister().ByNamespace(namespace).List(options.LabelSelector)
}
}

PodUsageFunc()

PodUsageFunc()函数用来计算Pod的所需资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//***计算pod的资源使用量***//
func PodUsageFunc(object runtime.Object) api.ResourceList {
pod, ok := object.(*api.Pod)
if !ok {
return api.ResourceList{}
}
// by convention, we do not quota pods that have reached an end-of-life state
if !QuotaPod(pod) {
return api.ResourceList{}
}
// TODO: fix this when we have pod level cgroups
// when we have pod level cgroups, we can just read pod level requests/limits
requests := api.ResourceList{}
limits := api.ResourceList{}
//***统计requests和limits***//
for i := range pod.Spec.Containers {
requests = quota.Add(requests, pod.Spec.Containers[i].Resources.Requests)
limits = quota.Add(limits, pod.Spec.Containers[i].Resources.Limits)
}
// InitContainers are run sequentially before other containers start, so the highest
// init container resource is compared against the sum of app containers to determine
// the effective usage for both requests and limits.
for i := range pod.Spec.InitContainers {
requests = quota.Max(requests, pod.Spec.InitContainers[i].Resources.Requests)
limits = quota.Max(limits, pod.Spec.InitContainers[i].Resources.Limits)
}
return podUsageHelper(requests, limits)
}
//***根据收集到的requests和limits生成result***//
func podUsageHelper(requests api.ResourceList, limits api.ResourceList) api.ResourceList {
result := api.ResourceList{}
//***占用1个pod数量配额***//
result[api.ResourcePods] = resource.MustParse("1")
if request, found := requests[api.ResourceCPU]; found {
result[api.ResourceCPU] = request
result[api.ResourceRequestsCPU] = request
}
if limit, found := limits[api.ResourceCPU]; found {
result[api.ResourceLimitsCPU] = limit
}
if request, found := requests[api.ResourceMemory]; found {
result[api.ResourceMemory] = request
result[api.ResourceRequestsMemory] = request
}
if limit, found := limits[api.ResourceMemory]; found {
result[api.ResourceLimitsMemory] = limit
}
return result
}

GenericRegistry

如PodEvaluator这样的Evaluator有非常多个,所以需要有一个地方来管理这些Evaluator,这个管理Evaluator的就是GenericRegistry。
GenericRegistry定义在/pkg/quota/generic/registry.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
// GenericRegistry implements Registry
type GenericRegistry struct {
// internal evaluators by group kind
InternalEvaluators map[unversioned.GroupKind]quota.Evaluator
}
```
可以看出,GenericRegistry中有字段InternalEvaluators,里面记录了GK和对应Evaluator的映射关系。可以通过Evaluators()方法获取InternalEvaluators。
``` Go
// Evaluators returns the map of evaluators by groupKind
func (r *GenericRegistry) Evaluators() map[unversioned.GroupKind]quota.Evaluator {
return r.InternalEvaluators
}

GenericRegistry的生成函数定义在/pkg/quota/evaluator/core/registry.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// NewRegistry returns a registry that knows how to deal with core kubernetes resources
// If an informer factory is provided, evaluators will use them.
func NewRegistry(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Registry {
pod := NewPodEvaluator(kubeClient, f)
service := NewServiceEvaluator(kubeClient)
replicationController := NewReplicationControllerEvaluator(kubeClient)
resourceQuota := NewResourceQuotaEvaluator(kubeClient)
secret := NewSecretEvaluator(kubeClient)
configMap := NewConfigMapEvaluator(kubeClient)
persistentVolumeClaim := NewPersistentVolumeClaimEvaluator(kubeClient, f)
return &generic.GenericRegistry{
InternalEvaluators: map[unversioned.GroupKind]quota.Evaluator{
pod.GroupKind(): pod,
service.GroupKind(): service,
replicationController.GroupKind(): replicationController,
secret.GroupKind(): secret,
configMap.GroupKind(): configMap,
resourceQuota.GroupKind(): resourceQuota,
persistentVolumeClaim.GroupKind(): persistentVolumeClaim,
},
}
}

可以看出,NewRegistry()会把PodEvaluator, ReplicationControllerEvaluator, ResourceQuotaEvaluator, SecretEvaluator, ConfigMapEvaluator, PersistentVolumeClaimEvaluator注册到GenericRegistry。

入口

整个Evaluator的入口定义在/pkg/quota/install/registry.go中:

1
2
3
4
5
6
// NewRegistry returns a registry of quota evaluators.
// If a shared informer factory is provided, it is used by evaluators rather than performing direct queries.
func NewRegistry(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Registry {
// TODO: when quota supports resources in other api groups, we will need to merge
return core.NewRegistry(kubeClient, f)
}

这里的core.NewRegistry()就是上面的NewRegistry(),返回GenericRegistry。得到GenericRegistry后,通过调用Evaluators()方法,即可获取全部的Evaluator。

resourcequota分析(一)-evaluator-v1.5.2的更多相关文章

  1. Hadoop随笔(二):Hadoop V1到Hadoop V2的主要变化

    一.消失的概念与新鲜的名词 Hadoop V2相对于Hadoop V1的变化主要在于资源管理和任务调度,计算模型仍然保持map/reduce的模型.资源管理和任务调度的变化导致了工作流程的变化,一些概 ...

  2. JDBC性能分析与优化

    JDBC性能分析与优化V1.0http://www.docin.com/p-758600080.html

  3. snmp数据包分析

    今天看了一下snmp数据包的报文格式,用wireshark抓了两个数据包来分析. 先说说snmp get-request的书报包格式吧,get-next-request,get-response,se ...

  4. Hadoop2源码分析-MapReduce篇

    1.概述 前面我们已经对Hadoop有了一个初步认识,接下来我们开始学习Hadoop的一些核心的功能,其中包含mapreduce,fs,hdfs,ipc,io,yarn,今天为大家分享的是mapred ...

  5. 安装php xdebug调试工具及性能分析工具webgrind for windows

    安装php xdebug调试工具及性能分析工具webgrind for windows 第一步:查看php版本等信息 phpinfo(); 上面是 x86 NTS VC14 第二步: 下载xdebug ...

  6. C打印函数printf的一种实现原理简要分析

    [0]README 0.1)本文旨在对 printf 的 某一种 实现 原理进行分析,做了解之用: 0.2) vsprintf 和 printf.c 的源码,参见 https://github.com ...

  7. k8s garbage collector分析(1)-启动分析

    k8s garbage collector分析(1)-启动分析 garbage collector介绍 Kubernetes garbage collector即垃圾收集器,存在于kube-contr ...

  8. k8s deployment controller源码分析

    deployment controller简介 deployment controller是kube-controller-manager组件中众多控制器中的一个,是 deployment 资源对象的 ...

  9. k8s replicaset controller分析(1)-初始化与启动分析

    replicaset controller分析 replicaset controller简介 replicaset controller是kube-controller-manager组件中众多控制 ...

随机推荐

  1. Java常用的公共方法

    --获取规字符串中的指定名称的某个字段值 1.public String getValueByName(String params,String name) --用于通过表单选中的复选框获取它的值(j ...

  2. python画图例子代码

    matplotlib包,使得python可以使用类似matlab的命令 双坐标,子图例子 fig, axes = plt.subplots( 2,1, figsize=(14, 14) ) ax = ...

  3. c语言中getchar的用法

    /************************************************************************* > File Name: getchar2. ...

  4. << 和>> 的计算公式

    在java中,一个数左移n位,就是将这个数乘以2的n次方,右移就是将这个数除以2的n次方. 如: 8>>2 = 2  (8/2^2) 15 << 3 = 120  (15*(2 ...

  5. VBA/VB6/VBS/VB.NET/C#/Python/PowerShell都能调用的API封装库

    API函数很强大,但是声明的时候比较繁琐. 我开发的封装库,包括窗口.键盘.鼠标.消息等常用功能.用户不需要添加API函数的声明,就可以用到API的功能. 在VBA.VB6的引用对话框中引用API.t ...

  6. Navicat 12 无限期试用

    最近发现navicat12又过期了,以前的是用的破解软件,然后是到1899年过期哈哈哈哈哈哈.重装了系统后,软件也重装了,发现破解软件不好使了,就先试用了,现在到期了.很是难受,这可咋整,不过在网上看 ...

  7. 如何在Windows服务器上新建一个Powershell.ps1的定时任务

    背景: 有一些一次性的Powershell脚本,需要我们每次都手动执行一下,为了简化工作,现在我们可以使用Windows自带的计划任务,进行定时执行. 该教程是在Windows Server 2012 ...

  8. SQL热备原理

  9. python数据类型:Number数字

    Python Number数据类型用于存储数值 数据类型是不允许改变的,如果改变Number数据类型的值,将从新分配内存空间 整型(int):整型或整数,是正或者负整数,不带小数点 长整型(long) ...

  10. [LC] 226. Invert Binary Tree

    Invert a binary tree. Example: Input: 4 / \ 2 7 / \ / \ 1 3 6 9 Output: 4 / \ 7 2 / \ / \ 9 6 3 1 /* ...