简介

Kubernetes是一个强大的编排工具,可以用来很方便的管理许多台机器,为了使机器的资源利用率提高,同时也尽可能的把压力分摊到各个机器上,这个职责就是由scheduler来完成的。

Kubernetes scheduler是一个策略丰富、拓扑感知、工作负载特定的功能,显著影响可用性、性能和容量。

为了能更好的使用它,所以从源码的角度,对它进行一个全方位的分析与学习。

scheduler的功能不多,但逻辑比较复杂,里面有很多考虑的因素,总结下来大致有如下几点:

  • Leader选主,确保集群中只有一个scheduler在工作,其它只是高可用备份实例。通过endpoint:kube-scheduler作为仲裁资源。

  • Node筛选,根据设置的条件、资源要求等,匹配出所有满足分配的Node结点。

  • 最优Node选择。在所有满足条件的Node中,根据定义好的规则来打分,取分数最高的。如果有相同分数的,则采用轮询方式。

  • 为了响应高优先级的资源分配,增加了抢占功能。scheduler有权删除一些低优先级的Pod,以释放资源给高优先级的Pod来使用。

功能说明

代码看下来比较困难,下面将分几个场景来描述scheduler工作的过程:

1、环境说明(假设3台机器,分别是8C16G)

场景一: 资源分配——最基本的功能

2、先分配一个请求2C4G的Pod: A

场景二:机器负载均衡——评分机制

3、再分配一个请求2C4G的Pod:B(尽管node1上还有空闲资源可分配B,但node2和node3空闲资源更多,打分更高,所以分配到了node2<选择node2还是node3,是由schedule轮询选择的>。)

4、同理,如果再分配一个C,scheduler会优先分配到node3上

场景三:资源抢占——特权机制

5、现在3个Node上都分配了2C4G,就是都剩余6C12G,如果我这个时候分配一个8C12G的Pod:D,在同优先级的情况下,D将不会分配,处于Pending状态,因为三台机器都资源不足。

6、如果这个时候,我给D设置一个高的优先级,schedule会删除一台机器上的Pod,比如A,然后资源足够了,将D分配到node1上,再将A分配到node2或node3上。(这里分配是一个类似,因为三台都是一样的)

7、下面实战一把,详细试验下scheduler的抢占过程:

我有一个Deployment,有3个复本,分别分配到两台机器上。(为什么用这个例子,是为了说明,抢占一定会发生在10-10-40-89上,因为要删除的Pod最少)

这个时候,我创建一个高优先级的Deployment:

快速查询,能看到下面的阶段:

第一步,将要分配的testpc-745cc7867-fqbp2设置为“提名Pod”,这个名字后面会再出现,同时删除原10-10-40-89上的testpod,由于截的比较慢,下图中新的testpod已经在10-10-88-99上创建了。

第二步,提名Pod将会分配到对应的结点上(等待Terminating状态的Pod释放完资源后)。

第三步,资源足够,Pod正常Running。

最后展示下watch情况下的事件:

测试我共有两个yaml文件,如下:

testpod.yaml:

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
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  labels:
    k8s-app: testpod
  name: testpod
spec:
  progressDeadlineSeconds: 600
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: testpod
  template:
    metadata:
      labels:
        k8s-app: testpod
    spec:
      containers:
      - image: nginx:1.17
        imagePullPolicy: IfNotPresent
        name: nginx
        ports:
        - containerPort: 80
          name: nginx
          protocol: TCP
        resources:
          requests:
            cpu: 1
            memory: 2Gi

testpc.yaml:

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
apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000000
globalDefault: false
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  labels:
    k8s-app: testpc
  name: testpc
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: testpc
  template:
    metadata:
      labels:
        k8s-app: testpc
    spec:
      containers:
      - image: nginx:1.17
        imagePullPolicy: IfNotPresent
        name: nginx
        ports:
        - containerPort: 80
          name: nginx
          protocol: TCP
        resources:
          requests:
            cpu: 6
            memory: 2Gi
      priorityClassName: high-priority

场景四:关系户——亲和与反亲和

scheduler在分配Pod时,考虑的要素很多,亲和性和反亲和,是一个比较常用的,在这里做一个典型来讲讲。

比如在上图中,我新的Pod:D,要求不能和A在一台机器上,和B的互斥打分是100,和C的互斥打分是10。表示说,D一定不能和A在一台机器,尽可能不和B、C在同一台机器,实在没办法时(资源不足),D更倾向于和C在一起。

