client-go的Indexer三部曲之二:性能测试

news2024/9/26 3:32:14

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本文是《client-go的Indexer》系列的第二篇,在前文咱们通过实例掌握了client-go的Indexer的基本功能,本篇咱们尝试对下面这两种接口进行压力测试,用数据验证Indexer的性能优势,看看是否如理论分析那样真的存在
  1. 第一个接口:basic/get_obj_by_obj_key,这个接口会用到Store.GetByKey方法,从本地缓存中取得pod对象返回,如下图红色箭头所示

在这里插入图片描述

  1. 第二个接口:remote/get_obj_by_obj_key_remote_query,此接口会调用client-go库的api,向api-server发起http请求,查找指定pod的信息返回
    在这里插入图片描述

部署情况说明

  • 今天的压测所涉及的服务和应用,它们的部署情况如下图所示,共两台Ubuntu电脑,电脑1用于执行压测,上面部署了k6(或者部署docker,用docker来运行k6),电脑2部署了kubernetes,同时也运行着名为client-go-indexer-tutorials的应用,该应用就是咱们编写的代码:实现了今天要压测的两个接口
    在这里插入图片描述

源码下载

  • 接下来要进入的是编码环节,如果您不想写代码,也可以从GitHub上直接下载,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称链接备注
项目主页https://github.com/zq2599/blog_demos该项目在GitHub上的主页
git仓库地址(https)https://github.com/zq2599/blog_demos.git该项目源码的仓库地址,https协议
git仓库地址(ssh)git@github.com:zq2599/blog_demos.git该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在tutorials/client-go-indexer-tutorials文件夹下,如下图红框所示:
    在这里插入图片描述

编码(第一个接口:basic/get_obj_by_obj_key)

  • 第一个接口的源码其实在前文其实已写好,就不重新写了,这里看一下关键代码,如下所示,其实也就一行(调用INDEXER.GetByKey)
// GetObjByObjKey b. 根据对象的key返回(演示Store.Get方法)
func GetObjByObjKey(c *gin.Context) {
	rawObj, exists, err := INDEXER.GetByKey(ObjKey(c))

	if err != nil {
		c.String(500, fmt.Sprintf("b. get pod failed, %v", err))
	} else if !exists {
		c.String(500, fmt.Sprintf("b. get empty pod, %v", err))
	} else {
		if v, ok := rawObj.(*v1.Pod); ok {
			c.JSON(200, v)
		} else {
			c.String(500, "b. convert interface to pod failed")
		}
	}
}
  • 在初始化gin的时候绑定path和handler即可
	// 用于提供基本功能的路由组
	basicGroup := r.Group("/basic")

	// a. 查询指定语言的所有对象的key(演示2. IndexKeys方法)
	basicGroup.GET("get_obj_keys_by_language_name", basic.GetObjKeysByLanguageName)

	// b. 返回对象的key,返回对应的对象(演示Store.GetByKey方法)
	basicGroup.GET("get_obj_by_obj_key", basic.GetObjByObjKey)

编码(第二个接口:remote/get_obj_by_obj_key_remote_query)

  • 要使用client-go库,首先要准备好ClientSet对象,这个在前文也准备好了,放在全局变量中随时可以用,来回顾初始化的代码
var ClientSet *kubernetes.Clientset
var once sync.Once

func initIndexer() {
	log.Println("开始初始化Indexer")

	var kubeconfig *string

	// 试图取到当前账号的家目录
	if home := homedir.HomeDir(); home != "" {
		// 如果能取到,就把家目录下的.kube/config作为默认配置文件
		kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
	} else {
		// 如果取不到,就没有默认配置文件,必须通过kubeconfig参数来指定
		kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
	}

	// 加载配置文件
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		panic(err.Error())
	}

	// 用clientset类来执行后续的查询操作
	ClientSet, err = kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}
	...
  • 再来看如何用ClientSet向api-server发起请求,这也是熟悉的api,在《client-go实战》系列中屡屡用到
