前言

“大伙得眼里有活,看见同事忙的时候要互相帮助,这样我们团队才能快速成长,出成绩,多干点活没坏处的,领导都看在眼里记在心里,不会亏待大伙。”

看到这也许你还有点懵,不是要讲k8s的HorizontalPodAutoscaler?怎么以一段经典pua开头,哈哈,别着急,接着往下看。

“高可用、高并发、大流量”这些曾经似乎只会出现在互联网业务中的高大上词汇,现在已然是随处可见,不管真实业务场景会不会出现,对外宣称时都会标榜这类特性,要支持这类特性有一个极其基础的能力是必须具备的,那就是扩容,而扩容一般又分为垂直扩容和水平扩容,最为广泛的属水平扩容。

水平扩容俗称加机器,对比现实工作中就是加人,加人从触发方式上来说分为主动和被动,主动就是一些热心肠(眼里有活)的同事看你太忙了过来帮你,这种概率较小,一般来说大概率是领导觉得你忙不过来了把你的活分一部分出去给其他人,这种就是被动触发加人。

回到互联网的世界中,当单机饱和了以后,就需要加机器,我经历过的公司都是运维人工操作,决策依据为一些可以体现繁忙度的监控指标,如qps、cpu利用率、内存占用等,对于一些爆炸性事件,这种人工操作就有些捉襟见肘,如大家屡见不鲜的明星头条新闻导致服务宕机的情况,假如能利用机器来自动化的感知压力进而扩容,就能更好的提高服务质量。

偶尔间发现了k8s的HorizontalPodAutoscaler可以实现自动水平扩容,就花时间简单实践了一下,在这里抛砖一波,希望能给大家带来些许帮助。

概念介绍

本节摘自k8s官网

在 Kubernetes 中,HorizontalPodAutoscaler 自动更新工作负载资源 (例如 Deployment 或者 StatefulSet), 目的是自动扩缩工作负载以满足需求。

水平扩缩意味着对增加的负载的响应是部署更多的 Pod。这与 “垂直(Vertical)” 扩缩不同,对于 Kubernetes, 垂直扩缩意味着将更多资源(例如:内存或 CPU)分配给已经为工作负载运行的 Pod。

如果负载减少,并且 Pod 的数量高于配置的最小值, HorizontalPodAutoscaler 会指示工作负载资源(Deployment、StatefulSet 或其他类似资源)缩减。

水平 Pod 自动扩缩不适用于无法扩缩的对象(例如:DaemonSet。)

HorizontalPodAutoscaler 被实现为 Kubernetes API 资源和控制器。

资源决定了控制器的行为。在 Kubernetes 控制平面内运行的水平 Pod 自动扩缩控制器会定期调整其目标(例如:Deployment)的所需规模,以匹配观察到的指标, 例如,平均 CPU 利用率、平均内存利用率或你指定的任何其他自定义指标。

HorizontalPodAutoscaler 是如何工作的?

本节摘自k8s官网

Kubernetes 将水平 Pod 自动扩缩实现为一个间歇运行的控制回路(它不是一个连续的过程)。间隔由 kube-controller-manager 的 --horizontal-pod-autoscaler-sync-period 参数设置(默认间隔为 15 秒)。

在每个时间段内,控制器管理器都会根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利用率。控制器管理器找到由 scaleTargetRef 定义的目标资源,然后根据目标资源的 .spec.selector 标签选择 Pod, 并从资源指标 API(针对每个 Pod 的资源指标)或自定义指标获取指标 API(适用于所有其他指标)。

  • 对于按 Pod 统计的资源指标(如 CPU),控制器从资源指标 API 中获取每一个 HorizontalPodAutoscaler 指定的 Pod 的度量值,如果设置了目标使用率,控制器获取每个 Pod 中的容器资源使用情况, 并计算资源使用率。如果设置了 target 值,将直接使用原始数据(不再计算百分比)。接下来,控制器根据平均的资源使用率或原始值计算出扩缩的比例,进而计算出目标副本数。

    需要注意的是,如果 Pod 某些容器不支持资源采集,那么控制器将不会使用该 Pod 的 CPU 使用率。下面的算法细节章节将会介绍详细的算法。

  • 如果 Pod 使用自定义指示,控制器机制与资源指标类似,区别在于自定义指标只使用原始值,而不是使用率。

  • 如果 Pod 使用对象指标和外部指标(每个指标描述一个对象信息)。这个指标将直接根据目标设定值相比较,并生成一个上面提到的扩缩比例。在 autoscaling/v2 版本 API 中,这个指标也可以根据 Pod 数量平分后再计算。

