如何使用 K6 测试数据库查询的性能
抱歉,我需要您提供要翻译的具体文本内容(除 > Source: … 之外的部分),才能为您完成简体中文翻译。请把文章的正文粘贴过来,我会保持原有的 Markdown 格式、代码块和链接不变,只翻译文字部分。
先决条件 📑
了解 xk6-sql 模块 🧠
xk6-sql 是 k6 的官方扩展,允许在性能测试中直接执行 SQL 查询。使用它,可以连接到不同的关系型数据库(MySQL、PostgreSQL、SQL Server、SQLite 等),并执行以下操作:
- 创建表
- 插入数据
- 在性能测试周期中执行查询
要使用它,需要导入 k6/x/sql 模块以及对应数据库的驱动,例如:xk6-sql-driver-postgres。导入后,你可以:
- 打开与数据库的连接;
- 在配置阶段(
setup)执行 SQL 命令; - 在执行阶段处理实体数据;
- 在拆卸阶段(
teardown)关闭连接。
使用的应用 🛝
Padrinho – 一个职位发现应用,拥有公共路由,用户可以直接通过前端访问每个机会的详细信息。即使在这些路由上启用了缓存,详细查询仍涉及多个实体的连接,约占应用处理的所有请求的 60 % 到 65 %。
除了确保返回信息的一致性外,我们还需要处理 Supabase 上唯一的 PostgreSQL 实例的可用性,尤其是在流量高峰期(首次访问)时,当职位被首次查询且缓存中尚不存在时。
配置我们的脚本 👷🏻♀️
导入
import sql from "k6/x/sql";
import postgres from "k6/x/sql/driver/postgres";
import { SharedArray } from "k6/data";
import { check } from "k6";
import { QUERY_DETALHE_VAGA } from "./query.js";
Nota: 从 k6 1.2.1 版本开始,引入了 Automatic extension resolution 功能。不再需要为 xk6 模块或不属于 k6 核心的模块创建自定义二进制,只需将标志
K6_ENABLE_COMMUNITY_EXTENSIONS设置为true。日志示例:
INFO[0000] Automatic extension resolution is enabled. The current k6 binary doesn't satisfy all dependencies, it's required to provision a custom binary. deps="k6/x/faker*"
INFO[0000] A new k6 binary has been provisioned with version(s): k6:v1.4.2 k6/x/faker:v0.4.4
测试选项
export const options = {
vus: 10,
iterations: 100,
duration: "5s",
};
我们定义 100 次迭代将在 最多 5 秒内完成,使用 10 个 VUs。
添加阈值
export const options = {
vus: 5,
iterations: 100,
duration: "5s",
thresholds: {
iteration_duration: [
"p(90) **Importante:** Nunca defina valores sensíveis diretamente no código."
]
}
};
与数据库的连接(setup)
export function setup() {
if (!host || !port || !dbname || !user || !password) {
throw new Error(
"Variáveis DB_HOST, DB_PORT, DB_NAME, DB_USER e DB_PASSWORD são obrigatórias."
);
}
const connectionString = `postgres://${user}:${password}@${host}:${port}/${dbname}?sslmode=${ssl}`;
const db = sql.open(postgres, connectionString);
return db;
}
第2步 – 定义查询批次
在第二步中,将定义用于查询我们数据库的批次。我们将使用一些在 .json 文件中定义的查询 ID,需要将其读取到 SharedArray 结构中:
const nanoIds = new SharedArray("nano_ids", () => {
return JSON.parse(open("./nanoids.json"));
});
第三步 – 执行查询
在已定义好数据集并打开数据库连接后,我们可以在执行阶段定义查询。其目的是将加载到 SharedArray 中的 ID 分配给所有计划在运行期间使用的 VU,向数据库发起查询,并确认查询返回了数据。由于我们在配置中没有设置延迟,VUs 将在配置的时间间隔内尽可能多地发送请求。
export default function (db) {
const nanoId = nanoIds[Math.floor(Math.random() * nanoIds.length)];
const result = db.query(QUERY_DETALHE_VAGA, nanoId);
check(result, {
"consulta executada": (rows) => rows.length >= 0,
});
}
第四阶段 – 拆卸
后执行阶段,在拆卸阶段,我们将关闭与数据库的连接:
export function teardown(db) {
db.close();
}
脚本结果 🧑🔬
在后执行的输出结果中,我们将获得迭代的主要指标,包括 avg、min、med、max 以及百分位 p(90) 和 p(95)。
█ THRESHOLDS
iteration_duration
✗ 'p(90) *Nosso experimento foi conduzido em execução única utilizando um banco de dados gratuito da ferramenta **Supabase**.*
结论 ❤️
数据库查询的性能是一个关键因素,直接影响用户体验和应用的可扩展性。
正如本文所示,使用 xk6-sql 能够在单独的 SQL 查询中识别性能瓶颈,建立明确的基准线,并随时间监控性能下降。
将数据库性能测试集成到开发周期中,不仅可以防止生产环境的问题,还能提供客观的指标,以便在影响最终用户之前优先进行优化并验证改进。
喜欢本内容并想了解更多关于 K6 性能测试的内容吗?
查看我在 Udemy 的课程:
