<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>综合实战 on Dorkytiger 的小屋</title>
    <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/</link>
    <description>Recent content in 综合实战 on Dorkytiger 的小屋</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <atom:link href="https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>项目设定与埋雷清单</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/01-project-setup/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/01-project-setup/</guid>
      <description>&lt;h1 id=&#34;91-项目设定与埋雷清单&#34;&gt;9.1 项目设定与埋雷清单&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：无　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/02-step1-goals/&#34;&gt;9.2 步骤一：定义目标&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/01-project-setup/&#34;&gt;09-capstone/01-project-setup&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;为了让这个实战有东西可查，你必须故意保留几个已知问题。&lt;/strong&gt; 一个&amp;quot;什么都对&amp;quot;的服务，练不出定位能力——&lt;strong&gt;六颗埋雷是本章最重要的准备&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一服务设计短链服务&#34;&gt;一、服务设计：短链服务&lt;/h2&gt;
&lt;h3 id=&#34;两个接口&#34;&gt;两个接口&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /links              创建短链
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  body: { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://example.com/very/long/url&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;→&lt;/span&gt; { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;aB3xK9&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET /{code}              跳转
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;→&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;302&lt;/span&gt; Location: https:&lt;span style=&#34;color:#75715e&#34;&gt;//example.com/very/long/url
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么这两个接口够用&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特征&lt;/th&gt;
					&lt;th&gt;对应知识点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;读多写少（读:写 ≈ 50:1）&lt;/td&gt;
					&lt;td&gt;缓存策略（第 7.4 节）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;热门短链被反复访问&lt;/td&gt;
					&lt;td&gt;幂律分布（第 5.5 节）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;读路径有缓存命中/未命中&lt;/td&gt;
					&lt;td&gt;缓存对 P99 的影响（第 7.4 节）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;写路径有唯一索引冲突&lt;/td&gt;
					&lt;td&gt;数据库错误处理（第 6.6 节）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;代码短（6 位 base62）&lt;/td&gt;
					&lt;td&gt;可以自然地做&amp;quot;加索引/不加索引&amp;quot;的对比&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;数据表&#34;&gt;数据表&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; links (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    id          BIGSERIAL &lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;KEY&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    code        TEXT &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,              &lt;span style=&#34;color:#75715e&#34;&gt;-- 短码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    url         TEXT &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,              &lt;span style=&#34;color:#75715e&#34;&gt;-- 原始 URL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    user_id     BIGINT &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,            &lt;span style=&#34;color:#75715e&#34;&gt;-- 创建者（用于热点分析）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    created_at  TIMESTAMPTZ &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; now(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hits        BIGINT &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DEFAULT&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;-- 访问计数（用于写路径演示）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;-- ⚠️ 注意：故意先不建 code 的唯一索引（见埋雷清单）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;二六颗埋雷本章的核心准备&#34;&gt;二、六颗埋雷（本章的核心准备）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;这六个问题对应第 6 章的六个瓶颈模式&lt;/strong&gt;。请在实现时刻意保留它们，&lt;strong&gt;不要提前修&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤一：定义目标</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/02-step1-goals/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/02-step1-goals/</guid>
      <description>&lt;h1 id=&#34;92-步骤一定义目标&#34;&gt;9.2 步骤一：定义目标&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/01-project-setup/&#34;&gt;9.1 项目设定与埋雷清单&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/03-step2-build-service/&#34;&gt;9.3 步骤二：搭服务与数据&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/&#34;&gt;第 1 章&lt;/a&gt;（SLO 四要素、延迟预算）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/02-step1-goals/&#34;&gt;09-capstone/02-step1-goals&lt;/a&gt;
产出：&lt;code&gt;docs/slo.md&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;这一步决定后面所有工作的方向。&lt;/strong&gt; 没有 SLO，「优化」就是无的放矢——因为你不知道要优化到多少才算够。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一要回答的三个问题&#34;&gt;一、要回答的三个问题&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;问题&lt;/th&gt;
					&lt;th&gt;为什么必须先答&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;峰值 QPS 是多少？&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;决定容量规划与压测强度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;用户能接受多慢？&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;决定 SLO 阈值（不能拍脑袋）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;数据会涨到多大？&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;决定测试数据量与容量规划的时间跨度&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;如果这三个答不出来&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;① 去问业务方（这是产品决策，不是技术决策）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;② 或者从现有监控里取真实数据
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;③ 实在拿不到 → 在 SLO 表里标注「待确认」，并写明打算怎么获取
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;「待确认」本身就是一个有价值的产出&lt;/strong&gt;——它暴露了「目前的性能目标没有依据」这个事实。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二slo-表四要素&#34;&gt;二、SLO 表（四要素）&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- docs/slo.md --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# SLO 表
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;font-style:italic&#34;&gt;最后更新：YYYY-MM-DD　|　对应版本：&amp;lt;commit&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;font-style:italic&#34;&gt;填写说明：四要素缺一不可。写不出来的标「待确认」，并注明获取方式。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## 接口 1：GET /{code}（跳转）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 字段 | 值 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| --- | --- |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 接口 | &lt;span style=&#34;color:#e6db74&#34;&gt;`GET /{code}`&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 关键路径 | 客户端 → 服务 → Redis → PostgreSQL |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| &lt;span style=&#34;font-weight:bold&#34;&gt;**目标 QPS（峰值）**&lt;/span&gt; | 3000 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| &lt;span style=&#34;font-weight:bold&#34;&gt;**P50 / P95 / P99 / P999**&lt;/span&gt; | 5 / 30 / 100 / 300 ms |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| &lt;span style=&#34;font-weight:bold&#34;&gt;**错误率阈值**&lt;/span&gt; | &amp;lt; 0.1% |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 超时率阈值 | &amp;lt; 0.05% |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 负载前提：数据量 | 100 万条 links |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 负载前提：**数据分布** | &lt;span style=&#34;font-weight:bold&#34;&gt;**幂律（齐夫，alpha≈1.2）**&lt;/span&gt;：前 1% 的 code 承担 40% 访问 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 负载前提：缓存状态 | warm（预热 5 分钟） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| &lt;span style=&#34;font-weight:bold&#34;&gt;**测量点**&lt;/span&gt; | 压测客户端（最接近用户体验） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 预热时长 | 60 秒 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 稳态时长 | 10 分钟 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 验收轮次 | ≥ 3 轮，取中位数 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 环境 | 单实例 4C8G；压测客户端独立进程 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| &lt;span style=&#34;font-weight:bold&#34;&gt;**崩溃线**&lt;/span&gt; | P99 &amp;gt; 1s 或错误率 &amp;gt; 1% 持续 30 秒 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 测量日期与版本 | YYYY-MM-DD，commit &lt;span style=&#34;color:#e6db74&#34;&gt;`abc1234`&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;**待确认项**&lt;/span&gt;：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; 峰值 QPS 的真实数据（向业务方确认 / 从监控取值）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; 数据量的一年增长预期
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## 接口 2：POST /links（创建短链）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 字段 | 值 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| --- | --- |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 接口 | &lt;span style=&#34;color:#e6db74&#34;&gt;`POST /links`&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 目标 QPS | 60（读:写 ≈ 50:1） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| P50 / P95 / P99 | 20 / 60 / 150 ms |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 错误率阈值 | &amp;lt; 0.5%（唯一索引冲突是正常业务，单独统计） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 负载前提 | 100 万条已有数据；URL 平均长度 60 字符 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 测量点 | 压测客户端 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 崩溃线 | P99 &amp;gt; 1s |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意三处刻意的设计&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤二：搭服务与数据</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/03-step2-build-service/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/03-step2-build-service/</guid>
      <description>&lt;h1 id=&#34;93-步骤二搭服务与数据&#34;&gt;9.3 步骤二：搭服务与数据&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/02-step1-goals/&#34;&gt;9.2 步骤一：定义目标&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/04-step3-baseline/&#34;&gt;9.4 步骤三：建立基线与噪声底线&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/03-test-pyramid/&#34;&gt;第 3 章&lt;/a&gt;（组件基准、真实依赖）、&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/05-experiment-design/05-dataset-design/&#34;&gt;第 5.5 节&lt;/a&gt;（数据集设计）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/03-step2-build-service/&#34;&gt;09-capstone/03-step2-build-service&lt;/a&gt;
产出：可运行的服务 + 一键起环境脚本 + 100 万行数据&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;这一步的目标不是&amp;quot;写出好代码&amp;quot;，而是&amp;quot;写出一个能被测量的系统&amp;quot;&lt;/strong&gt;——它必须有真实的依赖、固定的数据、可观测的指标，以及&lt;strong&gt;故意保留的埋雷&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一服务的四层结构&#34;&gt;一、服务的四层结构&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HTTP 层（Ktor 路由）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Service 层（业务逻辑：生成短码、缓存编排）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Repository 层（数据访问：PostgreSQL + Redis）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;基础设施（HikariCP 连接池、Redis 客户端）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;每一层对应的埋雷&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层&lt;/th&gt;
					&lt;th&gt;埋雷&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;HTTP 层&lt;/td&gt;
					&lt;td&gt;⑤ 日志同步 IO&lt;/td&gt;
					&lt;td&gt;每个请求打 INFO 日志&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Service 层&lt;/td&gt;
					&lt;td&gt;⑥ &lt;code&gt;synchronized&lt;/code&gt; 生成 code&lt;/td&gt;
					&lt;td&gt;锁 + 可能在协程里&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Repository 层&lt;/td&gt;
					&lt;td&gt;① 无唯一索引、② 每次 UPDATE、④ Default 上 JDBC&lt;/td&gt;
					&lt;td&gt;数据访问的三个问题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;缓存&lt;/td&gt;
					&lt;td&gt;③ TTL 无抖动&lt;/td&gt;
					&lt;td&gt;服务层与缓存层交界处&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二一键起环境&#34;&gt;二、一键起环境&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# docker-compose.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;postgres&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;postgres:16-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;POSTGRES_DB&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shortlink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;POSTGRES_USER&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;POSTGRES_PASSWORD&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;5432:5432&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;command&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;postgres&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - -&lt;span style=&#34;color:#ae81ff&#34;&gt;c max_connections=100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - -&lt;span style=&#34;color:#ae81ff&#34;&gt;c shared_buffers=256MB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - -&lt;span style=&#34;color:#ae81ff&#34;&gt;c log_min_duration_statement=200ms    &lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 慢查询日志（辅助定位）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;pg-data:/var/lib/postgresql/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./init.sql:/docker-entrypoint-initdb.d/init.sql:ro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./seed.sql:/docker-entrypoint-initdb.d/seed.sql:ro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;healthcheck&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;test&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CMD-SHELL&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pg_isready -U app -d shortlink&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;interval&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;timeout&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;retries&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;redis&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;redis:7-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;6379:6379&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;command&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;redis-server --maxmemory 512mb --maxmemory-policy allkeys-lru&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;healthcheck&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;test&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;redis-cli&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ping&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;interval&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# 观测栈（第 4 章）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;prometheus&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;prom/prometheus:v2.54.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9090:9090&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;grafana&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;grafana/grafana:11.2.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;GF_SECURITY_ADMIN_PASSWORD&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;pg-data&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键配置&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤三：建立基线与噪声底线</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/04-step3-baseline/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/04-step3-baseline/</guid>
      <description>&lt;h1 id=&#34;94-步骤三建立基线与噪声底线&#34;&gt;9.4 步骤三：建立基线与噪声底线&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/03-step2-build-service/&#34;&gt;9.3 步骤二：搭服务与数据&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/05-step4-capacity-curve/&#34;&gt;9.5 步骤四：容量曲线与拐点&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/04-toolchain/&#34;&gt;第 4 章&lt;/a&gt;（观测）、&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/05-experiment-design/07-noise-floor-and-regression/&#34;&gt;第 5.7 节&lt;/a&gt;（噪声底线）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/04-step3-baseline/&#34;&gt;09-capstone/04-step3-baseline&lt;/a&gt;
产出：&lt;code&gt;experiments/E09-baseline/&lt;/code&gt;（基线数据 + 噪声底线）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;这一步衡量的是「你的测量工具有多准」。&lt;/strong&gt; 在测出噪声底线之前，任何&amp;quot;优化了 X%&amp;ldquo;的说法都是没有依据的——&lt;strong&gt;因为你不知道 X% 是不是噪声&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一三件事按顺序做&#34;&gt;一、三件事，按顺序做&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;① 观测回路验证（10 分钟）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   → 确认指标、日志、火焰图三条链路都通
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;② 基线测量（30 分钟）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   → 在 SLO 目标负载下跑 3 轮，得到基线数据
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;③ 噪声底线测量（1 小时）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   → 代码不变，重复 10 轮，得到&amp;#34;我的尺子有多准&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;顺序不能反&lt;/strong&gt;：如果观测回路没通，基线数据就是不可信的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二-观测回路验证&#34;&gt;二、① 观测回路验证&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# tools/verify-observability.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set -uo pipefail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;═══ 观测回路验证 ═══&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ① 四层指标&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;① 检查四层指标&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;M&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -s --max-time &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; localhost:8080/metrics&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;check&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$M&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | grep -qE &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$1&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   ✅ &lt;/span&gt;$2&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   ❌ &lt;/span&gt;$2&lt;span style=&#34;color:#e6db74&#34;&gt;（缺这组）&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;check &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^app_requests_total&amp;#34;&lt;/span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;业务层&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;check &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^app_request_duration.*bucket&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;延迟层（直方图）&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;check &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^jvm_memory_used_bytes&amp;#34;&lt;/span&gt;         &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;资源层&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;check &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^db_pool_pending&amp;#34;&lt;/span&gt;               &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;饱和度层 ⭐&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;check &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^app_cache_hit_rate&amp;#34;&lt;/span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;缓存命中率&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;② 检查桶边界（应该在 100ms 附近加密）&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$M&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | grep &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;app_request_duration_seconds_bucket&amp;#39;&lt;/span&gt; | grep -oE &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;le=&amp;#34;[0-9.]+&amp;#34;&amp;#39;&lt;/span&gt; | head -12 | sed &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/^/   /&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;③ 检查指标基数（应该是个位数）&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   序列数: &lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$M&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | grep -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;app_request_duration_seconds_bucket&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;④ 检查火焰图能采到&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;jcmd 2&amp;gt;/dev/null | grep app.jar | awk &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; -n &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$PID&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  TMP&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;mktemp&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asprof -d &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; -e cpu -o collapsed -f &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$TMP&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$PID&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  LINES&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;wc -l &amp;lt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$TMP&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$LINES&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -gt &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   ✅ 火焰图有 &lt;/span&gt;$LINES&lt;span style=&#34;color:#e6db74&#34;&gt; 条栈（压测中采集会更多）&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   ⚠️  只有 &lt;/span&gt;$LINES&lt;span style=&#34;color:#e6db74&#34;&gt; 条栈（可能没在压测，或权限问题）&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  rm -f &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$TMP&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   ⚠️  未找到应用进程&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;⑤ 检查 Prometheus 抓取&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sf http://localhost:9090/-/ready &amp;gt; /dev/null &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   ✅ Prometheus 就绪&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                   &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   ⚠️  Prometheus 未就绪&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键检查&lt;/strong&gt;：&lt;strong&gt;&lt;code&gt;db_pool_pending&lt;/code&gt; 与 &lt;code&gt;app_cache_hit_rate&lt;/code&gt;&lt;/strong&gt;——这两个是后面定位的关键指标，&lt;strong&gt;如果没有，后面的分析会缺一大块&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤四：容量曲线与拐点</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/05-step4-capacity-curve/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/05-step4-capacity-curve/</guid>
      <description>&lt;h1 id=&#34;95-步骤四容量曲线与拐点&#34;&gt;9.5 步骤四：容量曲线与拐点&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/04-step3-baseline/&#34;&gt;9.4 步骤三：建立基线与噪声底线&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/06-step5-diagnose/&#34;&gt;9.6 步骤五：剖析定位&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/06-baseline-and-capacity-curve/&#34;&gt;第 1.6 节&lt;/a&gt;（容量曲线）、&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/03-test-pyramid/04-load-profiles/&#34;&gt;第 3.4 节&lt;/a&gt;（阶梯加压）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/05-step4-capacity-curve/&#34;&gt;09-capstone/05-step4-capacity-curve&lt;/a&gt;
产出：&lt;code&gt;experiments/E10-capacity/&lt;/code&gt;（曲线 + 拐点）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;「CPU 打满时的 QPS」不是容量，「延迟开始非线性上升的那个点」才是。&lt;/strong&gt; 而且&lt;strong&gt;在埋雷服务上，拐点会低得惊人&lt;/strong&gt;——这正是埋雷的价值：让你亲眼看到「一个缺失的索引如何把容量砍掉一半」。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一阶梯加压设计&#34;&gt;一、阶梯加压设计&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// loadtest/capacity-staircase.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;scenarios&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;staircase&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;executor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ramping-arrival-rate&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;startRate&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;timeUnit&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;1s&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;preAllocatedVUs&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;,          &lt;span style=&#34;color:#75715e&#34;&gt;// ⚠️ 必须给够，否则实际到达率低于设定值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;maxVUs&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;stages&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;,  &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;30s&amp;#39;&lt;/span&gt; }, { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;,  &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2m&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;400&lt;/span&gt;,  &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;30s&amp;#39;&lt;/span&gt; }, { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;400&lt;/span&gt;,  &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2m&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;700&lt;/span&gt;,  &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;30s&amp;#39;&lt;/span&gt; }, { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;700&lt;/span&gt;,  &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2m&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;30s&amp;#39;&lt;/span&gt; }, { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2m&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1500&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;30s&amp;#39;&lt;/span&gt; }, { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1500&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2m&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2000&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;30s&amp;#39;&lt;/span&gt; }, { &lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2000&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2m&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// 每级：爬升 30s + 稳态 2m（⚠️ 稳态窗口才是采数据的区间）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 故意不设 thresholds：容量测试的目的是找拐点，不是判定通过/失败
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;discardResponseBodies&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键设计（第 3.4 节）&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤五：剖析定位</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/06-step5-diagnose/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/06-step5-diagnose/</guid>
      <description>&lt;h1 id=&#34;96-步骤五剖析定位&#34;&gt;9.6 步骤五：剖析定位&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/05-step4-capacity-curve/&#34;&gt;9.5 步骤四：容量曲线与拐点&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/07-step6-optimize/&#34;&gt;9.7 步骤六：优化与验证&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/&#34;&gt;第 6 章&lt;/a&gt;（五步法、延迟分解、火焰图、瓶颈模式库）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/06-step5-diagnose/&#34;&gt;09-capstone/06-step5-diagnose&lt;/a&gt;
产出：&lt;code&gt;bottlenecks.md&lt;/code&gt;（瓶颈清单：证据链 + 贡献占比 + 被排除的假设）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;在拐点负载下剖析&lt;/strong&gt;（不是在低负载下）——因为&lt;strong&gt;低负载时一切都很健康，看不出问题&lt;/strong&gt;。这一步的产出是&lt;strong&gt;一份能被人追问的瓶颈清单&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一五步法在埋雷服务上的应用&#34;&gt;一、五步法在埋雷服务上的应用&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;① 现象量化 → 已有（步骤三、四的数据）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;② 分层拆解 → 找出哪一段占大头
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;③ 提出假设 → 六颗埋雷对应六个假设
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;④ 设计验证 → 每条假设一条可证伪的命令
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;⑤ 得出结论 → 证据链 + 贡献占比 + 被排除的假设
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第 ① 步已经在步骤三、四做完了&lt;/strong&gt;——这正是前面步骤的价值：&lt;strong&gt;你不用再从头量化&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二-分层拆解找出大头&#34;&gt;二、② 分层拆解：找出大头&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 在拐点负载（约 700 RPS）下测量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tools/decompose-at-knee.sh E11-diagnosis
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# tools/decompose-at-knee.sh &amp;lt;EXP_ID&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set -uo pipefail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXP_ID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;1:?usage: decompose-at-knee.sh &amp;lt;exp_id&amp;gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DIR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;docs/experiments/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;EXP_ID&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ⚠️ 关键：在【拐点负载】下剖析，不是在低负载下&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KNEE_QPS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;KNEE_QPS&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;700&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scripts/restart-app.sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/gc.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BASE_URL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;http://127.0.0.1:8080 k6 run --quiet --vus &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; --duration 60s loadtest/read-path.js &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 后台施压（持续整个剖析过程）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BASE_URL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;http://127.0.0.1:8080 RATE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$KNEE_QPS&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; DURATION&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;5m &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k6 run --summary-export&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/k6-knee.json&amp;#34;&lt;/span&gt; loadtest/read-path.js &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;K6_PID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 等进入稳态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;jcmd | grep app.jar | awk &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;═══ 在 &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;KNEE_QPS&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; RPS 下采集证据 ═══&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ① 四类火焰图&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;① 火焰图&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; E in cpu wall alloc lock; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asprof -d &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -f &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/&lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;.html&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$PID&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asprof -d &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -o collapsed -f &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/&lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;.collapsed&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$PID&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   &lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;.html / &lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;.collapsed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ② 线程快照（连续 3 份）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;② 线程快照&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/threads&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i in &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; 3; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  jcmd &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$PID&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; Thread.print &amp;gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/threads/threads-&lt;/span&gt;$i&lt;span style=&#34;color:#e6db74&#34;&gt;.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 tools/analyze-threads.py &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/threads&amp;#34;&lt;/span&gt;/threads-*.txt &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/threads/analysis.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   分析已生成&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ③ 指标快照&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -s localhost:8080/metrics &amp;gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/metrics.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ④ 数据库侧&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;③ 数据库诊断&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;psql &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;PG_CONN&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;postgresql://app:app@localhost:5432/shortlink&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/pg-diagnostics.txt&amp;#34;&lt;/span&gt; 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt;&amp;#39;SQL&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;-- 最贵的语句（看 calls 与 mean）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;SELECT calls, round(mean_exec_time::numeric,2) AS mean_ms,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;       round(total_exec_time::numeric,0) AS total_ms,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;       left(regexp_replace(query,&amp;#39;\s+&amp;#39;,&amp;#39; &amp;#39;,&amp;#39;g&amp;#39;), 50) AS query
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;FROM pg_stat_statements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;WHERE query NOT LIKE &amp;#39;%pg_stat_statements%&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;ORDER BY total_exec_time DESC LIMIT 10;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;-- 当前活跃查询与等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;SELECT pid, round(extract(epoch from (now()-query_start))::numeric,1) AS dur_s,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;       state, wait_event_type, wait_event, left(query,50)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;FROM pg_stat_activity WHERE state &amp;lt;&amp;gt; &amp;#39;idle&amp;#39; AND pid &amp;lt;&amp;gt; pg_backend_pid()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;ORDER BY dur_s DESC NULLS LAST LIMIT 10;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;   已保存到 pg-diagnostics.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wait $K6_PID 2&amp;gt;/dev/null &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;═══ 关键证据摘要 ═══&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;── 数据库最贵的语句 ──&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;head -8 &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/pg-diagnostics.txt&amp;#34;&lt;/span&gt; | tail -6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;── 火焰图热点（自身耗时 Top 5）──&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; E in cpu wall; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;[&lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  python3 tools/analyze-flamegraph.py &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/&lt;/span&gt;$E&lt;span style=&#34;color:#e6db74&#34;&gt;.collapsed&amp;#34;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    | grep -A6 &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;自身耗时 Top&amp;#34;&lt;/span&gt; | tail -5 | sed &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/^/  /&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;── 线程分析关键结论 ──&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BLOCKED|持续|⚠️|❌&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results/threads/analysis.txt&amp;#34;&lt;/span&gt; 2&amp;gt;/dev/null | head -6 | sed &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/^/  /&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;✅ 证据已采集 → &lt;/span&gt;$DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/results&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;三预期发现六颗埋雷的证据&#34;&gt;三、预期发现：六颗埋雷的证据&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;埋雷&lt;/th&gt;
					&lt;th&gt;预期证据&lt;/th&gt;
					&lt;th&gt;在哪份数据里&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;①&lt;/strong&gt; 无索引&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pg_stat_statements&lt;/code&gt; 里 &lt;code&gt;SELECT ... WHERE code = ?&lt;/code&gt; 的 mean 高；&lt;code&gt;EXPLAIN&lt;/code&gt; 显示 &lt;code&gt;Seq Scan&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pg-diagnostics.txt&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;②&lt;/strong&gt; 每次 UPDATE&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;lock&lt;/code&gt; 火焰图有内容；&lt;code&gt;pg_stat_activity&lt;/code&gt; 有 &lt;code&gt;wait_event_type=Lock&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;lock.collapsed&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;③&lt;/strong&gt; TTL 无抖动&lt;/td&gt;
					&lt;td&gt;缓存命中率曲线有周期性下凹&lt;/td&gt;
					&lt;td&gt;需要额外采集&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;④&lt;/strong&gt; Default 上 JDBC&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;&lt;code&gt;cpu&lt;/code&gt; 火焰图很空&lt;/strong&gt;，&lt;strong&gt;&lt;code&gt;wall&lt;/code&gt; 火焰图全是阻塞栈&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cpu.collapsed&lt;/code&gt; vs &lt;code&gt;wall.collapsed&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;⑤&lt;/strong&gt; 日志同步 IO&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sys&lt;/code&gt; CPU 偏高；火焰图有文件写栈&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cpu.collapsed&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;⑥&lt;/strong&gt; &lt;code&gt;synchronized&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;线程 dump 有 &lt;code&gt;BLOCKED&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;threads/analysis.txt&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;埋雷--的证据最重要的教学点&#34;&gt;埋雷 ④ 的证据（最重要的教学点）&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cpu.collapsed  → 很空（几乎没有采样）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wall.collapsed → 大量栈停在 socketRead0 / JDBC 调用
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;这个对比就是第 6.3 节的核心：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;「只采 CPU 火焰图会得出『没有瓶颈』的错误结论」
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;验证&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤六：优化与验证</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/07-step6-optimize/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/07-step6-optimize/</guid>
      <description>&lt;h1 id=&#34;97-步骤六优化与验证&#34;&gt;9.7 步骤六：优化与验证&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/06-step5-diagnose/&#34;&gt;9.6 步骤五：剖析定位&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/08-step7-soak-and-regression/&#34;&gt;9.8 步骤七：长稳与回归&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/07-optimization-and-validation/&#34;&gt;第 7 章&lt;/a&gt;（优先级金字塔、三问纪律、否决记录）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/07-step6-optimize/&#34;&gt;09-capstone/07-step6-optimize&lt;/a&gt;
产出：&lt;code&gt;OPTIMIZATION.md&lt;/code&gt;（优化收益报告）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;按优先级金字塔从下往上改，一次只改一处，每处都回答三个问题。&lt;/strong&gt; 而且——&lt;strong&gt;你至少要主动否决一项优化&lt;/strong&gt;，否则说明你没有真的评估过备选方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一优化的优先级排序&#34;&gt;一、优化的优先级排序&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;用第 7.1 节的金字塔对六个瓶颈排序&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;瓶颈&lt;/th&gt;
					&lt;th&gt;金字塔层级&lt;/th&gt;
					&lt;th&gt;预期收益&lt;/th&gt;
					&lt;th&gt;成本&lt;/th&gt;
					&lt;th&gt;排序&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;① 缺索引&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;② 算法与数据访问&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;90%&lt;/td&gt;
					&lt;td&gt;极低（一条 SQL）&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;④ Default 上 JDBC&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;③ 架构与并发&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;6%（但对全局卡顿 100%）&lt;/td&gt;
					&lt;td&gt;低（几行代码）&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;② UPDATE hits&lt;/td&gt;
					&lt;td&gt;② 算法与数据访问&lt;/td&gt;
					&lt;td&gt;2.4%&lt;/td&gt;
					&lt;td&gt;中（要改数据模型）&lt;/td&gt;
					&lt;td&gt;3&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;⑤ 日志同步 IO&lt;/td&gt;
					&lt;td&gt;⑤ 微观常数&lt;/td&gt;
					&lt;td&gt;1.2%&lt;/td&gt;
					&lt;td&gt;极低（降级别）&lt;/td&gt;
					&lt;td&gt;4&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;⑥ &lt;code&gt;synchronized&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;③ 架构与并发&lt;/td&gt;
					&lt;td&gt;写路径为主&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
					&lt;td&gt;5&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;③ 缓存 TTL 无抖动&lt;/td&gt;
					&lt;td&gt;④ 缓存&lt;/td&gt;
					&lt;td&gt;周期性尖刺&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
					&lt;td&gt;6&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;注意排序结果&lt;/strong&gt;：&lt;strong&gt;前两名来自 ② 和 ③ 层&lt;/strong&gt;（算法/架构），&lt;strong&gt;后四名收益都在个位数&lt;/strong&gt;——这正是金字塔的体现。&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤七：长稳与回归</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/08-step7-soak-and-regression/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/08-step7-soak-and-regression/</guid>
      <description>&lt;h1 id=&#34;98-步骤七长稳与回归&#34;&gt;9.8 步骤七：长稳与回归&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/07-step6-optimize/&#34;&gt;9.7 步骤六：优化与验证&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/09-step8-gate-and-report/&#34;&gt;9.9 步骤八：固化门禁与交付报告&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/03-test-pyramid/05-soak-testing/&#34;&gt;第 3.5 节&lt;/a&gt;（浸泡测试）、&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/07-optimization-and-validation/08-optimization-discipline/&#34;&gt;第 7.8 节&lt;/a&gt;（回归验证）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/08-step7-soak-and-regression/&#34;&gt;09-capstone/08-step7-soak-and-regression&lt;/a&gt;
产出：&lt;code&gt;experiments/E13-soak/&lt;/code&gt;（长稳数据）+ 回归确认&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;短跑发现不了的问题，长跑才能发现。&lt;/strong&gt; 而且这一步还要回答一个问题：&lt;strong&gt;我优化了 A，会不会让 B 变慢了？&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一为什么要做这一步&#34;&gt;一、为什么要做这一步&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;前六步做的都是&amp;quot;短跑&amp;quot;&lt;/strong&gt;（3–5 分钟的压测）。短跑发现不了：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;问题类型&lt;/th&gt;
					&lt;th&gt;为什么短跑发现不了&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;内存泄漏&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每小时涨 30 MB，5 分钟只涨 2.5 MB（在噪声内）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;连接泄漏&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每次异常路径漏一个连接，需要累积才显现&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;文件描述符泄漏&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同上&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;缓存无界增长&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;需要长时间才能填满&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;长周期 GC 问题&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;老年代回收可能需要几十分钟才一次&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;缓存 TTL 无抖动的影响&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;TTL 是 10 分钟——短跑看不到它失效&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;注意最后一条&lt;/strong&gt;：&lt;strong&gt;埋雷 ③（缓存 TTL 无抖动）只有在这一步才能被观察到&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二浸泡测试设计&#34;&gt;二、浸泡测试设计&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tools/run-soak.sh E13-soak 1h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键参数&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;值&lt;/th&gt;
					&lt;th&gt;理由&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;时长&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1 小时&lt;/strong&gt;（最低要求）&lt;/td&gt;
					&lt;td&gt;覆盖缓存 TTL（10 分钟）× 6 轮、老年代 GC 周期&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;负载&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;目标容量的 60%–80%&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;不要用满负载（排队会掩盖泄漏信号）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;模型&lt;/td&gt;
					&lt;td&gt;恒定到达率&lt;/td&gt;
					&lt;td&gt;不要做阶梯&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;采样间隔&lt;/td&gt;
					&lt;td&gt;30 秒&lt;/td&gt;
					&lt;td&gt;太稀会漏掉趋势，太密产生大量数据&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;为什么负载用 60%–80% 而不是满负载&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>步骤八：固化门禁与交付报告</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/09-step8-gate-and-report/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/09-step8-gate-and-report/</guid>
      <description>&lt;h1 id=&#34;99-步骤八固化门禁与交付报告&#34;&gt;9.9 步骤八：固化门禁与交付报告&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/08-step7-soak-and-regression/&#34;&gt;9.8 步骤七：长稳与回归&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/10-lab9/&#34;&gt;9.10 Lab 9：总编排&lt;/a&gt;
用到：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/08-continuous-performance/&#34;&gt;第 8 章&lt;/a&gt;（门禁、告警、容量规划）、&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/08-writing-conclusions/&#34;&gt;第 6.8 节&lt;/a&gt;（结论写法）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/09-step8-gate-and-report/&#34;&gt;09-capstone/09-step8-gate-and-report&lt;/a&gt;
产出：门禁 + 告警 + 容量表 + &lt;strong&gt;&lt;code&gt;PERF-REPORT.md&lt;/code&gt;（最终交付物）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一句话结论&#34;&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;前七步产出了数据和分析；这一步把它们变成&amp;quot;机制&amp;quot;和&amp;quot;一份能被决策的报告&amp;quot;。&lt;/strong&gt; 判断标准是：&lt;strong&gt;不需要人记得，它自己会运行&lt;/strong&gt;；以及&lt;strong&gt;报告能被非性能工程师用于决策&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一要交付的五样东西&#34;&gt;一、要交付的五样东西&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;#&lt;/th&gt;
					&lt;th&gt;交付物&lt;/th&gt;
					&lt;th&gt;来自&lt;/th&gt;
					&lt;th&gt;判断标准&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;CI 微基准门禁&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;第 8.2 节&lt;/td&gt;
					&lt;td&gt;代码不变时&lt;strong&gt;零误报&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;生产告警规则&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;第 8.5 节&lt;/td&gt;
					&lt;td&gt;每条都有 runbook、含领先指标&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;容量表&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;第 8.7 节&lt;/td&gt;
					&lt;td&gt;每个数字能追溯到实验&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;性能报告&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;第 6.8 节&lt;/td&gt;
					&lt;td&gt;能被非性能工程师用于决策&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;回归基线&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;本步骤&lt;/td&gt;
					&lt;td&gt;优化后的版本成为新基线&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二-ci-微基准门禁&#34;&gt;二、① CI 微基准门禁&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;复用第 8 章的流程&lt;/strong&gt;，但&lt;strong&gt;只保留与本项目相关的基准&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// src/main/kotlin/bench/ShortlinkBenchmark.kt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@State&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;Scope&lt;/span&gt;.Benchmark)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ShortlinkBenchmark&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; base62 = Base62Codec()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Benchmark&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generateCode&lt;/span&gt;(bh: Blackhole) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        bh.consume(base62.encode(&lt;span style=&#34;color:#a6e22e&#34;&gt;Random&lt;/span&gt;.nextLong(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;62L&lt;/span&gt;.pow(&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Benchmark&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;encodeUrl&lt;/span&gt;(bh: Blackhole) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        bh.consume(base62.encode(&lt;span style=&#34;color:#a6e22e&#34;&gt;Random&lt;/span&gt;.nextLong()))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 序列化基准（短链的响应体很小，但仍值得测）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@State&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;Scope&lt;/span&gt;.Benchmark)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SerializationBenchmark&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; format = Json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;lateinit&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; response: CreateLinkResponse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setup&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        response = CreateLinkResponse(code = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;aB3xK9&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Benchmark&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;encode&lt;/span&gt;(bh: Blackhole) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        bh.consume(format.encodeToString(response))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;门禁配置&lt;/strong&gt;（沿用第 8 章的脚本，阈值用实测的 CI 噪声底线）：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lab 9：总编排</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/10-lab9/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/10-lab9/</guid>
      <description>&lt;h1 id=&#34;910-lab-9总编排&#34;&gt;9.10 Lab 9：总编排&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/09-capstone/09-step8-gate-and-report/&#34;&gt;9.9 步骤八：固化门禁与交付报告&lt;/a&gt;　|　下一节：无（全书结束）
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/09-capstone/readme/&#34;&gt;09-capstone/README&lt;/a&gt;
预计时长：&lt;strong&gt;3–5 天&lt;/strong&gt;（分为 8 次，每次 2–6 小时）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一这个-lab-的定位&#34;&gt;一、这个 Lab 的定位&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;它不是&amp;quot;一个新的练习&amp;quot;，而是把前八章的 Lab 串成一条线&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;本 Lab 的步骤&lt;/th&gt;
					&lt;th&gt;复用了哪个 Lab&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤一（定义目标）&lt;/td&gt;
					&lt;td&gt;Lab 1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤二（搭服务）&lt;/td&gt;
					&lt;td&gt;Lab 3（组件基准的环境）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤三（基线）&lt;/td&gt;
					&lt;td&gt;Lab 4（观测回路）+ Lab 5（噪声底线）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤四（容量曲线）&lt;/td&gt;
					&lt;td&gt;Lab 3（阶梯加压）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤五（剖析定位）&lt;/td&gt;
					&lt;td&gt;Lab 6（埋雷定位）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤六（优化验证）&lt;/td&gt;
					&lt;td&gt;Lab 7（优化与三问）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤七（长稳回归）&lt;/td&gt;
					&lt;td&gt;Lab 3（浸泡）+ Lab 5（回归）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;步骤八（门禁报告）&lt;/td&gt;
					&lt;td&gt;Lab 8（门禁）+ Lab 2（基准）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;如果你做过前八个 Lab，这里你会很熟悉&lt;/strong&gt;——区别是：&lt;strong&gt;这次要在一个完整的、有真实依赖的服务上做&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二八次实施安排&#34;&gt;二、八次实施安排&lt;/h2&gt;
&lt;h3 id=&#34;第-1-次立项与搭环境4-小时&#34;&gt;第 1 次：立项与搭环境（4 小时）&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## 目标
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;跑通「服务 + 依赖 + 观测」三件套
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## 任务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; 实现两个接口（POST /links、GET /{code}）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`docker compose up -d`&lt;/span&gt; 起 PostgreSQL + Redis
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; 灌入 100 万行数据（幂律分布）+ &lt;span style=&#34;color:#e6db74&#34;&gt;`ANALYZE`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; 埋四层指标（确认 &lt;span style=&#34;color:#e6db74&#34;&gt;`/metrics`&lt;/span&gt; 有四组）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;**确认六颗埋雷都存在**&lt;/span&gt;（&lt;span style=&#34;color:#e6db74&#34;&gt;`verify-traps.sh`&lt;/span&gt;）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## 产出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; 可运行的服务
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`docs/experiments/E09-baseline/results/env.txt`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## 验收
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`curl localhost:8080/metrics | grep db_pool_pending`&lt;/span&gt; 有输出
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`verify-traps.sh`&lt;/span&gt; 显示六颗埋雷全部生效
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;- [ ]&lt;/span&gt; 手工验证两个接口功能正常
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;提示&lt;/strong&gt;：&lt;strong&gt;这一步最容易卡在埋点&lt;/strong&gt;——如果指标埋错了，后面所有分析都缺一块。&lt;strong&gt;宁可多花 1 小时确认四层指标齐全&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