HorizontalPodAutoscaler 的常见用途是将其配置为从聚合 API (metrics.k8s.io、custom.metrics.k8s.io 或 external.metrics.k8s.io)获取指标。metrics.k8s.io API 通常由名为 Metrics Server 的插件提供,需要单独启动。有关资源指标的更多信息, 请参阅 Metrics Server。

对 Metrics API 的支持解释了这些不同 API 的稳定性保证和支持状态。

HorizontalPodAutoscaler 控制器访问支持扩缩的相应工作负载资源(例如:Deployment 和 StatefulSet)。这些资源每个都有一个名为 scale 的子资源,该接口允许你动态设置副本的数量并检查它们的每个当前状态。有关 Kubernetes API 子资源的一般信息, 请参阅 Kubernetes API 概念。

演练

准备测试镜像

代码逻辑很简单,创建SpringBoot工程stress-test,包含一个Controller,暴露一个接口cpu-test,占着cpu执行一分钟。

package com.example.stresstest.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import java.util.concurrent.TimeUnit; @Controller
public class GreetingController { @GetMapping("/cpu-test")
public String greeting() {
Long i = System.currentTimeMillis();
while(true){
if (System.currentTimeMillis() - i > TimeUnit.MINUTES.toMillis(1)){
break;
}
} return "finish";
}
}

将stress-test打包成镜像push到镜像仓库(我这里用的是公司内的,读者可以自行选择)。

部署Stress-test

通过resources.limit.cpu: "1"限制最大能占用的cpu为1核

kubectl create -f stress-test-deployment.ymal

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: stress-test
name: stress-test
namespace: jc-test
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 1
selector:
matchLabels:
app: stress-test
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
labels:
app: stress-test
spec:
containers:
image: xxx/stress-test.1.0
imagePullPolicy: IfNotPresent
name: stress-test
resources:
limits:
cpu: "1"
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: docker-registry
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30

创建 HorizontalPodAutoscaler

针对stress-test创建了一个HPA,监控的指标为cpu平均利用率,当cpu平均利用率到达80%以后开始自动扩容,最大副本数maxReplicas为3,当cpu平均利用率平缓以后会缩容到minReplicas。

kubectl create -f stress-test-hpa.yaml

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-stress-test
namespace: jc-test
spec:
maxReplicas: 3
metrics:
- resource:
name: cpu
target:
averageUtilization: 80
type: Utilization
type: Resource
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: stress-test

测试

看下测试之前的副本个数,只有一个

kubectl get deployment stress-test -n jc-test
NAME READY UP-TO-DATE AVAILABLE AGE
stress-test 1/1 1 1 13d

curl http://127.0.0.1:8080/cpu-test 访问测试接口,该接口会占着cpu执行一分钟,意味着cpu利用率会达到100%,大约15s以后查看副本数的变化,已经变成两个副本,多开几个窗口访问/cpu-test,最终副本数会到达3 。  

kubectl get deployment stress-test -n jc-test
NAME READY UP-TO-DATE AVAILABLE AGE
stress-test 2/2 2 2 13d

看下HPA的效果  

kubectl get hpa  hpa-stress-test--watch

一点浅见

看案例确实比较简单,但是具体要如何落地呢,这里谈谈自己的一点看法。

1.容量预估,结合业务预期通过压测等手段知道当前要部署的资源数量,比如笔者之前团队业务预期是一天1000万笔订单,而订单会分摊到早中晚的各一个小时完成,所以预估下qps=1000万/3/3600=926,通过压测单台服务能承受是qps是120,所以部署8台就足够了,但是为了防止一些突发情况,会多预留20%左右的资源,最终部署10台;

