大家好,我是张晋涛。
本篇我将为你介绍一个工具 - k6 ,它和 K8s 并没有什么间接的关系,它是一款开源的性能压测工具。
k6 背地的故事
2016 年 8 月,k6 在 GitHub 上公布了第一个版本,至此,一个杰出的开源负载压测工具进入了人们的视线。
2021 年的 6 月,对于 Grafana 和 k6 来讲是个大日子,Grafana Labs 收买了 k6 。
而事实上, Grafana 与 k6 的缘分还要追溯到更早的 2 年前。
2019 年,在进行 Grafana 6.0 的短期令牌刷新行为的压测时,Grafana Labs 进行了一系列的技术选型。
因为 Grafana Labs 的大部分后端软件是应用 Go 来实现的,凑巧 k6 满足 OSS 和 Go 需要,并且负载测试是应用 JS 编写(Grafana 前端框架及 UI 都在应用)。这使得 k6 自 Grafana 6.0 版本开始,一直地为 Grafana 开发者及测试者实现追踪 bug 的使命。
图 1 ,k6 退出 Grafana Labs
多样的压测工具
一个满意应手的自动化负载压测工具会极大的晋升程序开发人员的代码品质及效率。
下图中是一些比拟常见的用于负载压测的工具,咱们能够在 GitHub 上看到,目前,更新比拟频繁、沉闷的我的项目次要有:Gatling, Jmeter 和 k6 。
图 2 ,压测工具们
如何从中抉择,简略的讲就是工具效率的比拼。次要从以下两个方面来考量:
- 工具性能
- 工具应用体验
下图对以上工具进行了一些简略的比照。
这里我次要比照下其中较为沉闷的 3 个我的项目。
- JMeter - 相熟 Java 的小伙伴可能比拟理解这个工具。因为存在工夫久,JMeter 的性能是这之中最全面的,并且集成、附加组件做的较好。基于它构建的 SaaS 服务 Blazemeter,置信大家也都熟识。这也导致了一个极大的问题,应用的复杂性高及不够轻量级;
- Gatling - Gatling 也有着 SaaS 产品 Gatling Frontline。就应用门槛来讲,JS 要比 Scala 要低很多;
- k6 - k6 最后是由 SaaS 服务 Load Impact 的几名员工开发保护。应用门槛低(JS),参数化更简略,并且 “负载测试即代码” 的理念也让他的保护老本更低。将来可期。
图 3 ,3 种热门工具比一比
执行成果
或者这样:
装置 k6
k6 是用 Go 语言开发的,要装置 k6 步骤很简略,只有间接在其 GitHub 的 Release 页面下载二进制文件即可。比方:
(MoeLove) ➜ wget -q https://github.com/grafana/k6/releases/download/v0.35.0/k6-v0.35.0-linux-amd64.tar.gz (MoeLove) ➜ tar -xzf k6-v0.35.0-linux-amd64.tar.gz (MoeLove) ➜ lsk6-v0.35.0-linux-amd64 k6-v0.35.0-linux-amd64.tar.gz(MoeLove) ➜ mv ./k6-v0.35.0-linux-amd64/k6 ~/bin/k6(MoeLove) ➜ k6 versionk6 v0.35.0 (2021-11-17T09:53:18+0000/1c44b2d, go1.17.3, linux/amd64)
或者也能够间接应用它的 Docker 镜像:
➜ ~ docker run --rm loadimpact/k6 version k6 v0.35.0 (2021-11-17T09:53:03+0000/1c44b2d, go1.17.3, linux/amd64)
外围概念
在 k6 中并没有太多的概念。其中最次要的就是用来执行测试的 virtual users (VUs) ,它的实质就是并发执行工作的次数。
在应用 k6 执行测试的时候,能够通过 --vus
或者 -u
进行指定,默认是 1 。
上手实际
我个人感觉 k6 在目前的这些支流压测工具中算用户体验比拟好的一个。它应用 JS(ES6)作为配置语言,还是比拟不便的,咱们来做一些示例。
简略申请
如果对于进行 HTTP 申请的时候,咱们只须要从 k6/http
导入 http
即可。
留神在 k6 中,默认状况下必须得有个作为入口的 default
函数,这相似咱们罕用的 main
函数。
import http from "k6/http";export default function(){ http.get("https://test-api.k6.io/public/crocodiles/")}
执行后成果如下:
(MoeLove) ➜ k6 run simple_http_get.js /\ |‾‾| /‾‾/ /‾‾/ /\ / \ | |/ / / / / \/ \ | ( / ‾‾\ / \ | |\ \ | (‾) | / __________ \ |__| \__\ \_____/ .io execution: local script: simple_http_get.js output: - scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop): * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)running (00m01.1s), 0/1 VUs, 1 complete and 0 interrupted iterationsdefault ✓ [======================================] 1 VUs 00m01.1s/10m0s 1/1 iters, 1 per VU data_received..................: 6.3 kB 5.7 kB/s data_sent......................: 634 B 578 B/s http_req_blocked...............: avg=848.34ms min=848.34ms med=848.34ms max=848.34ms p(90)=848.34ms p(95)=848.34ms http_req_connecting............: avg=75.59µs min=75.59µs med=75.59µs max=75.59µs p(90)=75.59µs p(95)=75.59µs http_req_duration..............: avg=247.46ms min=247.46ms med=247.46ms max=247.46ms p(90)=247.46ms p(95)=247.46ms { expected_response:true }...: avg=247.46ms min=247.46ms med=247.46ms max=247.46ms p(90)=247.46ms p(95)=247.46ms http_req_failed................: 0.00% ✓ 0 ✗ 1 http_req_receiving.............: avg=455.24µs min=455.24µs med=455.24µs max=455.24µs p(90)=455.24µs p(95)=455.24µs http_req_sending...............: avg=103.77µs min=103.77µs med=103.77µs max=103.77µs p(90)=103.77µs p(95)=103.77µs http_req_tls_handshaking.......: avg=848.07ms min=848.07ms med=848.07ms max=848.07ms p(90)=848.07ms p(95)=848.07ms http_req_waiting...............: avg=246.9ms min=246.9ms med=246.9ms max=246.9ms p(90)=246.9ms p(95)=246.9ms http_reqs......................: 1 0.911502/s iteration_duration.............: avg=1.09s min=1.09s med=1.09s max=1.09s p(90)=1.09s p(95)=1.09s iterations.....................: 1 0.911502/s vus............................: 1 min=1 max=1 vus_max........................: 1 min=1 max=1
k6 默认会将执行后的后果输入到终端。同时它自带了一些指标会同时输入。
这些指标基本上都是语义化的,看名字就能够了解其含意,这里就不一一介绍了。
带查看的申请
咱们能够在申请中同时减少一些测试,判断接口的响应值是否合乎咱们的预期。如下:
import http from "k6/http";import { check, group } from "k6";export default function() { group("GET", function() { let res = http.get("http://httpbin.org/get?verb=get"); check(res, { "status is 200": (r) => r.status === 200, "is verb correct": (r) => r.json().args.verb === "get", }); });}
通过引入了 check
函数,来执行一些判断的逻辑,当然上述的 ==>
其实是 ES6 中的一种简写,将其开展为失常的函数也能够。比方:
import http from "k6/http";import { check, group } from "k6";export default function() { group("GET", function() { let res = http.get("http://httpbin.org/get?verb=get"); check(res, { "status is 200": function(r){ return r.status === 200 }, "is verb correct": (r) => r.json().args.verb === "get", }); });}
应用 k6 执行此脚本后,失去的输入相比之前的多了如下内容:
█ GET ✓ status is 200 ✓ is verb correct checks.........................: 100.00% ✓ 2 ✗ 0
从这里能够看到咱们以后申请接口的测试是否通过(也能够用来判断以后接口是否能失常提供服务)。
自定义指标输入
接下来咱们尝试下在压测过程中定义一些本人定的指标。只须要从 k6/metrics
中导入一些不同类型的指标即可。这和在 Prometheus 中的类型基本一致。
这里我减少了两个 metric。一个 testCounter
用于统计一共执行了多少次测试, passedRate
计算通过率。
import http from "k6/http";import { Counter, Rate } from "k6/metrics";import { check, group } from "k6";let testCounter = new Counter("test_counter");let passedRate = new Rate("passed_rate");export default function() { group("GET", function() { let res = http.get("http://httpbin.org/get?verb=get"); let passed = check(res, { "status is 200": (r) => r.status === 200, "is verb correct": (r) => r.json().args.verb === "get", }); testCounter.add(1); passedRate.add(passed); });}
这里咱们设置了 2 个 VU, 以及设置了执行过程为 10s
执行后的输入如下:
(MoeLove) ➜ k6 run -u 2 -d 10s simple_custom_metrics.js... execution: local script: simple_custom_metrics.js output: - scenarios: (100.00%) 1 scenario, 2 max VUs, 40s max duration (incl. graceful stop): * default: 2 looping VUs for 10s (gracefulStop: 30s)running (10.4s), 0/2 VUs, 36 complete and 0 interrupted iterationsdefault ✓ [======================================] 2 VUs 10s █ GET ✓ status is 200 ✓ is verb correct checks.........................: 100.00% ✓ 72 ✗ 0 data_received..................: 18 kB 1.7 kB/s data_sent......................: 3.9 kB 372 B/s group_duration.................: avg=567.35ms min=440.56ms med=600.52ms max=738.73ms p(90)=620.88ms p(95)=655.17ms http_req_blocked...............: avg=266.72µs min=72.33µs med=135.14µs max=776.66µs p(90)=644.4µs p(95)=719.96µs http_req_connecting............: avg=170.04µs min=45.51µs med=79.9µs max=520.69µs p(90)=399.41µs p(95)=463.55µs http_req_duration..............: avg=566.82ms min=439.69ms med=600.31ms max=738.16ms p(90)=620.52ms p(95)=654.61ms { expected_response:true }...: avg=566.82ms min=439.69ms med=600.31ms max=738.16ms p(90)=620.52ms p(95)=654.61ms http_req_failed................: 0.00% ✓ 0 ✗ 36 http_req_receiving.............: avg=309.13µs min=122.4µs med=231.72µs max=755.3µs p(90)=597.95µs p(95)=641.92µs http_req_sending...............: avg=80.69µs min=20.47µs med=38.91µs max=235.1µs p(90)=197.87µs p(95)=214.79µs http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s http_req_waiting...............: avg=566.43ms min=439.31ms med=600.16ms max=737.8ms p(90)=620.19ms p(95)=654.18ms http_reqs......................: 36 3.472534/s iteration_duration.............: avg=567.38ms min=440.62ms med=600.53ms max=738.75ms p(90)=620.89ms p(95)=655.2ms iterations.....................: 36 3.472534/s passed_rate....................: 100.00% ✓ 36 ✗ 0 test_counter...................: 36 3.472534/s vus............................: 2 min=2 max=2 vus_max........................: 2 min=2 max=2
能够看到在输入中多了两行:
passed_rate....................: 100.00% ✓ 36 ✗ 0 test_counter...................: 36 3.472534/s
与咱们的预期相符。
不过这样看起来不够直观,咱们能够尝试应用 k6 Cloud 来展现后果。登陆后,只有在执行 k6 时,通过 -o cloud
的形式将输入指定到 cloud 就能够在 cloud 上看到所有的指标了
总结
本篇次要是在介绍一个现代化的用户体验绝对较好的压测工具 k6 。我目前正在打算将其引入到咱们我的项目的 CI 中,以便理解每次外围局部的变更对我的项目性能的影响。
后续推动顺利的话,会再分享 k6 如何利用到 CI 环境中,敬请期待。
欢送订阅我的文章公众号【MoeLove】