// GetObjByObjKey 远程请求,根据指定key查询pod对象
func GetObjByObjKey(c *gin.Context) {
	rawObj, err := basic.ClientSet.
		CoreV1().
		Pods(basic.NAMESPACE).
		Get(c, c.DefaultQuery("pod_name", ""), metav1.GetOptions{})

	if err != nil {
		c.String(500, fmt.Sprintf("g. get pod failed, %v", err))
	} else {
		c.JSON(200, rawObj)
	}
}
  • 最后是绑定path和方法
	remoteGroup := r.Group("/remote")
	// g. 使用clientset远程查询
	remoteGroup.GET("get_obj_by_obj_key_remote_query", remote.GetObjByObjKey)
  • 请将程序运行起来,稍后压测会用到
  • 至此,用于性能对比测试的两个接口代码都已经写好,接下来开始准备性能测试

用k6压测第二个接口(远程访问api-server的方式)

  • 这里用到k6作为压测工具,您也可以选择自己熟悉的工具来用,选择k6是因为足够简单省事儿,如果您已经装好了docker,执行压测只要一行命令就行了
  • 首先编写第二个接口的压测脚本,也就是压测client-go远程访问api-server查询对象的性能,新建文件remote.js,内容如下,可见非常简单,就是发请求检查返回码和返回body
import http from 'k6/http';
import { check } from 'k6';

export default function () {
  const res = http.get(`http://${__ENV.MY_HOSTNAME}/remote/get_obj_by_obj_key_remote_query?pod_name=${__ENV.POD_NAME}`);
  check(res, {
    'is status 200': (res) => res.status === 200,
    'body size is > 0': (r) => r.body.length > 0,
  });
}
  • 如果您的电脑上部署了docker,那么执行以下命令即可完成压力测试,命令中的参数稍后会详细说明
docker run \
--rm \
-i \
loadimpact/k6 \
run \
--duration 60s \
--vus 10 \
-e MY_HOSTNAME=192.168.50.76:18080 \
-e POD_NAME=nginx-deployment-696cc4bc86-2rqcg \
- < remote.js
  • 这里解释清楚上述命令用到的每个参数,
docker run \    	// docker运行容器
--rm \				// 等当前控制台结束时删除该容器(相当于一次性任务)
-i \				// 保持STDIN打开
loadimpact/k6 \		// 镜像名
run \				// 容器中执行的命令,即启动k6的命令
--duration 60s \	// k6的参数:压测时长60秒
--vus 10 \			// k6的参数:并发数为10
-e MY_HOSTNAME=192.168.50.76:18080 \				// remote.js脚本中用到的参数,压测服务的IP和端口
-e POD_NAME=nginx-deployment-696cc4bc86-2rqcg \		// remote.js脚本中用到的参数,pod名称
- < remote.js										// k6压测脚本名称
  • 压测结束,详细数据如下,没有报错,整体QPS为5,虽然我的电脑很烂,但是这么低的QPS还是让人看了直摇头…
     ✓ is status 200
     ✓ body size is > 0

     checks.........................: 100.00% ✓ 6380
     data_received..................: 1.5 MB  25 kB/s
     data_sent......................: 53 kB   857 B/s
     http_req_blocked...............: avg=119.67µs min=927ns   med=2.63µs   max=4.2ms    p(90)=4.96µs   p(95)=7.16µs
     http_req_connecting............: avg=115.35µs min=0s      med=0s       max=4.13ms   p(90)=0s       p(95)=0s
     http_req_duration..............: avg=1.9s     min=15.62ms med=1.99s    max=2.11s    p(90)=2.01s    p(95)=2.03s
       { expected_response:true }...: avg=1.9s     min=15.62ms med=1.99s    max=2.11s    p(90)=2.01s    p(95)=2.03s
     http_req_failed................: 0.00%   ✓ 0319
     http_req_receiving.............: avg=244.4µs  min=23.86µs med=115.38µs max=8.72ms   p(90)=343.48µs p(95)=674.31µs
     http_req_sending...............: avg=18.34µs  min=4.59µs  med=12.75µs  max=209.44µs p(90)=25.43µs  p(95)=35.07µs
     http_req_tls_handshaking.......: avg=0s       min=0s      med=0s       max=0s       p(90)=0s       p(95)=0s
     http_req_waiting...............: avg=1.9s     min=15.51ms med=1.99s    max=2.11s    p(90)=2.01s    p(95)=2.03s
     http_reqs......................: 319     5.159646/s
     iteration_duration.............: avg=1.9s     min=19.58ms med=1.99s    max=2.11s    p(90)=2.01s    p(95)=2.03s
     iterations.....................: 319     5.159646/s
     vus............................: 5       min=5      max=10
     vus_max........................: 10      min=10     max=10