样例:

1
2
3
4
5
6
7
8
9
10
11
podAntiAffinity:
  preferredDuringSchedulingIgnoredDuringExecution:
  - weight: 100
    podAffinityTerm:
      labelSelector:
        matchExpressions:
        key: security
          operator: In
          values:
          - S2
      topologyKey: kubernetes.io/hostname

通过对这四个应用场景的分析,对它的功能有了一个初步的了解。要想更全面、深入的了解它的功能,需要从它的源码来着手。下面将从源码层面来做深入分析。

代码分析

scheduler总体结构

scheduler的配置,基本都是采用默认配置,图中列出了它的配置加载流程,基本都是加载它自身的默认配置。

server.Run为它的主体逻辑,之后会详细讲解。

重要配置讲解

图中,单独列出了两个config配置:

1、disablePreemption:

scheduler有个抢占功能。当Pod调度发现无可用资源时,它会将比该Pod优先级低的Pod删除,以释放资源给它来调度。disablePreemption默认为false,表示开启抢占,如果需要关闭,则设置为true。

2、既然说到优先级,所以我还列出来了优先级的设置方法。

Kubernetes中有个单独的优先级的资源,叫:PriorityClass,通过下面这个yaml,能创建一个PriorityClass。

1
2
3
4
5
6
7
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only."

然后可将这个PriorityClass关联到Pod上:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
 priorityClassName: high-priority

这样就完成的Pod优先级的设置。如果不设置,Pod默认是同一优先级(为0)。

特别注意:

static Pod比较特殊,需要直接设置priority,因为kubelet是根据priority来判断。

scheduler启动流程

通过深入分析server.Run,可看到如下流程:

server.Run还是有一部分的配置处理流程。

schedulerConfig中,根据默认的参数,加载了两大块内容:predicate、priority函数。

  • predicate函数用于做Pod是否可分配到Node上的检查函数。

  • priority函数,则用于选优。当可分配的Node有多个时,这个时候就会根据priority函数来给node打分,最终调度到分数最高的Node上。

Kubernetes提供了这些默认的判断函数:

predicate:

1、CheckNodeConditionPredicate

we really don’t want to check predicates against unschedulable nodes.

检查Node状态:是否处于可调度状态等。

-----> 遍历nodeInfo中Node的所有状况:

  • 如果Node类型为ready,并且状态不是True,则认为结点为notReady

  • 如果Node类型为OutOfDisk,并且状态不是False,则认为结点OutOfDisk

  • 如果Node类型为NetworkUnavailable,并且状态不是False,则认为结点状态为:NetworkUnavailable

检查Node的spec,如果是UnSchedulable,则认为结点为UnSchedulable。

以上检查都通过,则返回匹配成功。

2、PodFitsHost

we check the pod.spec.nodeName.

检查pod.spec.nodeName是否匹配。

----> 如果Pod未指定NodeName,则返回匹配成功。

检查Node的名字,如果与Pod指定的同名,则匹配成功,否则返回:nodeName不匹配。

3、PodFitsHostPorts

we check ports asked on the spec.

检查服务端口是否被占用。

-----> 如果元数据metadata中有定义需要的podPorts,则直接从元数据中取,否则从Pod的所有容器中获取需要的port。

如果需要的port为空,则返回匹配成功。

从nodeInfo中获取当前已经使用的port,如果有冲突,则返回:端口不匹配,否则返回匹配成功。

4、PodMatchNodeSelector

check node label after narrowing search.

检查label是否匹配。

------> 如果Pod中定义了NodeSelector,则根据选择来匹配Node的labels,如果不匹配,则返回NodeSelectorNotMatch。

如果Pod的Affinity中定义了NodeAffinity,则检查结点亲和关系:

  • 如果未定义requiredDuringSchedulingIgnoredDuringExecution,则直接返回匹配。

  • 如果定义了requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,则里面有一个匹配,则匹配。否则认为不匹配。

特别的:如果nodeSelectorTerms为nil,则全不匹配;如果nodeSelectorTerms不为nil,但是空的切片,则全不匹配;同样,nodeSelectorTerms中的MatchExpressions,如果为nil或者是空切片,也不匹配。

5、PodFitsResources

