热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

kuernetes–自定义指标HPA,实现PHPFPM弹性伸缩

HPA通过监控POD的CPU和MEM使用率,实现了默认的弹性伸缩功能。然而,在实际环境中,伸缩的判断依据通常不单单是CPUMEM,还可能是:POD的线程使用率POD的QPSPOD的



HPA通过监控POD的CPU和MEM使用率,实现了默认的弹性伸缩功能。


然而,在实际环境中,伸缩的判断依据通常不单单是CPU/MEM,还可能是:



  • POD的线程使用率

  • POD的QPS

  • POD的带宽


无法一一列举。


HPA支持我们扩展自定义指标,只要我们让prometheus采集到POD的这些指标,那么HPA就可以通过一定的机制查询prometheus来得到这些指标值,进而做出伸缩依据。


HPA基础指标架构


HPA版本要求


为了最终使用自定义指标,需要使用如下版本的HPA:


apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler

HPA工作原理


HPA实现在kube-controller-manager中,是一个控制器。


该控制器周期性扫描所有配置的HPA对象,每个HPA对象关联到1个Deployment,进而关联到N个POD。


控制器将获取这些POD的CPU和MEM资源使用量,求这些POD的平均值,然后做出是否伸缩的决策。


问题来了,HPA是从哪里取到POD的CPU和MEM使用率的呢?


我们也知道,通过下面的命令同样可以查看POD的资源使用量:


[root@10-42-49-142 ~]# kubectl top pods -n abtest11
NAME                                    CPU(cores)   MEMORY(bytes)  
abtest-bgm-smzdm-com-5d4899774b-6lh5b   20m          79Mi            
abtest-test-job-5487cfbf7-gxp44         1m           23Mi

其实top命令和HPA都采用了同一种方法来获取CPU/MEM指标,下面是调用流程:



metrics-server是一个开源项目,它采集集群所有kubelet中的容器CPU/MEM指标数据,保存到内存里。


当HPA调用apiserver的特定URL时,apiserver转发请求给metrics-server得到应答,也就是我们上面kubectl top看到的数据了。


我们完全可以直接请求apiserver的特定URL,方法如下:


kubectl get --raw '/apis/metrics.k8s.io/v1beta1/namespaces/abtest11/pods'| jq .
{
  "kind": "PodMetricsList",
  "apiVersion": "metrics.k8s.io/v1beta1",
  "metadata": {
    "selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/abtest11/pods"
  },
  "items": [
    {
      "metadata": {
        "name": "abtest-bgm-smzdm-com-5d4899774b-6lh5b",
        "namespace": "abtest11",
        "selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/abtest11/pods/abtest-bgm-smzdm-com-5d4899774b-6lh5b",
        "creationTimestamp": "2020-06-04T02:52:54Z"
      },
      "timestamp": "2020-06-04T02:52:12Z",
      "window": "30s",
      "containers": [
        {
          "name": "abtest-bgm-smzdm-com",
          "usage": {
            "cpu": "18782113n",
            "memory": "81008Ki"
          }
        }
      ]
    },
    {
      "metadata": {
        "name": "abtest-test-job-5487cfbf7-gxp44",
        "namespace": "abtest11",
        "selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/abtest11/pods/abtest-test-job-5487cfbf7-gxp44",
        "creationTimestamp": "2020-06-04T02:52:54Z"
      },
      "timestamp": "2020-06-04T02:52:12Z",
      "window": "30s",
      "containers": [
        {
          "name": "abtest-test-job",
          "usage": {
            "cpu": "401002n",
            "memory": "23668Ki"
          }
        }
      ]
    }
  ]
}

这个命令调用apiserver,获取abtest11这个namespace下面所有pod的cpu/mem指标,将得到metrics-server的JSON应答。


这个转发关系是通过配置apiservice资源类型实现的:


kubectl describe apiservice v1beta1.metrics.k8s.io
Name:         v1beta1.metrics.k8s.io
Namespace:    
Labels:      
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"apiregistration.k8s.io/v1beta1","kind":"APIService","metadata":{"annotations":{},"name":"v1beta1.metrics.k8s.io"},"spec":{"...
API Version:  apiregistration.k8s.io/v1
Kind:         APIService
Metadata:
  Creation Timestamp:  2019-11-20T03:58:48Z
  Resource Version:    49406253
  Self Link:           /apis/apiregistration.k8s.io/v1/apiservices/v1beta1.metrics.k8s.io
  UID:                 6d633213-1d1f-499f-ab16-d6673b9a0ce0
Spec:
  Group:                     metrics.k8s.io
  Group Priority Minimum:    100
  Insecure Skip TLS Verify:  true
  Service:
    Name:            metrics-server
    Namespace:       kube-system
    Port:            443
  Version:           v1beta1
  Version Priority:  100
Status:
  Conditions:
    Last Transition Time:  2020-05-11T18:47:59Z
    Message:               all checks passed
    Reason:                Passed
    Status:                True
    Type:                  Available
Events:                    

也就是说,apiserver收到/apis/metrics.k8s.io/v1beta1/前缀的调用,就会转发流量给metrics-server这个service。


当然,metrics-server是需要我们自己部署配置的,具体方法大家去github主页参考即可。


HPA自定义指标架构


其实呢,HPA Controller逻辑上已经预埋了自定义指标的扩展能力,自定义指标的获取与上述基础指标的获取,原理上是一模一样的。



HPA控制器会通过调用apiserver的另外一个URL前缀,经过代理后调用到k8s-prometheus-adaptor服务,该服务会从prometheus采集到自定义指标,并转换成JSON格式作为返回。


可见,



  • 基础指标:metrics-server采集kubelet

  • 自定义指标:k8e-prometheus-adaptor采集prometheus


因为我们有大量指标存储在prometheus中,因此有了k8s-prometheus-adaptor的加持,我们就可以把他们利用到HPA中。


k8s-prometheus-adaptor架构


在了解这个开源项目的过程中,我发现最难理解的还是它的工作原理,所以我还是阅读了一下它的代码。



该程序由”定时拉取”和”实时查询”两部分组成,既然有一个实时查询prometheus指标的功能,为什么还要定时拉取?拉取什么?这是我在接触该项目过程中最大的困惑,直接影响到我们对其规则配置的理解。


要解释这个问题,很难离开实际的配置例子,所以我们直接进入本篇博客的主题,根据PHP-FPM进程使用率的HPA。(PHP是依靠启动多个PHP-FPM进程来实现并发的,如果POD里面的FPM进程使用率太高的话,我们认为应该扩容)


明确指标计算


给HPA自定义指标叫做fpm_active_rate,代表1个POD的FPM进程使用率。


在prometheus中并没有fpm_active_rate这个东西,只有2类原始数据:


pm_status{container_name="abtest-bgm-smzdm-com",instance="10.42.58.17:808",job="kubernetes-php-pods",namespace="abtest",pod_ip="10.42.58.17",pod_name="abtest-bgm-smzdm-com-b56679fdf-2fhlv",pod_template_hash="b56679fdf",state="total processes",zdm_app_env="test",zdm_app_green_blue="green",zdm_app_key="abtest-bgm-smzdm-com",zdm_app_language="php",zdm_app_owner="abtest-bgm-smzdm-com",zdm_app_type="deployment"}
pm_status{container_name="abtest-bgm-smzdm-com",instance="10.42.58.17:808",job="kubernetes-php-pods",namespace="abtest",pod_ip="10.42.58.17",pod_name="abtest-bgm-smzdm-com-b56679fdf-2fhlv",pod_template_hash="b56679fdf",state="active processes",zdm_app_env="test",zdm_app_green_blue="green",zdm_app_key="abtest-bgm-smzdm-com",zdm_app_language="php",zdm_app_owner="abtest-bgm-smzdm-com",zdm_app_type="deployment"}

pm_status是prometheus采集的原始序列数据。


标签state分为”active processes”和”total processes”,分别代表活跃进程数和总进程数。


标签namespace和pod_name则标识了所归属的POD。


因此,每个POD的fpm_active_rate的计算思路就是用active除以total即可。


配置文件


现在,我们必须看一下配置文件了:


apiVersion: v1
kind: ConfigMap
metadata:
  name: adapter-config
  namespace: custom-metrics
data:
  config.yaml: |
    rules:
    - seriesQuery: '{__name__="pm_status",namespace!="",pod_name!="",state="active processes"}'
      resources:
        overrides:
          namespace:
            resource: namespace
          pod_name:
            resource: pod
      name:
        as: "fpm_active_rate"
      metricsQuery: sum(max_over_time(<<.Series>>{<<.LabelMatchers>>,state="active processes"}[2m])) by (<<.GroupBy>>) / sum(max_over_time(<<.Series>>{<<.LabelMatchers>>,state="total processes"}[2m])) by (<<.GroupBy>>)

adapter支持配置多条规则,为了搞定fpm_active_rate指标,我只需要一个rule。


定时拉取


adapter会定时执行seriesQuery,这是一个promql。


它过滤出最新采集到的所有pm_status,并且还需要满足state是active processes的,这是干啥呢?


假设prom中只有这两条记录:


pm_status{container_name="abtest-bgm-smzdm-com",instance="10.42.58.17:808",job="kubernetes-php-pods",namespace="abtest",pod_ip="10.42.58.17",pod_name="abtest-bgm-smzdm-com-b56679fdf-2fhlv",pod_template_hash="b56679fdf",state="total processes",zdm_app_env="test",zdm_app_green_blue="green",zdm_app_key="abtest-bgm-smzdm-com",zdm_app_language="php",zdm_app_owner="abtest-bgm-smzdm-com",zdm_app_type="deployment"}
pm_status{container_name="abtest-bgm-smzdm-com",instance="10.42.58.17:808",job="kubernetes-php-pods",namespace="abtest",pod_ip="10.42.58.17",pod_name="abtest-bgm-smzdm-com-b56679fdf-2fhlv",pod_template_hash="b56679fdf",state="active processes",zdm_app_env="test",zdm_app_green_blue="green",zdm_app_key="abtest-bgm-smzdm-com",zdm_app_language="php",zdm_app_owner="abtest-bgm-smzdm-com",zdm_app_type="deployment"}

那么,上述语句将得到结果:


pm_status{container_name="abtest-bgm-smzdm-com",instance="10.42.58.17:808",job="kubernetes-php-pods",namespace="abtest",pod_ip="10.42.58.17",pod_name="abtest-bgm-smzdm-com-b56679fdf-2fhlv",pod_template_hash="b56679fdf",state="active processes",zdm_app_env="test",zdm_app_green_blue="green",zdm_app_key="abtest-bgm-smzdm-com",zdm_app_language="php",zdm_app_owner="abtest-bgm-smzdm-com",zdm_app_type="deployment"}

然后adapter根据resources.overwrites配置,从这条记录中进行提取+映射,得到如下信息:



  • namespace标签的abtest11就是POD所属的namespace

  • pod_name标签的abtest-bgm-smzdm-com-b56679fdf-2fhlv就是POD的name。


同时,adapter根据name.as配置,将pm_status名字改为fpm_active_rate,也就是HPA自定义指标的名字。


此后,adapter在内存中记录一个这样的映射关系:


fpm_active_rate, abtest11, abtest-bgm-smzdm-com-b56679fdf-2fhlv  —->  rule

也就是这个POD到这条配置规则的关系。


可见,定时任务的目的就是『发现』: 发现所有的POD,记录它们与所属rule之间的关系。


实时查询


之所以要定时构建上述索引关系,其目的是为了满足实时查询。




阅读后续内容?


你必须付费加入我的知识星球,为有效知识付费是对作者最好的回报。


二维码见下方 或者 右侧边栏。






推荐阅读
  • 本文详细介绍了在MySQL中如何高效利用EXPLAIN命令进行查询优化。通过实例解析和步骤说明,文章旨在帮助读者深入理解EXPLAIN命令的工作原理及其在性能调优中的应用,内容通俗易懂且结构清晰,适合各水平的数据库管理员和技术人员参考学习。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 线程能否先以安全方式获取对象,再进行非安全发布? ... [详细]
  • Amoeba 通过优化 MySQL 的读写分离功能显著提升了数据库性能。作为一款基于 MySQL 协议的代理工具,Amoeba 能够高效地处理应用程序的请求,并根据预设的规则将 SQL 请求智能地分配到不同的数据库实例,从而实现负载均衡和高可用性。该方案不仅提高了系统的并发处理能力,还有效减少了主数据库的负担,确保了数据的一致性和可靠性。 ... [详细]
  • 利用ZFS和Gluster实现分布式存储系统的高效迁移与应用
    本文探讨了在Ubuntu 18.04系统中利用ZFS和Gluster文件系统实现分布式存储系统的高效迁移与应用。通过详细的技术分析和实践案例,展示了这两种文件系统在数据迁移、高可用性和性能优化方面的优势,为分布式存储系统的部署和管理提供了宝贵的参考。 ... [详细]
  • Android中将独立SO库封装进JAR包并实现SO库的加载与调用
    在Android开发中,将独立的SO库封装进JAR包并实现其加载与调用是一个常见的需求。本文详细介绍了如何将SO库嵌入到JAR包中,并确保在外部应用调用该JAR包时能够正确加载和使用这些SO库。通过这种方式,开发者可以更方便地管理和分发包含原生代码的库文件,提高开发效率和代码复用性。文章还探讨了常见的问题及其解决方案,帮助开发者避免在实际应用中遇到的坑。 ... [详细]
  • 本文详细介绍了在Linux系统上编译安装MySQL 5.5源码的步骤。首先,通过Yum安装必要的依赖软件包,如GCC、GCC-C++等,确保编译环境的完备。接着,下载并解压MySQL 5.5的源码包,配置编译选项,进行编译和安装。最后,完成安装后,进行基本的配置和启动测试,确保MySQL服务正常运行。 ... [详细]
  • 针对MySQL Undo空间满载及Oracle Undo表空间溢出的问题,本文详细探讨了其原因与解决策略。首先,通过启动SQL*Plus并以SYS用户身份登录数据库,查询当前数据库的UNDO表空间名称,确认当前状态。接着,分析导致Undo空间满载的常见原因,如长时间运行的事务、频繁的更新操作等,并提出相应的解决方案,包括调整Undo表空间大小、优化事务管理、定期清理历史数据等。最后,结合实际案例,提供具体的实施步骤和注意事项,帮助DBA有效应对这些问题。 ... [详细]
  • 本指南详细介绍了在Linux环境中高效连接MySQL数据库的方法。用户可以通过安装并使用`mysql`客户端工具来实现本地连接,具体命令为:`mysql -u 用户名 -p 密码 -h 主机`。例如,使用管理员账户连接本地MySQL服务器的命令为:`mysql -u root -p pass`。此外,还提供了多种配置优化建议,以确保连接过程更加稳定和高效。 ... [详细]
  • 阿里云MySQL与Oracle数据库的主从复制技术详解 ... [详细]
  • 本文详细介绍了使用 Python 进行 MySQL 和 Redis 数据库操作的实战技巧。首先,针对 MySQL 数据库,通过 `pymysql` 模块展示了如何连接和操作数据库,包括建立连接、执行查询和更新等常见操作。接着,文章深入探讨了 Redis 的基本命令和高级功能,如键值存储、列表操作和事务处理。此外,还提供了多个实际案例,帮助读者更好地理解和应用这些技术。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
author-avatar
书友79805954
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有