用k6压测第一个接口(获取本地缓存的数据)

  • 远程访问api-server的方式,QPS只有5,接下来该测试第一个接口了,看走本地缓存在性能上是否能比远程访问更强,这要是翻车了该咋办,博客都写不下去了…,Indexer成了全村的希望
    在这里插入图片描述
  • 先编写k6脚本,名为indexer.js
import http from 'k6/http';
import { check } from 'k6';

export default function () {
  const res = http.get(`http://${__ENV.MY_HOSTNAME}/basic/get_obj_by_obj_key?obj_key=${__ENV.OBJ_KEY}`);
  check(res, {
    'is status 200': (res) => res.status === 200,
    'body size is > 0': (r) => r.body.length > 0,
  });
}
  • 完整的压测命令如下
docker run \
--rm \
-i \
loadimpact/k6 \
run \
--duration 60s \
--vus 10 \
-e MY_HOSTNAME=192.168.50.76:18080 \
-e OBJ_KEY=indexer-tutorials/nginx-deployment-696cc4bc86-2rqcg \
- < indexer.js
  • 压测结束,详细数据如下,没有报错,整体QPS为993,嘿嘿,稳了,没翻车…
     ✓ is status 200
     ✓ body size is > 0

     checks.........................: 100.00% ✓ 1192360
     data_received..................: 288 MB  4.8 MB/s
     data_sent......................: 10 MB   168 kB/s
     http_req_blocked...............: avg=4.67µs   min=343ns  med=3.13µs  max=4.81ms   p(90)=5.55µs   p(95)=6.56µs
     http_req_connecting............: avg=633ns    min=0s     med=0s      max=4.4ms    p(90)=0s       p(95)=0s
     http_req_duration..............: avg=9.87ms   min=3.15ms med=9.03ms  max=238.05ms p(90)=13.56ms  p(95)=15.55ms
       { expected_response:true }...: avg=9.87ms   min=3.15ms med=9.03ms  max=238.05ms p(90)=13.56ms  p(95)=15.55ms
     http_req_failed................: 0.00%   ✓ 059618
     http_req_receiving.............: avg=321.15µs min=8.16µs med=70.93µs max=62.14ms  p(90)=478.85µs p(95)=2.07ms
     http_req_sending...............: avg=19.72µs  min=2.29µs med=14.48µs max=2.82ms   p(90)=25.42µs  p(95)=37.31µs
     http_req_tls_handshaking.......: avg=0s       min=0s     med=0s      max=0s       p(90)=0s       p(95)=0s
     http_req_waiting...............: avg=9.53ms   min=3.07ms med=8.69ms  max=237.72ms p(90)=13.13ms  p(95)=15.04ms
     http_reqs......................: 59618   993.440775/s
     iteration_duration.............: avg=10.05ms  min=3.24ms med=9.21ms  max=238.67ms p(90)=13.75ms  p(95)=15.73ms
     iterations.....................: 59618   993.440775/s
     vus............................: 10      min=10       max=10
     vus_max........................: 10      min=10       max=10
  • 至此,压测完成,同样是获取pod的信息,Indexer由于不涉及网络请求,在性能优势上表现的很明显,当然了Indexer也不是万能了,前文编码中,它的局限性也体现出来了
  1. 要和api-server保持长连接,以获取数据最新的变化
  2. 本地内存中长期存放资源数据,相比之下client-go的一次请求响应就搞定了
  3. 灵活性,下图是client-go远程请求api-server的代码,可以按需求随时改变条件,namespace、label-selector等等自由变化,而Indexer则一开始就要把范围确定好,然后只能本地获取这些资源的内容
    在这里插入图片描述
  • 综上所述,两种方式各有优劣,就算混合着用也没问题,一切还是为业务服务吧
  • 至此,性能篇就完成了,接下来就是《client-go的Indexer三部曲》的终篇:源码篇,相信经历了前两篇的实战,您对Indexer已经有了很深入的了解,所以接下来阅读源码也就是件很轻松愉快的事情了

