ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ZITADEL 压测实战:基于 k6 + xk6 的 API 端点基准测试框架全解(benchmark)

ZITADEL 压测实战:基于 k6 + xk6 的 API 端点基准测试框架全解(benchmark) ZITADEL 压测实战基于 k6 xk6 的 API 端点基准测试框架全解benchmark【免费下载链接】zitadelZITADEL - Identity infrastructure, simplified for you.项目地址: https://gitcode.com/GitHub_Trending/zi/zitadel本文以 ZITADEL 仓库中的 benchmark 目录为核心系统讲解其基于 k6/xk6 的 API 端点压测框架从环境准备、Makefile 驱动的执行流程到 16 个内置用例登录、OIDC 会话、用户列表查询等的 setup/test/teardown 模型并深入源码剖析参数解析、并发限流与结果判读方式。读完后你可以独立完成针对 ZITADEL API 的基准测试运行、参数调优与结果分析。一、benchmark 包是什么ZITADEL 的benchmark目录包含针对 API 特定端点进行基准测试的代码底层压测引擎为 k6Grafana 开源的负载测试工具并通过 xk6k6 的扩展机制将 ZITADEL 特有的认证与资源创建逻辑以 Go 模块形式注入到 k6 运行时中。整体设计特点TypeScript 编写用例每个压测场景是一个独立的 k6 脚本*.ts由 webpack 统一打包为 k6 可执行的 JSMakefile 统一入口所有场景都通过make 用例名触发自动完成依赖克隆、模块构建、打包与压测执行CSV 结果落盘每次运行按时间戳输出 CSV便于事后统计与比对用例即文档16 个用例覆盖登录 UI、机器身份PAT、client credentials、JWT、会话管理、用户列表查询、投影一致性校验等 ZITADEL 核心链路。二、前置条件运行压测前需要准备以下工具见 benchmark/README.mdnpmNode.js 包管理器用于安装 TypeScript 依赖与执行 webpack 打包k6压测引擎本体goxk6 构建扩展二进制需要 Go 工具链xk6安装后需确保~/go/bin在PATH中因为xk6 build生成的 k6 二进制会落在该目录一个运行中的 ZITADEL API 实例默认假定为http://localhost:8080。此外Makefile 中的ensure_modules目标会在仓库根目录克隆 Zitadel 官方的xk6-modules仓库zitadel/xk6-modules后续所有构建与执行都围绕它进行。从 Makefile 可以看到关键约定K6 : ./../../xk6-modules/k6 # 由 xk6 build 产出的 k6 二进制 ensure_modules: ifeq (,$(wildcard $(PWD)/../../xk6-modules)) echo cloning xk6-modules cd ../.. git clone https://github.com/zitadel/xk6-modules.git endif cd ../../xk6-modules git pull即xk6-modules 目录位于 Zitadel 仓库的同级目录且每次执行会git pull保持最新。三、目录结构与代码组织benchmark 的目录布局src/use_cases/被测用例的定义处。每个文件对应一个make目标如 human_password_login.ts、users_by_login_name.ts、introspection.ts 等会话类用例集中在 src/use_cases/session/ 子目录add_session.ts、oidc_session.ts、otp_session.ts、password_session.ts。src/ZITADEL 资源与 API 调用的实现层被用例复用例如 user.ts创建人类用户/查询用户列表、org.ts组织生命周期、login_ui.ts登录 UI 流程、oidc.tsOIDC 端点、metadata.ts、user_grant.ts 等app.ts 封装了 API 应用与密钥创建并内建 k6Trend指标如app_add_app_duration记录每步耗时。Makefile全部执行入口。webpack.config.js将src/use_cases/**/*.ts按 glob 生成多入口逐个打包为dist/用例名.js。postmortems/真实压测事件的复盘记录见第八节。四、压测参数环境变量与默认值所有参数通过环境变量传入Makefile 中定义了前 5 个的默认占位Makefile 第 1–6 行用例脚本内解析其余参数。完整参数表环境变量说明默认值VUS并行执行的虚拟用户进程数量20DURATION压测执行时长200sZITADEL_HOSTZITADEL 实例的 URLhttp://localhost:8080ADMIN_LOGIN_NAME管理员人类用户的登录名需具备IAM_OWNER角色本地默认zitadel-adminzitadel.localhostADMIN_PASSWORD该管理员用户的密码本地默认Password1!USER_AMOUNT为 list-users 基准测试在 setup 阶段创建的用户数2500SETUP_CONCURRENCYlist-users setup 阶段创建用户时的最大在途请求数50两个要点需要注意管理员权限要求setup 阶段使用管理控制台的凭据以管理员身份登录该用户必须能创建组织以及组织内的所有资源README 原文要求。本地初始化实例自带上述默认管理员账号可直接使用。SETUP_CONCURRENCY的存在原因当USER_AMOUNT很大且创建请求无上限并行时会耗尽本机临时端口报错cant assign requested address。这正是 pool.ts 中mapPool要解决的问题见第六节。五、执行方式与 16 个内置用例5.1 通用执行模式每个用例都遵循相同的 k6 三阶段模型setup()以管理员身份登录、创建组织与前置资源→ 主函数按__VU分配工作并施压→teardown()清理资源。以 human_password_login.ts 为例export async function setup() { const tokens loginByUsernamePassword(Config.admin as User); // 管理员登录 const org await createOrg(tokens.accessToken!); // 新建组织 const humanPromises Array.from({ length: MaxVUs() }, (_, i) createHuman(zitizen-${i}, org, tokens.accessToken!)); // 为每个 VU 建一个人类用户 ... } export default function (data: any) { const token loginByUsernamePassword(data.users[__VU - 1]); // 第 __VU 个用户走登录 UI userinfo(token.accessToken!); // 再调 user info 端点 } export function teardown(data: any) { removeOrg(data.org, data.tokens.accessToken); // 删除组织 }重要前提运行测试前需要一个已初始化的用户账号因为测试没有实现登录过程中的“强制修改密码”界面README 明确要求。5.2 用例清单make 目标setup 做什么test 做什么human_password_login创建人类用户用这些用户通过登录 UI 签名再调 user infomachine_pat_login创建 machine并为每个 machine 建一个 PAT用 PAT 调 user info 端点machine_client_credentials_login创建 machine并为每个 machine 建 client credentials secret以client_credentialsgrant type 调 token 端点user_info创建人类用户并使其登录用这些用户调 user info 端点manipulate_user—创建一个人类用户、更新其资料、锁定用户、再删除它introspect创建项目、每项目一个 API、每 API 一个密钥并用密钥生成 JWT用这些 JWT 调 introspection 端点add_session创建人类用户以 user id check 方式创建新会话oidc_session创建 service account 以便创建 auth request 与 session创建 auth request、创建 session 并把 session 关联到 auth request即 ZITADEL 登录 UI 的标准 OIDC 集成流程otp_session为每个 VU 创建一个人类用户并绑定 OTP Email基于登录名创建会话设置 OTP Email 挑战最后校验 OTP 码password_session为每个 VU 创建一个人类用户基于登录名创建会话第二步校验密码machine_jwt_profile_grant生成公私钥、创建 service account、添加密钥创建 token 并调 user infomachine_jwt_profile_grant_single_user生成公私钥、创建单个 service account、添加密钥对同一个用户并行创建 token 并调 user info并发热点场景users_by_metadata_key一半 VU 建人类用户另一半建 machine每个用户加 3 条 metadata调 list users 端点并按 metadatakey过滤users_by_metadata_value同上调 list users 端点并按 metadatavalue过滤users_by_login_name在新组织中以SETUP_CONCURRENCY并行度创建USER_AMOUNT个用户默认 2500以与 login v2 相同的方式调 ListUsersloginNameQueryEQUALS_IGNORE_CASE、organizationIdQuery、limit: 2verify_all_user_grants_exists创建 50 个项目、每个 VU 一台 machine创建 machine 并把全部项目授予该 machine补充细节verify_all_user_grants_exists的 teardown故意不删除组织以便事后人工核对投影projections数据的正确性详见 verify_all_user_grants_exist.ts。users_by_login_name的 README 备注要在旧查询计划下复现秒级延迟应使用大数据集例如USER_AMOUNT100000 VUS10 DURATION60s。5.3 k6 命令行与结果输出Makefile 中每个目标本质上是同一条命令模板human_password_login: bundle ${K6} run --summary-trend-stats min,avg,max,p(50),p(95),p(99) \ dist/human_password_login.js \ --vus ${VUS} --duration ${DURATION} \ --out csvoutput/human_password_login_${DATE}.csv--summary-trend-stats min,avg,max,p(50),p(95),p(99)在最终摘要中输出 min/avg/max 与 p50/p95/p99 分位耗时--out csvoutput/用例_${DATE}.csv逐请求明细落盘DATE由$(shell date %d-%H:%M:%S)生成bundle目标会先mkdir -p output注意verify_all_user_grants_exist目标未启用--out csv该行被注释说明它更关注校验而非延迟。部分目标如introspect、machine_jwt_profile_grant、oidc_session等比bundle多依赖ensure_key_pair与ensure_modules因为需要本地生成的 RSA 密钥对用于 JWT/profile 类流程。六、构建机制深入bundle、xk6 模块与密钥生成6.1 webpack 打包webpack.config.js 的关键配置entry: GlobEntries(./src/use_cases/**/*.ts), // 每个用例一个入口 output: { path: path.join(__dirname, dist), libraryTarget: commonjs, filename: [name].js }, externals: /^(k6|https?\:\/\/)(\/.*)?/, // k6 内置模块与 CDN 依赖不打包 devtool: source-map, optimization: { minimize: false }, // 不在浏览器中运行无需压缩TypeScript 由 babel-loader 转译k6 内置模块k6/http、k6/crypto等和https://jslib.k6.io/...远程模块被标记为 external由 k6 运行时在沙箱中提供。package.json 声明 Node 引擎为18 || 20TypeScript 5.9 webpack 5。bundle目标完整流程Makefile 第 98–104 行bundle: mkdir -p output npm i npm run bundle # webpack 打包 src/use_cases/**/*.ts - dist/ go install go.k6.io/xk6/cmd/xk6latest # 安装 xk6 CLI cd ../../xk6-modules xk6 build --with xk6-zitadel. # 构建带 ZITADEL 扩展的 k6 二进制最后一步是 xk6 的核心价值所在xk6 build --with xk6-zitadel.把 xk6-modules 中的 ZITADEL Go 扩展编译进 k6产出的二进制即xk6-modules/k6也就是K6变量指向的路径从而使 k6 脚本可以调用 ZITADEL 特定的认证扩展。6.2 RSA 密钥对生成ensure_key_pair目标用 openssl 生成 2048 位密钥对Makefile 第 106–116 行ensure_key_pair: ifeq (,$(wildcard $(PWD)/.keys)) mkdir .keys endif ifeq (,$(wildcard $(PWD)/.keys/key.pem)) openssl genrsa -out .keys/key.pem 2048 endif ifeq (,$(wildcard $(PWD)/.keys/key.pem.pub)) openssl rsa -in .keys/key.pem -outform PEM -pubout -out .keys/key.pem.pub endif生成的benchmark/.keys/key.pem私钥与key.pem.pub公钥供 JWT profile grant 等用例使用私钥留在客户端用于签名 JWT公钥需配置到 ZITADEL 的 service account 上。6.3 配置加载Config 与 MaxVUsconfig.ts 是所有用例共享的配置中枢export const Config { host: __ENV.ZITADEL_HOST || http://localhost:8080, orgId: , codeVerifier: __ENV.CODE_VERIFIER || randomString(10), admin: { loginName: __ENV.ADMIN_LOGIN_NAME || zitadel-adminzitadel.localhost, password: __ENV.ADMIN_PASSWORD || Password1!, }, };这里印证了 README 的默认值并补充两点codeVerifier用于 PKCES256code challenge 由crypto.sha256派生支持CODE_VERIFIER环境变量注入——README 未列出该参数但从源码看它服务于登录 UI 的授权码流程Client()函数在CLIENT_ID未设置时会请求/ui/console/assets/environment.json并读取其中的clientid即从运行中的实例动态获取管理控制台的 client_id避免硬编码。同文件的MaxVUs()从 k6 的stages/scenarios选项推断本次运行的最大 VU 数供 setup 阶段决定要创建多少个用户每个 VU 一个专属用户避免并发竞争同一账号。6.4 有限并发mapPoolpool.ts 实现了一个固定在途任务数的mapPool注释明确说明动机对大USER_AMOUNT数据集做无界Promise.all会耗尽临时端口。users_by_login_name.ts 是它的典型消费者const userAmount parseInt(__ENV.USER_AMOUNT) || 2500; const setupConcurrency parseInt(__ENV.SETUP_CONCURRENCY) || 50; const users await mapPool( Array.from({ length: userAmount }, (_, i) i), setupConcurrency, async (i) { const user await createHuman(zitizen-${i}, org, tokens.accessToken!); ... }, );mapPool内部启动min(concurrency, items.length)个 worker每个 worker 顺序领取索引执行既保持写入顺序又硬性约束在途请求数——这正是SETUP_CONCURRENCY参数的实现落点。七、深入一个用例users_by_login_name 的完整数据流users_by_login_nameusers_by_login_name.ts是理解整套框架的最佳样本因为它完整覆盖了 setup/teardown、大数据量参数与查询结构setup管理员登录 →createOrg→ 用mapPool以 50 并发创建 2500 个zitizen-i用户每 1% 打印一次进度→ 取第一个用户的登录名作为查询目标test每个 VU 调用 ListUsers查询结构与登录 v2 完全一致query: { limit: 2 }, queries: [ { loginNameQuery: { loginName: data.targetLoginName, method: TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE } }, { organizationIdQuery: { organizationId: data.org.organizationId } }, ],随后check校验“恰好查到 1 个用户”不满足时打印result与totalResult的调试信息而不抛错——压测脚本以“尽量不中断”为原则teardownremoveOrg删除组织及其所有用户。该用例的设计意图是在压测负载下验证登录名查询登录 v2 的核心路径的延迟与正确性README 给出的USER_AMOUNT100000 VUS10 DURATION60s组合用于在旧查询计划下复现秒级延迟属于回归验证性质的用法。八、结果判读从一次 503 事件复盘看 CSV 的权威地位postmortems/2026-08-27-503-burst.md 记录了 v4.17.1 压测扫描中两次 HTTP 503 突发Service error -27来自云前端而非 ZITADEL 的 JSON 错误的完整调查过程其中几条经验对使用本框架的人非常有价值失败计数以 CSV 为准而不是 k6 的错误输出行数。burst 1 中 150 个失败请求里只有 29 个表现为抛出的 k6 错误其余 121 个落在 update/lock/delete 上check 失败但不 throw复盘明确写道“failure counts are taken from the CSV and not fromgrep -c levelerroron the log”。区分两类失败群体。同一轮manipulate_user运行中存在两个无关的失败群体一次 55 秒的基础设施 503 突发与 25 分钟后由持续负载导致的应用层超时退化文档化的“sustained churn 退化行为”二者必须分开报告否则会把基础设施事件误记为 ZITADEL 的失败率。指标与日志需交叉验证该复盘用 Cloud Run 的启动指标排除了容器重启假设同时指出日志查询本身可能因过滤器写错而“看起来像答案”强调先建 control 再下结论。这些经验共同指向一条使用准则阅读output/*.csv的逐请求明细与状态码分布再结合终端的--summary-trend-stats分位数摘要做结论。九、快速上手清单综合以上针对本地开发实例http://localhost:8080默认管理员账号的最小可行流程cd benchmark npm i # 安装 TS 依赖 make bundle # 克隆/更新 xk6-modules、webpack 打包、xk6 build VUS20 DURATION60s make human_password_login VUS20 DURATION60s make user_info USER_AMOUNT2500 SETUP_CONCURRENCY50 make users_by_login_name针对远端实例则显式指定环境变量ZITADEL_HOSThttps://zitadel.example.com \ ADMIN_LOGIN_NAMEadminexample.com \ ADMIN_PASSWORDpassword \ make machine_client_credentials_login使用限制与注意事项汇总被测账号必须是已初始化的用户无需再走修改密码流程管理员账号需能创建组织及组织内全部资源IAM_OWNER需要网络访问以克隆/更新 xk6-modules 仓库、npm i与go install xk6大USER_AMOUNT场景务必配合SETUP_CONCURRENCY避免本地临时端口耗尽JWT 相关用例依赖ensure_key_pair生成的.keys/密钥对且公钥需已配置到对应的 service accountverify_all_user_grants_exists结束后组织会被保留需自行决定是否清理用于投影数据的人工核验。十、小结ZITADEL 的 benchmark 框架把“压测脚本工程化”做到了可直接复制的程度webpack 多入口打包让每个用例独立可执行xk6 扩展把 ZITADEL 认证逻辑下沉到 Go 层Makefile 统一了参数、统计口径与 CSV 输出而mapPool、Config/MaxVUs等工具模块则解决了大样本 setup 的稳定性问题。配合 README 中 16 个用例的 setup/test 说明与 postmortems 中的判读经验它既是性能回归的工具集也是理解 ZITADEL 各端点登录 UI、OIDC、introspection、ListUsers、投影一致性实际行为的一份活文档。【免费下载链接】zitadelZITADEL - Identity infrastructure, simplified for you.项目地址: https://gitcode.com/GitHub_Trending/zi/zitadel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表