this one comes here since it’s not restrictive enough as we do not try to match values but ranges.

-----> 检查Node的allowedPodNumber是否超过,如果超过,增加超限错误(此处未直接返回,会把所有错误检查完一次性返回)。

检查元数据中是否有定义podRequest、ignoredExtendedResources,如果定义了,则从元数据中取。否则从Pod中每个容器中取:先检查所有container中所有需要的资源总合,再检查initContainer中,如果有资源比总合还大,则取较大的为所需要的资源。

如果需要的资源都为0,则返回检查结果。

获取Node的可用资源,检查需要新申请的资源+已申请的资源是否超过可用资源,如果超过,则记录资源不足。

检查所有Pod扩展资源,并判断扩展资源是否需要检查(ignoredExtendedResources),如果需要检查,则判断资源是否足够,不足够则记录失败。

返回检查结果(如果无失败,是检查成功)。

6、NoDiskConflict

Following the resource predicate, we check disk.

----> 遍历Pod所有存储、Node下的所有Pod,检查是否有存储冲突:

如果Pod无存储(无GCE、AWS、RBD、ISCSI),则检查通过。

7、PodToleratesNodeTaints

check toleration here, as node might have toleration.

-----> 检查结点是否容忍taint环境:

参数:Pod中定义的容忍规则:tolerations,Node中的环境状态:taints,筛选规则:取effect为NoSchedule、NoExecute的。

如果Node无taints,返回匹配成功。

遍历所有taints,如果taint不满足筛选规则,则跳过检查。

遍历所有的容忍规则,检查是否有规则是允许结点的taint状态。检查步骤:

  1. 如果effect为空,则检查通过,否则要相同。

  2. 如果key为空,则检查通过,否则要相同。

  3. 如果operator为Exists,则检查通过,如果为空或者是Equal,则要相同,否则不通过。

8、PodToleratesNodeNoExecuteTaints

check toleration here, as node might have toleration.

-----> 检查规则同上相似,只是筛选规则变了:取effect为NoExecute的。

9、CheckNodeLabelPresence

labels are easy to check, so this one goes before.

------> 检查label是否存在,不关心值。可设置label存在与不存在。

只有在scheduler.CreateFromConfig(policy)才会初始化该检查,在RegisterCustomFitPredicate中注册,默认无该检查。

10、checkServiceAffinity

-----> 检查服务类同关系。

如果一个Pod的服务调度到有label:"region=foo"的Node,之后有相同服务的Pod都会调度到该Node。

11、MaxPDVolumeCountPredicate

-----> 检查挂载的卷个数是不是超标,只支持:ESB:39,GCE:16,AzureDisk:16。

12、VolumeNodePredicate

-----> 无

13、VolumeZonePredicate

-----> 检查存储区域划分:

检查Node中是否有label:failure-domain.beta.kubernetes.io/zone或者failure-domain.beta.kubernetes.io/region,如果有,则检查Pod存储情况。

遍历Pod需要的存储信息:

根据PVC名字获取PVC信息,取出PVC对应的PV名字,如果没有名字(表示还未绑定PV),获取PVC的StorageClassName,如果处理正在绑定中,则跳过不检查,否则返回匹配失败(因为PVC绑定失败)。

绑定成功的,根据pvName获取对应的PV信息,检查PV的标签,如果PV有上面两个标签(zone、region),检查PV的值中(值可能有多个,用__分隔),是否包含Node对应标签的值,如果没有包含,则返回匹配失败。

14、CheckNodeMemoryPressurePredicate

doesn’t happen often.

-----> 检查Node内存压力。

15、CheckNodeDiskPressurePredicate

doesn’t happen often.

16、InterPodAffinityMatches

Most expensive predicate to compute.

默认有这些打分函数(priority):

SelectorSpreadPriority:根据相同的RC和服务拆分,使每个Node具有相同服务或RC的Pod尽量少,spreads pods by minimizing the number of pods (belonging to the same service or replication controller) on the same node.

InterPodAffinityPriority:根据Pod共性来分配,pods should be placed in the same topological domain (e.g. same node, same rack, same zone, same power domain, etc.).

LeastRequestedPriority:选择比较闲的node,Prioritize nodes by least requested utilization.

BalancedResourceAllocation:从资源分配平衡性来考虑分配,Prioritizes nodes to help achieve balanced resource usage.