参考

  • k6官方资料:https://k6.io/docs

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/657300.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

css小兔鲜项目搭建

目录 精灵图 精灵图的使用步骤 背景图片大小 background连写 文字阴影 盒子阴影 过渡 骨架标签 SEO三大标签 版心的介绍 css书写顺序 项目结构搭建 精灵图 场景&#xff1a;项目中将多张小图片&#xff0c;合并成一张大图片&#xff0c;这张大图片称之为精灵图 优点…

c语言实现 顺序存储和链式存储(几种链表)

目录 一、简介 二、一些问题 1、递归free 2、free单向循环链表&#xff1a; 3、free单向链表 4、free双向循环链表 5、free使用数组实现链式存储结构 6、sizeof&#xff08;&#xff09;求字符串大小的问题 三、总结 一、简介 花了几天的时间从头开始使用c语言…

UnityVR--UIManager--UI管理2

目录 前言 UIManger的实现 1. 需要用到的变量和数据 2. 在构造中的工作 3. 初始化面板 4. 显示面板 5. 隐藏面板和隐藏所有面板 6. 其他小工具 在场景中实现 1. 不同面板的类型设置 2. 场景中的设置 前言 接前篇&#xff0c;上一篇已经有了UITools.cs其中定义了UI面板需…

Web服务器群集:部署LAMP平台

目录 一、理论 1.LAMP平台 2.Apache网址服务基础 2.httpd服务器的基本配置 3.构建虚拟Web主机 4.MySQL服务 5.构建PHP运行环境 二、实验 1.LAMP架构DISCUZ论坛应用 三、问题 1.虚拟机内存分配上限问题&#xff0c;内存上限只能加到3G。 2.虚拟机CPU如何设置才更加合…

RISC-V 函数调用约定和Stack使用

RISC-V 函数调用约定和Stack使用 引言RISC-V vs x86RISC-V寄存器StackStruct补充函数调用约定寄存器约定函数跳转和返回指令的编程约定被调用函数的编程约定 RISC-V 汇编与 C 混合编程RISC-V 汇编调用 C 函数C 函数中嵌入 RISC-V 汇编 引言 MIT 6.S081 2020 操作系统 本文为M…

1744_Perl获取文件属性参数

全部学习汇总&#xff1a; GreyZhang/perl_basic: some perl basic learning notes. (github.com) 前阵子写通过Perl执行判断调用ImageMagick实现图像的批量压缩功能脚本时用到过这个功能&#xff0c;只是当时仅仅看了一个获取文件大小的功能。 今天看第六版的小骆驼书又看到了…

一篇十分硬核的QT开发经验文章!送给正在做QT开发或想从事QT开发的你

当编译发现大量错误的时候&#xff0c;从第一个看起&#xff0c;一个一个的解决&#xff0c;不要急着去看下一个错误&#xff0c;往往后面的错误都是由于前面的错误引起的&#xff0c;第一个解决后很可能都解决了。 定时器是个好东西&#xff0c;学会好使用它&#xff0c;有时…

别再为缓慢启动而失去用户! 让你的Android应用体验绝佳性能

为什么要启动优化&#xff1f; 启动优化是为了提升应用程序的启动性能&#xff0c;即减少应用程序从启动到可交互状态所需要的时间。以下是一些关键原因&#xff0c;解释了为什么启动优化是重要的&#xff1a; 用户体验&#xff1a; 启动时间是用户与应用程序互动的第一个体验…

常用API

文章目录 1、String类String概述创建对象的两种方式字符串的内容比较String常用APIString类开发验证码功能手机号码屏蔽功能 2、Object类Object类的作用Object类的常用方法**Object的toString方法**Object的equals方法 3、Objects类4、StringBuilder类5、Math类6、System类7、B…

2023-06-17:说一说redis中渐进式rehash?

2023-06-17&#xff1a;说一说redis中渐进式rehash&#xff1f; 答案2023-06-17&#xff1a; 在Redis中&#xff0c;如果哈希表的数组一直保持不变&#xff0c;就会增加哈希冲突的可能性&#xff0c;从而降低检索效率。为了解决这个问题&#xff0c;Redis会对数组进行扩容&am…