2.远取指标,以第一步压测得出的qps为例,如果服务的qps到达120,说明目前已处于饱和状态,可以拿平均qps=120来作为是否扩容的标准;

3.设置HPA参数,比如min=5,max=10,qps=120,意味着最小数量是5台,最大数量是10,也许你会问10台如果还不够用呢,这的确是一个好问题,那我再调大点?似乎合情合理,但是有没有想过你的上游能不能承受,你依赖的基础资源能不能承受,微服务一般无状态可以随意扩容,但数据库、redis可就没那么轻松了,所以说max不能只考虑自己,要全局思考,再者说如果接入层做了限流,max已经被圈定在一个可控的范围内,设置太大反而是浪费资源,综合来说max也就是第一步容量预估得出的10,再多了上游不一定能扛得住,如果确实业务增长的比较快,那就得重新做容量预估,投入更多的资源来支持。

单独的说max似乎有点鸡肋,得结合min来说,max是为扩容,min是为缩容,什么场景下才需要缩容呢?为了节省资源,服务器白天可以用来跑在线业务,到了晚上用户都休息了在线业务是不是就空闲了,这时就可以把在线业务少部署几台以备不时之需,其余的资源留给一些离线业务去用,比如T+1的报表、定时任务等,这正是min的使用场景,同样的min也不能设置太小,因为服务的启动也需要一点时间,在启动的这个过程中是不能提供服务的。

HPA的本质就是计算机世界中的pua,眼里有活-通过HPA自动加机器,节省资源-通过HPA自动减机器。  

HPA体现了一种降本增效的思想,这种思想和现实世界高度吻合,“公司不养闲人,大家得眼里有活,自动补位。”

本文只作为抛砖,啰嗦一点自己的看法,提到的知识实属皮毛,还请去k8s官网取其精华。

推荐阅读

https://mp.weixin.qq.com/s/F3JndqsH9VxNSn4mAKoMjQ   美团弹性伸缩系统的技术演进与落地实践

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ Pod 水平自动扩缩

https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/   HorizontalPodAutoscaler 演练

 

  

  

抛砖系列之k8s HorizontalPodAutoscaler(HPA)的更多相关文章

  1. 抛砖系列之redis监控命令

    前言 redis是一款非常流行的kv数据库,以高性能著称,其高吞吐.低延迟等特性让广大开发者趋之若鹜,每每看到别人发出的redis故障报告都让我产生一种居安思危,以史为鉴的危机感,恰逢今年十一西安烟雨 ...

  2. 抛砖系列之git仓库拆分工具git-filter-repo

    最近负责把团队内的git仓库做了一次分拆,解锁一个好用的工具git-filter-repo,给大伙抛砖一波,希望以后遇到类似场景时可以信手拈来. 背景 笔者团队目前是把业务相关的java项目都放到了一 ...

  3. 抛砖系列之-MySQL中的数据类型JSON

    今天介绍一个MySQL中的数据类型-JSON,相信大家对JSON都不陌生,在日常工作中使用到的频率也很高,话不多说,直接开始. 何谓JSON 看下RFC文档对于JSON的描述 1.基于 JavaScr ...

  4. 容器编排系统K8s之HPA资源

    前文我们了解了用Prometheus监控k8s上的节点和pod资源,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14287942.html:今天我们来了解下 ...

  5. .Net Core2.1 秒杀项目一步步实现CI/CD(Centos7.2)系列一:k8s高可用集群搭建总结以及部署API到k8s

    前言:本系列博客又更新了,是博主研究很长时间,亲自动手实践过后的心得,k8s集群是购买了5台阿里云服务器部署的,这个集群差不多搞了一周时间,关于k8s的知识点,我也是刚入门,这方面的知识建议参考博客园 ...

  6. 【k8s连载系列】k8s介绍

    k8s是Kubernetes的缩写,Google 于 2014 年开源了 Kubernetes 项目. 一.k8s的历史演变 k8s的演变过程:首先从传统的服务-->虚拟机部署-->容器部 ...

  7. (视频)asp.net core系列之k8s集群部署视频

    0.前言 应许多网友的要求,特此录制一下k8s集群部署的视频.在录制完成后发现视频的声音存在一点瑕疵,不过不影响大家的观感. 一.视频说明 1.视频地址: 如果有不懂,或者有疑问的欢迎留言.视频分为两 ...

  8. 利用k8s实现HPA

    如何利用kubernetes实现应用的水平扩展(HPA) 云计算具有水平弹性的特性,这个是云计算区别于传统IT技术架构的主要特性.对于Kubernetes中的POD集群来说,HPA就是实现这种水平伸缩 ...

  9. k8s系列--node(k8s节点介绍,新增节点,移除节点)

    一.简介 Node是Pod真正运行的主机,可以是物理机也可以是虚拟机. Node本质上不是Kubernetes来创建的, Kubernetes只是管理Node上的资源. 为了管理Pod,每个Node节 ...

  10. java8实战一------解决冗杂,java8真的很便利(抛砖)

    你的代码很容易因为需求而变化,对自己代码改来改去的你一定会觉得烦的.在我看来,java8很容易的解决了这个问题. 先来看看例子!在一堆苹果里,筛选绿色的苹果.当然,Apple类是这样子. class ...