NodePreferAvoidPodsPriority:用于用户自定义分配,权重10000起,方便用户来指定。0的时候不起作用。用户通过这个来指定:scheduler.alpha.kubernetes.io/preferAvoidPods Set this weight large enough to override all other priority functions.

NodeAffinityPriority:根据结点关系来分配,Prioritizes nodes that have labels matching NodeAffinity.

TaintTolerationPriority:根据pod设置的容忍项来分配,Prioritizes nodes that marked with taint which pod can tolerate.

最终,死循环进入:scheduleOne,真正开始schedule的调度流程。

Schedule调度流程

先讲主流程:

主流程分为以下8步:

  1. 从Pod队列中取出一个需要调度的Pod。

  2. 尝试调度该Pod。

  3. 调度失败,则尝试抢占Pod。

  4. 调度成功后,尝试做volumes绑定。

  5. 由于reserve插件暂时未启用,暂未分析。

  6. 尝试将Pod分配到Node上。

  7. 真正实现绑定。第4步和第6步中,都只是对schedule的cache的操作,先确保对cache的操作能完成,最终在第7步,异常实现将cache中的修改应用到apiserver中。如果应用失败,会将pod的分配信息从cache中清除,重新进行scheduler。

  8. 最复杂也最核心的,就是第2步和第3步,下面分别进行分析。

调度Pod流程

调度Pod,就是尝试将Pod分配到Node上,流程如下:

共有7点,将逐步分析:

  1. Pod基本检查,检查Pod是否有了对应的PVC,这里只是检查PVC是否存在,不关心绑定过程。

  2. 取出所有Node列表。

  3. 将nodeInfo应用到缓存中。全局nodeInfo中保存了当前Node的真实数据信息,而cache中会有调度过程的假设分析的信息。

  4. 检查Pod是否可调度到Node上,返回可调度的Node列表。

    a) 这里的检查,是针对前面初始化时,注册的predicate函数,如果有不符合,则认为不可调度。

    b) 这里会尝试两次,之所以两次,是因为有“提名Pod”的存在。暂时先不管“提名Pod”哪来的,后面会讲到。提名Pod,就是说,这个Pod已经分配到Node上,但它还未应用到Kubernetes环境,目前只是占着这个坑位,要调度的Pod,在调度的过程中,也需要考虑它所占的资源。

    c) 第一次时,会先把优先级大于当前Pod的提名Pod分配到Node中(添加到一个临时的nodeInfo中),然后检查所有的predicat函数是否通过。

    d) 第二次时,不添加提名Pod,再检查所有的predicate函数。之所以有第二次,是因为提名Pod实际还并不存在,有些Pod亲和性可能会判断有误。

    e) 当然,如果没有提名Pod,则不需要第二次判断。

  5. 如果找不到,则返回失败。如果只找到一个,则返回该Node。

  6. 当找到多个Node时,会去给Node打分,打分规则如下:

    a) 如果没有定义打分规则,则返回所有分数都为1。schedule默认是有打分函数的,前面初始化中有讲。

    b) 运行早期老版本的打分函数。早期就是单纯的一个function,运行后得到打分结果。

    c) 新版本,将打分函数拆分成两步,map和reduce,先按16个并发运行map,之后运行reduce统计执行结果。

    d) 这里还预留了扩展支持。

    e) 最终返回打分结果。

  7. 根据打分结果,选择Node。

    a) 先取出得分最高的Node列表。

    b) 然后按round-robin的方式选择Node。

由于相同最高分的Node可能有多个,genericScheduler采用round-robin的方式:它自己记录一个全局的lastNodeIndex,如何num为当前有相同最高分的节点数,则用lastNodeIndex % num来选取本次节点的下标,之后lastNodeIndex加1,实现轮询调度。

到此,Pod的调度流程分析完成。当中有个特别的东西:提名Pod(NominatedPod),它的出现和下面讲的抢占流程有关。

Pod抢占流程

抢占的流程,比调度复杂一些,主要分两大步:抢占分析和抢占。第一步是检查是不是能完成抢占,第二步是执行抢占(删除Pod)。