基于Spark的气象数据分析

研究背景与方案 1.1.研究背景 在大数据时代背景下&#xff0c;各行业数据的规模大幅度增加&#xff0c;数据类别日益复杂&#xff0c;给数据分析工作带来极大挑战。气象行业和人们的生活息息相关&#xff0c;随着信息时代的发展&#xff0c;大数据技术的出现为气象数据的发展…

第九章 形态学图像处理

文章目录 9形态学图像处理9.2腐蚀与膨胀9.2.1腐蚀9.2.2膨胀 9.3开操作和闭操作9.5一些基本形态学方法9.3.1边界提取 9.6灰度级形态学9.6.3一些基本的形态学算法 9形态学图像处理 9.2腐蚀与膨胀 9.2.1腐蚀 imgcv2.imread(dige.png,0) kernel np.ones((3,3),np.uint8) num[[…

第七章 原理篇:HOG特征提取

之前面试被问到了然后没有讲出来&#xff0c;所以今天复习一下&#xff01; 气死我了&#xff01; 参考教程&#xff1a; What Is a Feature Descriptor in Image Processing? https://medium.com/analytics-vidhya/a-gentle-introduction-into-the-histogram-of-oriented-…

scratch lenet(3): 直方图均衡化的C语言实现

文章目录 1. 目的2. 原理3. 实现3.1 获得直方图 int hist[256]3.2 获得累积分布 int cdf[256]3.3 均衡化公式3.4 遍历原图&#xff0c;逐点均衡化&#xff0c;得到结果 4. 完整代码和结果4.1 例子14.2 例子24.3 例子34.4 完整代码 5. References 1. 目的 用 C 语言实现直方图均…

低价618背后,看见品牌营销的「产业新洪流」

如今消费者对于低价与品质的兼得需求&#xff0c;正倒逼一个全新的产业经济模式出现&#xff0c;而企业恰是最直接承载者。只有具备真正“低价”的能力模型&#xff0c;企业才能参与到下一轮的产业经济&#xff0c;甚至是社会经济的发展浪潮中。 作者|皮爷 出品|产业家 成本不…

Elasticsearch设置密码

Elasticsearch设置密码 概述ES开启认证配置密码访问开启安全认证的EScurl浏览器直接访问Kibana 配置 es认证直接配置用户名密码到 kibana.yml以kibana密钥的形式使用命令行启动参数形式指定用户名密码 使用kibana 查看es用户 概述 ES默认没有开启安全组件&#xff0c;如果我们…

简单的Dubbo实验环境搭建

Dubbo-api中定义的UserQueryFacade接口可以发布在私服上&#xff0c;这样子dubbo-consumer和dubbo-provider就可以以maven依赖的形式导入使用。dubbo-provider需要提供接口的实现类&#xff0c;dubbo-consumer需要订阅该实现类&#xff0c;他们的元数据都通过zk进行记录。 许多…

Three.js学习项目--3D抗美援朝数据可视化

文章目录 部分场景体验地址操作说明 视频我做了哪些&#xff08;功能&#xff09;局限源代码地址部分逻辑按需渲染模型加载动画控制器模型纹理条件切换模型加载同时请求部分纹理 生成进度条模型缩放小动画 部分场景 体验地址 https://kmyc.hongbin.xyz/ 操作说明 视频 操作说…

LeetCode——查询后矩阵的和

目录 1、题目 2、题目解读 3、代码 1、题目 2718. 查询后矩阵的和 - 力扣&#xff08;Leetcode&#xff09; 给你一个整数 n 和一个下标从 0 开始的 二维数组 queries &#xff0c;其中 queries[i] [typei, indexi, vali] 。 一开始&#xff0c;给你一个下标从 0 开始的…

数学建模常用模型(一):灰色预测法

数学建模常用模型&#xff08;一&#xff09;&#xff1a;灰色预测法 灰色预测法是一种用于处理少量数据、数据质量较差或者缺乏历史数据的预测方法。它适用于一些非线性、非平稳的系统&#xff0c;尤其在短期预测和趋势分析方面有着广泛的应用。灰色预测法作为一种强大的数学…