Calico 跨仓库性能结果发布:把 perf 测试数据沉淀进 Lens Elasticsearch 长期趋势库
发布时间:2026/9/29 2:31:24来源:尧图网络
网络云原生网络安全【免费下载链接】calicoCloud native networking and network security项目地址https://gitcode.com/gh_mirrors/cal/calico点击查看免费下载本文介绍 Calico 单仓monorepo中hack/perf/目录的定位与用法它是一套把各类性能测试tiger-bench、felix/k8sfv、OpenStack Neutron→etcd resync 等的测量结果统一写入 Lens Elasticsearch/Kibana 集群、以便跨时间追踪趋势的“管道”plumbing。读完本文你将掌握测试方如何以“写 JSON 文件”的极简契约产出数据点、send-perf-results工具如何注入 CI 元数据并完成发布、索引模板与索引命名约定如何设计以及如何为一项新测试接入一个新的索引族index family并验证数据落地。为什么需要这套机制性能数据的“易逝性”问题Calico 单仓内已积累了相当规模的性能测试——tiger-bench、felix/k8sfv、OpenStack Neutron→etcd resync 计时等。历史上这些测试的结果都是易逝的打印到 CI 日志里日志轮转后即丢失。这导致两个经典问题无法回答“这次 PR 是不是拖慢了 endpoint 编程速度”“过去一个季度里Felix 的内存占用是不是在悄悄爬升”Lens 的 ES/Kibana 栈banzai-lens.dev-tools.tigera.net为结构化性能数据提供了落点与随时间可视化的能力。hack/perf/就是连接测试与 Lens 的正式通道canonical home。如果对底层 ES 客户端实现感兴趣tiger-bench 的pkg/elasticsearch/elasticsearch.go是值得阅读的先例而本目录在其之上抽象出了**生产者侧“写 JSON 文件”**的统一契约。需要特别澄清的是这套机制不是面向单 PR 的性能门禁同步、阻塞合并而是面向长期趋势可见性——捕捉渐进式回归、验证性能优化成果、在数据面/分支之间做跨时间对比。Lens 存储与凭据配置ES Kibana 入口https://banzai-lens.dev-tools.tigera.net现有仪表盘tiger-bench 的结果位于/app/dashboards#/view/856d49ee-c097-4c58-a6e7-1433475698fc。凭据与端点向#banzai频道或 Lens 集群的负责人索取 ES 端点 URL以ELASTICSEARCH_URL环境变量设置通常监听 9200 端口与上面的 Kibana URL 不同外加以下二选一ELASTICSEARCH_USERELASTICSEARCH_TOKENBasic 认证或ELASTICSEARCH_KEYAPI key首选。在 CI 中这些值作为 Semaphore 的 secrets 挂到运行你的测试的 pipeline 上在本地同样的环境变量也可用但要遵守下文的“运维卫生”约定不要用开发机运行污染趋势数据。目录结构hack/perf 里有什么hack/perf/ ├── cmd/send-perf-results/main.go # 把 JSON 文档推送到 ES 的工具 ├── index-templates/family.json # 每个索引族一个 ES 索引模板 └── README.md # 本文对应的原始文档仓库中当前已有两个真实的索引模板benchmark_data_neutron_resync.jsonOpenStack resync 规模测试与 benchmark_data_nft_dataplane.jsonFelix nftables 数据面基准可作为新族的直接参照。一个测试如何发布测量结果两步契约产生性能数据的测试只需做两件事每个测量写一个 JSON 文件到artifacts/perf/index_family/descriptive_name.json。每个文件是一条独立的 ES 文档只包含场景特定的标量——规模维度、指标、test_name等。CI 元数据git_commit、ci_run_id等不是生产者的职责见后文 Schema 一节。在生产该数据的 Semaphore job 末尾安排send-perf-results运行一次。最简单的模式是在 job 命令末尾加一行go run ./hack/perf/cmd/send-perf-results --dir artifacts/perf也可以调用预编译好的二进制。每个 job 恰好调用一次这是唯一需要的运维纪律——原因见“幂等性”一节。artifacts/perf/位于既有的artifacts/上传体系之下因此每个测量的 JSON 文件也会自动作为 Semaphore artifacts 被捕获——当某个数字看起来异常时可用于事后排查。仓库里的真实生产者印证了这一约定OpenStack resync 测试通过RESYNC_PERF_ARTIFACTS_DIR环境变量默认artifacts/perf控制输出目录逐迭代落盘 JSON 文件见 resync_scale_test.py 中的相关实现与注释Felix 的 nftables 基准测试则在NFT_BENCH_PERF_ARTIFACTS_DIR被设置时才输出文档见 felix/nftables/bench_test.go 中perfArtifactsEnvVar与perfFamily benchmark_data_nft_dataplane的定义从而保证普通go test运行不会污染长期趋势库。send-perf-results 到底做了什么每次调用工具按顺序执行以下步骤对应 main.go 的实现应用索引模板对hack/perf/index-templates/family.json中的每一个向 ES 的/_index_template/family发起 PUT。这是幂等的 upsert——具体意义见下一小节。遍历artifacts/perf/family/*.json对每个family子目录walkAndSend会警告并跳过顶层游离文件。为每个文档注入 CI 元数据timestamp、git_commit、git_branch、code_version、ci_run_id、pr_number、env除非生产者已提供该字段——生产者值优先。取值来自 CI 系统自身的变量Semaphore 下是SEMAPHORE_*ArgoCI 下是CI_GIT_*/CI_JOB_ID。POST 到family_UTC 年份/_doc年份后缀在发送时计算time.Now().UTC().Format(2006)生产者侧完全不用关心日期。ES 会在首次写入时依据第 1 步应用的模板自动创建带日期的索引。正常退出码为 0。一个关键设计哲学在源码注释里写得很明确“Lens 是可观测性设施不是关键路径”。工具只在真正不可恢复的情况下返回非零凭据缺失、ES 不可达、JSON 格式错误、映射冲突——全部记录 warning 并继续--require-publication标志可反转这一默认对“存在的意义就是发布”的调用方来说凭据缺失、某条文档发送失败、以及一条可发送的文档都没找到都会变成硬失败即使在--require-publication下索引模板 PUT 失败也仍是 warning——模板过期只会让新字段失去映射Kibana 不便并不会造成数据丢失。每周的 OpenStack resync 规模运行是仓库里唯一设置该标志的调用方。networking-calico/devstack/bootstrap.sh 中的实际用法展示了两种模式的对照定时运行SCALE_ONLYtrue把发布当作交付物--require-publication且不套|| true防止“测了全部却没发布任何数据”的假绿而逐 PR 运行则保持“Lens 是可观测性而非关键路径”用|| true兜底避免趋势库短暂不可达导致 PR 失败。模板 PUT 什么时候真正生效Elasticsearch 的索引模板只在索引创建时生效对已存在的索引不生效。一旦benchmark_data_family_2026存在其 mapping 就已固定再次 PUT 模板不会修改该索引。因此“每次运行都 PUT”的行为只在四个狭窄场景中有意义某族首次运行——在第一条文档落地前创建模板使首个自动创建的索引获得固定类型而非依赖 ES 的动态推断年份切换——新的一年里benchmark_data_family_YYYY会在首次写入时用当时集群状态中的模板自动创建集群重建或迁移——等价于场景 1防御性重放——如果模板因任何原因丢失master 故障切换的边角情况曾被观察到会丢条目下一次运行会把它放回去。在正常的稳态运行中模板已就位、年中时段PUT 是无操作。但每次运行仍会做原因有二(a) 每个族每个 CI job 只是一次 HTTP成本几乎为零(b) 场景 4 的自愈特性价值远超这点成本。年中编辑模板增删改字段、改类型不会影响已存活的索引新增字段会在首次现身时走动态映射推断删除的字段仍出现在旧文档的_source与存活索引的 mapping 中类型变更则可能触发写入拒绝映射冲突直到次年新索引带着新模板滚动出来。对于需要年中生效的类型变更更稳妥的做法是reindex 到改名索引如_2026_v2而不是和既有 mapping 硬刚。Schema什么才算一个好的数据点核心原则有三条一个测量 一条文档。不要把测试的整份原始输出塞成一条深层嵌套的文档先把它拆解成独立的标量测量。只允许扁平标量。每个字段都应是标量字符串、数字、布尔或标量的扁平数组。要避免嵌套对象如cold.phases.endpoints.compare_ms技术上可用但在 Kibana 里更难发现、可视化更笨重对象数组如steady: [{phases: ...}, {phases: ...}]ES 默认映射会把它们压平成并行的标量数组丢失元素间关联。Lens 无法对其绘图即使把字段映射为nested类型使其可查询Lens依然无法绘图——只能降级去写 TSVB 或 Vega。如果测试产出多个子测量如一次 “cold” 运行加三次 “steady” 迭代把它们展开成多条文档用phase/iter/test_step字段区分。生产者负责的字段场景特定的标量是生产者的职责test_name——标识场景族的稳定字符串与索引名区分如neutron_resync规模参数——如scale_endpoints: 10000、scale_policies: 100、scale_hosts: 10。字段名应对你的场景具体但在同一测试内保持一致被测量的指标扁平化如endpoints_total_ms而非endpoints.total_ms如果该文档是若干相关子测量之一加上phase/iter/test_step关键字如果测试可能部分成功加上ok: bool与可选的error: string适用时的场景上下文dataplaneiptables、nftables、ebpf、encapvxlan、ipip、none、k8s_version、cloudgcp、aws、azure、kind、node_type、node_count。工具注入的字段不要自己设置send-perf-results从 CI 环境补充以下字段除非生产者已提供值生产者优先timestamp——ISO-8601 UTCKibana 的时间字段git_commit——来自SEMAPHORE_GIT_SHA或CI_GIT_SHAgit_branch——来自SEMAPHORE_GIT_BRANCH或CI_GIT_BRANCHcode_version——由git_commit派生的短 SHA源码中取前 12 个字符ci_run_id——来自SEMAPHORE_JOB_ID、CI_JOB_ID或CI_WORKFLOW_NAMEpr_number——来自SEMAPHORE_GIT_PR_NUMBER或CI_GIT_PR_NUMBER仅在设置了 PR 号且非none时写入env——任一 run ID 已设置则为ci否则为dev可用PERF_ENV覆盖。仪表盘过滤env ! dev即可把开发机运行排除在趋势数据之外。源码中的firstEnv辅助函数按顺序读取多套 CI 变量因此测试在 CI 系统之间迁移时仍能落地完整文档而不是留下空白的 provenance 和env: dev那将与开发机运行无法区分、污染趋势数据。Semaphore 的值在两者同时存在时优先。定时运行应把PERF_ENV设为自定义值每周的 OpenStack resync 规模运行使用weekly。定时运行可能使用与逐 PR 运行不同的机器类型计时不可直接比较仪表盘应能将其分离。phase vs iter vs test_stepiter整数重复的整轮测试的序号如0表示 cold1..N表示 steady 轮次。phasekeyword测试不同阶段的标签cold、steady、setup、teardown。当每个阶段运行多次时与iter配合使用。test_stepkeyword单次测试运行内快照的标签如felix/k8sfv内存泄漏场景中的snap_0、snap_1……。用于测试内的时序iter用于重复的整轮运行。三者可以共存一个运行三次 steady 迭代、每次迭代拍 20 张堆快照的测试会有iter ∈ {1,2,3}、phase steady、test_step ∈ {snap_0, ..., snap_19}。索引命名约定索引命名为family_period-suffixfamily是benchmark_data_test如benchmark_data_neutron_resyncperiod-suffix是YYYY年度或YYYY-MM月度。不要用日度。send-perf-results固定写入年度后缀。对大多数单仓性能测试年度是正确的默认——分片数最少、集群状态开销最低数据量留有充足余量。只有以下情况才选月度高文档量一年的数据可能超过单个索引 10 GB。ES 希望主分片处于 10–50 GB 区间按每文档约 500 字节算年度索引可舒适容纳约 2000 万条文档——当前没有任何测试接近这个量级年内保留策略年度索引意味着必须等到跨年才能清理数据频繁的 schema 演进月度索引提供了自然的重置点。在 Kibana 中为每个族创建一个带通配符的索引模式benchmark_data_test_*这样年度/月度后缀都能被覆盖日后切换粒度也不会失去连续性。为什么不用日度日度索引会过度碎片化本就很低频的性能数据几百个近乎空的分片浪费堆内存、集群状态膨胀、查询扇出代价高昂而且动态映射推断每年有 365 次漂移机会而非 1 次。tiger-bench 的既有索引早于该约定可维持现状新测试族应遵循该约定。接入一个新的索引族五步操作按benchmark_data_test规则选一个族名。添加hack/perf/index-templates/family.json至少覆盖元数据字段加上你的场景特定数值指标。可参考下面的入门模板。让测试写入artifacts/perf/family/*.json。在产出数据的 Semaphore job 末尾加入send-perf-results调用如果之前的族没加过。首次 CI 运行后按“验证数据落地”一节核对数据。入门索引模板一个覆盖元数据字段与total_ms指标的最小模板如下。把它放到hack/perf/index-templates/benchmark_data_test.json并在total_ms旁追加你的场景数值字段{ index_patterns: [benchmark_data_test_*], template: { mappings: { properties: { timestamp: {type: date}, git_commit: {type: keyword}, git_branch: {type: keyword}, ci_run_id: {type: keyword}, code_version: {type: keyword}, pr_number: {type: keyword}, test_name: {type: keyword}, dataplane: {type: keyword}, encap: {type: keyword}, k8s_version: {type: keyword}, cloud: {type: keyword}, node_type: {type: keyword}, env: {type: keyword}, phase: {type: keyword}, test_step: {type: keyword}, iter: {type: integer}, ok: {type: boolean}, error: {type: keyword}, total_ms: {type: double} } } } }把index_patterns中的test替换为你的族后缀。任何可能变成小数的数值指标都应固定为double见下方“数值类型变宽”。对照真实模板可看到完整的形态benchmark_data_neutron_resync.json 定义了scale_ports/scale_networks/scale_sgs/scale_hosts等规模字段以及total_ms、expand_total_ms、subnets_*、policy_*、endpoints_*、felix_config_total_ms等细分阶段计时与计数指标benchmark_data_nft_dataplane.json 则定义了scale_ipsets/scale_set_members/scale_chains/scale_rules与wall_ns_per_op/cpu_ns_per_op/bytes_per_op/allocs_per_op这类每操作指标。ES schema 陷阱清单动态映射推断ES 依据写入每个新索引的第一条文档推断字段类型。如果某个周期首条文档error: null下个周期首条却是error: timeout就会产生跨索引模式的映射不一致Kibana 显示 “conflict” 警告。修法依赖索引模板send-perf-results每次调用都会应用模板模板变更会自动传播。即便只固定一小撮已知字段也能避免大多数意外。textvskeywordES 默认动态映射把字符串映射为text可全文搜索不可聚合并附带.keyword子字段。若想按git_branch过滤或分组就得写git_branch.keyword。在模板里把字符串字段固定为keyword要自然得多。字段数上限ES 默认限制一个索引最多 1000 个字段。扁平文档不会触及深层嵌套文档却可能惊人地快触顶。数值类型变宽如果首条文档total_ms: 100被映射为long之后出现total_ms: 100.5后者的推送会因映射冲突失败。模板中凡可能走小数的数值指标都应固定为double。Kibana 可视化陷阱清单Lens默认可视化器不绘制nested类型的字段。TSVB 和 Vega 可以但你不会想为这个去写 Vega。避免嵌套字段。必须有时区字段Kibana 索引模式需要日期字段才能启用时间序列视图用timestamp。索引模式通配符每个测试族一个benchmark_data_neutron_resync_*覆盖年度与月度后缀。棘手场景的模式单次运行的多次迭代cold N 轮 steady每个迭代推送一条文档用phase和iter区分{ phase: cold, iter: 0, total_ms: 6798, ... } { phase: steady, iter: 1, total_ms: 4769, ... } { phase: steady, iter: 2, total_ms: 4730, ... } { phase: steady, iter: 3, total_ms: 4672, ... }在 Kibana 中按phase: steady过滤后绘制total_ms的中位数或并排对比 cold 与 steady。单次运行内的时序对felix/k8sfv内存泄漏这类长时间运行中持续拍堆快照的测试每个快照推一条带test_step标签的文档{ test_step: snap_0, heap_alloc_bytes: 12345678, ... } { test_step: snap_1, heap_alloc_bytes: 13456789, ... } ... { test_step: snap_19, heap_alloc_bytes: 25678901, ... }每条文档仍会带上完整元数据commit、branch、ci_run_id——这些在同一运行内跨文档重复。ES 处理这种重复毫无压力Kibana 可以绘制heap_alloc_bytes随test_step的变化并以git_commit作为系列拆分做跨运行对比。通过与失败伴随连续指标直接把ok: true|false及可选的error: message放在与计时相同的文档上即可。Kibana 可以在同一仪表盘里以独立可视化绘制各场景的失败率。测试失败或部分结果如果测试中途崩溃部分指标可用把已有的文件写成ok: false加error: reason。一条 “test failed at scale1000” 的数据点本身就是有价值的趋势信息没有任何可用数据如基础设施在测试开始前就挂了不要写文件。一条处处null的文档只会制造噪音——失败记录交给 CI 日志即可。运维卫生不要从本地开发运行推送。多数开发者本来就没有 Lens 凭据——send-perf-results在ELASTICSEARCH_URL未设置时会静默跳过。若确实在本地推送例如为测试工具本身注入的env: dev让仪表盘可以过滤掉开发运行。索引保留。向 Lens 集群负责人确认benchmark_data_*是否配置了 ILMIndex Lifecycle Management。若未配置索引会无限累积值得建立一条把旧索引滚动到更廉价层级的 ILM 策略。Schema 演进。如果需要改变某个字段的含义不要原地修补既有族——新建一个族benchmark_data_neutron_resync_v2_*并更新仪表盘。跨周期对抗类型漂移的痛苦远超从头开始。验证数据是否落地首次 CI 运行后先确认文档进了 ES 再继续。在 Kibana →Dev Tools中GET benchmark_data_test_*/_search { size: 5, sort: [{timestamp: desc}] }应能看到最近的文档且字段与类型符合预期。如果某字段显示为text而你期望keyword说明索引模板未生效——检查模板的index_patterns是否与实际索引名匹配。从 shell 验证curl -s $ELASTICSEARCH_URL/benchmark_data_test_*/_search?size5sorttimestamp:desc \ -H Authorization: ApiKey $ELASTICSEARCH_KEY | jq .hits.hits查看特定索引推断出的 mappingGET benchmark_data_test_2026/_mapping推送数据之后下一步创建 Kibana 索引模式Stack Management → Index Patterns → Create模式benchmark_data_your_test_*时间字段timestamp。构建一个入门 Lens 可视化把主指标拖到 Y 轴、timestamp拖到 X 轴用dataplane或git_branch作为系列拆分。保存到仪表盘加上env: ci及基线场景设置的过滤器。分享仪表盘 URL把它放在测试文档旁边让其他人能看到该测试的历史趋势。本地开发与干跑要脱离 ES、仅以本地文件流测试工具本身go run ./hack/perf/cmd/send-perf-results --dry-run --dir /tmp/some/perf--dry-run只打印“将要 POST 什么”而不接触 ES源码中它也会跳过模板应用步骤。工具还支持--templates指定模板目录配合--dir、--dry-run、--require-publication四个标志足以覆盖从本地排错到 CI 发布门禁的全部场景。结语hack/perf/的设计刻意把“生产”与“发布”解耦测试方只需在artifacts/perf/family/下写出扁平、标量的 JSON 文档其余全部交给send-perf-results——模板自愈、CI 元数据注入、年度索引滚动都由此工具在每次调用时自动完成。对调用方而言唯一真正的纪律是“每个 job 恰好发布一次”对运维而言则是“不要把开发机运行混进env: ci的趋势数据”。遵循本文的索引族接入五步与 schema 约定任何新性能测试都能在十几分钟内获得跨季度、可对比、可追溯的趋势仪表盘。赞分享网络云原生网络安全【免费下载链接】calicoCloud native networking and network security项目地址https://gitcode.com/gh_mirrors/cal/calico点击查看免费下载相关推荐告别ExcelJMeter性能测试结果一键入数据库实现长期趋势分析告别ExcelJMeter性能测试结果一键入数据库实现长期趋势分析 Apache JMeter作为一款开源的性能测试工具能够分析和测量各种服务的性能。但很多测试质量保障Telegraf趋势分析长期性能趋势预测Telegraf趋势分析长期性能趋势预测 引言为什么需要长期性能趋势预测 在当今复杂的IT环境中系统性能监控已从简单的实时告警演变为需要深度洞察和预测性可观测性指标监控运维Crawlee-Python时序数据库集成长期趋势分析Crawlee Python时序数据库集成长期趋势分析 引言为什么需要时序数据库集成 你是否还在为网络爬虫数据的长期存储与趋势分析而烦恼当爬取数据量达到网页爬虫浏览器控制上一篇Semantic-UI-React组件库架构解析代码组织与设计理念下一篇PPTAgent WebUI 实战可视化界面里 AI 智能体如何自动为你做 PPT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网