抢占检查

  1. 检查Pod是否可以发起抢占:如果Pod是提名Pod(已经预分配到Node),并且该Node上有处于terminating的Pod p,并且p的优先级小于当前Pod,则不允许发起抢占。

  2. 获取所有Node清单。

  3. 获取可能的Node。检查调度失败原因,如果是nodeNotReady这种原因,则Node不参与抢占。这些都是不参与抢占的:predicates.ErrNodeSelectorNotMatch,predicates.ErrPodAffinityRulesNotMatch,predicates.ErrPodNotMatchHostName,predicates.ErrTaintsTolerationsNotMatch,predicates.ErrNodeLabelPresenceViolated,predicates.ErrNodeNotReady,predicates.ErrNodeNetworkUnavailable,predicates.ErrNodeUnderDiskPressure,predicates.ErrNodeUnderPIDPressure,predicates.ErrNodeUnderMemoryPressure,predicates.ErrNodeUnschedulable,predicates.ErrNodeUnknownCondition,predicates.ErrVolumeZoneConflict,predicates.ErrVolumeNodeConflict,predicates.ErrVolumeBindConflict
  4. 如果可抢占的Node没有,则结束。

  5. 获取pdb列表:pdb is PodDisruptionBudget. 这个是预算的定义,比如statefulset定义了3个复本,而我们定义了,允许其中1个Pod可以挂掉。

  6. 获取通过抢占(删除一些Pod),能完成调度的Node列表。

    a) 将比当前Pod优先级低的Pod全部从nodeInfoCopy中删除,然后尝试去调度。b) 如果调度失败,则表示无法抢占。(因为不能删除比它优先级高的)c) 将要删除的Pod,根据pdb进行拆分:nonViolatingVictim和violatingVictim。说明见图中。d) 然后尝试将violatingVictim中的Pod一个个加进去,尝试能不能调度。numViolatingVictim中记录不通过数。e) 然后尝试将nonViolatingVictim中的Pod一个个加进去,尝试能不能调度。victims记录不通过的Pod信息。f) 返回victims和numViolatingVictim。

  7. extenders扩展保留。
  8. 从可抢占的Node列表中,选择最合适的一个Node。按如下规则进行选择:a) node pdb violations最小。就是上面返回的numViolatingVictimb) 如果只有一个Node满足,则返回该Nodec) 比较Node中victims中优先级的最高值,取最小的那个。最高:取的是单个Node中,优先级的最高值。最小:取的是所有Node中的最小值d) 如果只有一个,则返回该Node。e) 取Node中victims优先级总和最小的。f) 如果只有一个,则返回该Node。g) 取Node中victims的Pod数最小的。h) 返回第一个。
  9. 如果无合适的,则结束。
  10. 获取比当前优先级小的提名Pod。
  11. 返回Node信息,需要删除的Pod列表,优先级小的提名Pod。

到此,抢占检查结束。得到期望调度的Node、要调度到这个Node上,需要删除的Pod列表、以及比当前Pod优先级小的提名Pod。

抢占执行流程(找到了期望的Node才会进入)

  1. 将当前Pod,变更为提名Pod,对应的Node为期望的Node。这里就是提名Pod出现的原因。
  2. 将提名Pod信息更新到apiServer。
  3. 遍历victims(抢占流程返回的需要删除的Pod列表),删除Pod,并记录event。
  4. 遍历nominatedPodsToClear(抢占返回的比当前Pod优先级小的提名Pod),清空提名Pod配置,并更新apiServer。

到此,调度流程分析完成。

参考:https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/