随机推荐

  1. SpringCloud(十一)- 秒杀 抢购

    1.流程图 1.1 数据预热 1.2 抢购 1.3 生成订单 (发送订单消息) 1.4 订单入库 (监听 消费订单消息) 1.5 查看订单状态 1.6 支付 (获取支付链接 ) 1.7 支付成功 微信 ...

  2. qtcreator修改界面但是没有更新

    原因 我之前修改了项目名(简单的修改文件夹和.pro文件名),但是项目构建的位置还是之前目录. 解决 将 build directory改为新的目录即可.

  3. 【每日一题】【map、数组、二维数组排序、静态函数和库函数】2022年2月24日-NC97 字符串出现次数的TopK问题

    描述给定一个字符串数组,再给定整数 k ,请返回出现次数前k名的字符串和对应的次数.返回的答案应该按字符串出现频率由高到低排序.如果不同的字符串有相同出现频率,按字典序排序.对于两个字符串,大小关系取 ...

  4. 基于.NetCore开发博客项目 StarBlog - (24) 统一接口数据返回格式

    前言 开发接口,是给客户端(Web前端.App)用的,前面说的RESTFul,是接口的规范,有了统一的接口风格,客户端开发人员在访问后端功能的时候能更快找到需要的接口,能写出可维护性更高的代码. 而接 ...

  5. GitHub上的一个Latex模板

    代码下载:GitHub的项目地址或者在LATEX项目报告模板下载. 编译环境:Latex的编译器,如Ctex软件. 把源码clone或者下载到本地后,根据他的说明 如何开始 使用report.tex开 ...

  6. 何为GUI???

    1.GUI是什么–简介 GUI的全称为Graphical User Interface,图形化界面或图形用户接口,是指采用图形方式显示的计算机操作环境用户接口.与早期计算机使用的命令行界面相比,图形界 ...

  7. [机器学习] Yellowbrick使用笔记6-分类可视化

    分类模型试图在一个离散的空间中预测一个目标,即为一个因变量实例分配一个或多个类别. 代码下载 分类分数可视化工具显示类之间的差异以及一些特定于分类器的可视化评估.我们目前已经实施了以下分类器评估: 分 ...

  8. [seaborn] seaborn学习笔记0-seaborn学习笔记章节

    seaborn学习笔记章节 seaborn是一个基于matplotlib的Python数据可视化库.seaborn是matplotlib的高级封装,可以绘制有吸引力且信息丰富的统计图形.相对于matp ...

  9. 记一个难以发现的 UB

    观察以下代码: vector<int> X, Y, A, val; inline int ls(int p) { return p << 1; } inline int rs( ...

  10. 使用java代码调用rabbitmq接口进行新增编辑mq用户、虚拟机vhost、动态创建交换机exchange、队列queue以及设置权限,绑定vhost与exchange等操作

    使用java代码操作rabbitmq时,首先需要一个有创建用户等权限的管理员账号,需要在rabbitmq的后台管理页面手动创建这个账号,系统推荐的这几个tag可以让账号有rabbitmq后台管理页面的 ...