【转】Kubernetes scheduler学习笔记的更多相关文章

  1. kubernetes CRD学习笔记

    前言 最近在极客时间订阅了kubernetes的专栏,这篇文章是想记录一下自己学习CRD(custom resource definition)的过程,加深一下记忆. 准备工作 首先安装一下我们用的g ...

  2. K8S学习笔记之二进制的方式创建一个Kubernetes集群

    0x00 单节点搭建和简述 minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环境. 官方地址: ...

  3. Contour 学习笔记(一):使用 Contour 接管 Kubernetes 的南北流量

    原文链接:Contour 学习笔记(一):使用 Contour 接管 Kubernetes 的南北流量 在 Kubernetes 中运行大规模以 Web 为中心的工作负载,最关键的需求之一就是在 L7 ...

  4. Kubernetes 学习笔记(一):基础概念

    个人笔记,仅本人查阅使用,不保证正确. 零.微服务 微服务架构专注于应用解耦合,通过将应用彻底地组件化和服务化,每个微服务只包含一个非常小的功能,比如权限管理.日志收集等等.由这一组微服务组合起来,提 ...

  5. Kubernetes学习笔记(四):服务

    服务介绍 服务是一种为一组相同功能的pod提供单一不变接入点的资源.当服务存在时,他的IP和端口不会改变.客户端通过IP和端口建立连接,这些连接会被路由到任何一个pod上.如此,客户端不需要知道每个单 ...

  6. Kubernetes学习笔记(八):Deployment--声明式的升级应用

    概述 本文核心问题是:如何升级应用. 对于Pod的更新有两种策略: 一是删除全部旧Pod之后再创建新Pod.好处是,同一时间只会有一个版本的应用存在:缺点是,应用有一段时间不可用. 二是先创建新Pod ...

  7. Kubernetes学习笔记之认识Kubernetes组件

    前言:笔记知识点来源于Kubernetes官方文档说明,链接:https://kubernetes.io/docs/concepts/overview/components/ ,本记录仅仅是学习笔记记 ...

  8. Kubernetes权威指南学习笔记(一)

    https://blog.csdn.net/keysilence1/article/details/70239717 概念 Kubernetes是谷歌严格保密十几年的秘密武器——Borg的一个开源版本 ...

  9. Kubernetes全栈架构师(二进制高可用安装k8s集群部署篇)--学习笔记

    目录 二进制高可用基本配置 二进制系统和内核升级 二进制基本组件安装 二进制生成证书详解 二进制高可用及etcd配置 二进制K8s组件配置 二进制使用Bootstrapping自动颁发证书 二进制No ...

随机推荐

  1. ctfhub技能树—文件上传—文件头检查

    打开靶机 尝试上传一个php文件 抓包修改 放包 制作图片马 上传图片马,并修改文件类型为png 测试连接 查找flag 成功拿到flag

  2. ctfhub技能树—sql注入—Cookie注入

    手注 打开靶机 查看页面信息 查找cookie 测试是否为cookie注入 抓包 尝试注入 成功查询到数据库名 查询表名 查询字段名 查询字段信息 成功拿到flag sqlmap 查询数据库名 pyt ...

  3. WMIC 查看bios配置信息

    如何查看我们的主板上的BIOS信息呢?有办法,不用安装任何软件,只需要windows自带的命令提示符就行,哈哈 WMIC BIOS LIST FULL /FORMAT:VALUE 如果第一次使用wmi ...

  4. Jmeter二次开发——自定义函数

    在之前的博文中,Jmeter二次开发--基于Java请求,已介绍了Jmeter二次开发的基础情况,上次分享的是java请求开发,今天来分享下Jmeter中的函数开发.聊到Jmeter的函数,知道Jme ...

  5. atlas读写分离

    Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bug ...

  6. ichartjs插件的使用

    项目中可能会用到饼状图.柱状图.环形图等,ichartjs是一个很不错的插件,体量小,只需引入ichart.1.2.1.min.js即可满足基础需求,github下载地址是:https://githu ...

  7. 1、进程管理常用命令和进程ID

    常用命令 1. ps (英文全拼:process status)命令用于显示当前进程的状态,类似于 windows 的任务管理器. 详细介绍参照:https://www.runoob.com/linu ...

  8. java虚拟机入门(五)- 常见垃圾回收器及jvm实现

    上节讲完了垃圾回收的基础,包括java的垃圾是什么,如何寻找以及常用的垃圾回收算法,那么那么多的理论知识讲完了,具体是什么样的东西在做着回收垃圾的事情呢?我们接下来就好好聊聊jvm中常用的垃圾回收器. ...

  9. 无法获取 vmci 驱动程序版本: 句柄无效。 驱动程序 vmci.sys 版本不正确。请尝试重新安装 VMware Workstation。 打开模块DevicePowerOn电源失败。

    1.别打开电源,然后到虚拟机安装文件夹内.2.找到你的虚拟机系统文件中后缀为vmx的文件,右击用记事本或者Notepad++打开.2.搜索找到vmci0.present='TRUE',字段,把true ...

  10. IGXE搬砖项目

    主要的赚钱方式和倒爷其实是差不多的,自动检测igxe平台上价格与buff相差8.5%以上的饰品,按照历史价格进行一定的过滤,防止翻车,然后自动购买. 2019年经历了十几次的改进以对抗同行的脚本,到1 ...