<?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/06-analysis-and-profiling/</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/06-analysis-and-profiling/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>分析流程：五步法</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/01-analysis-workflow/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/01-analysis-workflow/</guid>
      <description>&lt;h1 id=&#34;61-分析流程五步法&#34;&gt;6.1 分析流程：五步法&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：无　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/02-latency-decomposition/&#34;&gt;6.2 延迟分解&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/01-analysis-workflow/&#34;&gt;06-analysis-and-profiling/01-analysis-workflow&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; 关键纪律是：&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;/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;&lt;strong&gt;现象量化&lt;/strong&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;strong&gt;分层拆解&lt;/strong&gt;：延迟花在哪几段，CPU 花在哪&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;strong&gt;提出假设&lt;/strong&gt;：可能是连接池排队 / GC / 慢查询&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;strong&gt;设计验证&lt;/strong&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;strong&gt;结论&lt;/strong&gt;：含贡献占比与&lt;strong&gt;被排除的假设&lt;/strong&gt;&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;你不仅要证明「是连接池排队」，还要说明「为什么不是 GC」。&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;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;&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;P50 还是 P99？错对率如何？是否达标？&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;/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-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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 接口 | GET /orders/{id} |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 指标 | P99 从 80ms → 400ms（P50 从 20ms → 25ms） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 时间 | 2025-01-15 14:30 开始，持续至今 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 范围 | 所有实例；只影响带 user_id 的查询；无 user_id 的正常 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 错误率 | 0.1%（未变） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| QPS | 850（未变） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| CPU | 45%（未变） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 变更 | 14:00 有一次部署（版本 v2.3.1） |
&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/06-analysis-and-profiling/02-latency-decomposition/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/02-latency-decomposition/</guid>
      <description>&lt;h1 id=&#34;62-延迟分解把总账拆成明细&#34;&gt;6.2 延迟分解：把总账拆成明细&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/01-analysis-workflow/&#34;&gt;6.1 分析流程五步法&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/03-flamegraph-reading/&#34;&gt;6.3 火焰图读法&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/02-latency-decomposition/&#34;&gt;06-analysis-and-profiling/02-latency-decomposition&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;「这个接口要 400 ms」是一个总账。&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;p&gt;工厂发现「一件产品从下单到发货要 8 天」，要改进就得知道这 8 天花在哪：&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;占 8 天的比例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;订单排队等排产&lt;/td&gt;
					&lt;td&gt;3 天&lt;/td&gt;
					&lt;td&gt;37%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;原料采购&lt;/td&gt;
					&lt;td&gt;2 天&lt;/td&gt;
					&lt;td&gt;25%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;生产加工&lt;/td&gt;
					&lt;td&gt;1 天&lt;/td&gt;
					&lt;td&gt;12%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;质检&lt;/td&gt;
					&lt;td&gt;0.5 天&lt;/td&gt;
					&lt;td&gt;6%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;包装入库&lt;/td&gt;
					&lt;td&gt;0.5 天&lt;/td&gt;
					&lt;td&gt;6%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;发货运输&lt;/td&gt;
					&lt;td&gt;1 天&lt;/td&gt;
					&lt;td&gt;12%&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;看到这张表，改进方向立刻明确&lt;/strong&gt;：优化「生产加工」（只占 12%）最多省 1 天；&lt;strong&gt;而&amp;quot;订单排队&amp;quot;占了 3 天&lt;/strong&gt;——那才是大头。&lt;/p&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;一个 P99 = 200 ms 的接口：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  网络 + 客户端排队   70 ms  (35%)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  网关 + 服务排队     90 ms  (45%)  ← 真正的瓶颈
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  应用自身代码         7 ms  (3.5%) ← 你想优化的地方
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  数据库              25 ms  (12.5%)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  缓存 + 下游          8 ms  (4%)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;你写的代码只占 3.5%。&lt;/strong&gt; 如果只优化它，最多省 7 ms。&lt;/p&gt;</description>
    </item>
    <item>
      <title>火焰图读法</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/03-flamegraph-reading/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/03-flamegraph-reading/</guid>
      <description>&lt;h1 id=&#34;63-火焰图读法&#34;&gt;6.3 火焰图读法&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/02-latency-decomposition/&#34;&gt;6.2 延迟分解&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/04-thread-and-coroutine-dumps/&#34;&gt;6.4 线程与协程快照&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/03-flamegraph-reading/&#34;&gt;06-analysis-and-profiling/03-flamegraph-reading&lt;/a&gt;
工具用法见 &lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/04-toolchain/03-async-profiler/&#34;&gt;第 4 章 4.3&lt;/a&gt;；本节讲&lt;strong&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;火焰图是一张「时间面积图」，不是调用顺序图。&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;/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;/td&gt;
					&lt;td&gt;宽度 = 时间占比&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;相邻区域不代表有先后关系&lt;/td&gt;
					&lt;td&gt;左右相邻&lt;strong&gt;不代表&lt;/strong&gt;调用顺序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&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;栈深度 = 调用层级&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;/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-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;│                  handleRequest                    │
&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;│ 业务   │         serialize (很宽，下方无子帧)        │  ← 热点！
&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;p&gt;&lt;strong&gt;行动&lt;/strong&gt;：这就是优化目标。看它的实现——常见的是序列化、正则、加密、字符串处理、集合操作。&lt;/p&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;handleRequest
&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;     └─ repository
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         └─ hibernate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             └─ jdbc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 └─ socketRead   ← 深而窄
&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;</description>
    </item>
    <item>
      <title>线程与协程快照</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/04-thread-and-coroutine-dumps/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/04-thread-and-coroutine-dumps/</guid>
      <description>&lt;h1 id=&#34;64-线程与协程快照&#34;&gt;6.4 线程与协程快照&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/03-flamegraph-reading/&#34;&gt;6.3 火焰图读法&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/05-bottleneck-pools/&#34;&gt;6.5 瓶颈模式库（一）：池化类&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/04-thread-and-coroutine-dumps/&#34;&gt;06-analysis-and-profiling/04-thread-and-coroutine-dumps&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; 单张快照告诉你「此刻谁在哪」（可能只是路过），多张对比才能看出「谁一直卡在那里」。这就是「瞬时状态」与「持续问题」的区别。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一用工厂巡检拍照理解快照&#34;&gt;一、用「工厂巡检拍照」理解快照&lt;/h2&gt;
&lt;p&gt;你去工厂检查为什么产线慢了。&lt;strong&gt;拍一张照片&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;照片里 3 个工人站着不动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;但这可能只是巧合&lt;/strong&gt;——他们可能刚好在等下一个零件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;连拍 5 张（每 3 秒一张）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5 张照片里，同样的 3 个工人站在同一个位置不动。&lt;/li&gt;
&lt;li&gt;而其他工人都在移动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结论：这 3 个工人被卡住了。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&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;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;code&gt;RUNNABLE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;正在运行或等待 CPU&lt;/td&gt;
					&lt;td&gt;CPU 饱和，或在自旋&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;BLOCKED (on object monitor)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;等 monitor 锁&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;锁竞争&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;WAITING (parking)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;无限期等待（&lt;code&gt;LockSupport.park&lt;/code&gt;）&lt;/td&gt;
					&lt;td&gt;等锁、等队列、等任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;TIMED_WAITING&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;有时限等待（&lt;code&gt;sleep&lt;/code&gt;、&lt;code&gt;await(timeout)&lt;/code&gt;）&lt;/td&gt;
					&lt;td&gt;有超时等待（可能是重试退避）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;WAITING (on object monitor)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Object.wait()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;等条件变量&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;关键栈特征速查&#34;&gt;关键栈特征速查&lt;/h3&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;code&gt;HikariPool.getConnection&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;连接池排队&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;socketRead0&lt;/code&gt; / &lt;code&gt;socketWrite0&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;等网络（数据库/下游）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Unsafe.park&lt;/code&gt; / &lt;code&gt;LockSupport.park&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;等锁或等任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;LinkedBlockingQueue.take&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;线程池空闲（正常）或队列空&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ArrayBlockingQueue.put&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;队列满，生产者被阻塞（背压生效）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Object.wait&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;等条件变量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Thread.sleep&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;主动睡眠（重试退避或轮询）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;FileOutputStream.write&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;同步日志刷盘&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;classloader&lt;/code&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;三多个快照的对比方法&#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-bash&#34; data-lang=&#34;bash&#34;&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;&lt;span style=&#34;color:#75715e&#34;&gt;# 连续取 5 份，间隔 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;for&lt;/span&gt; i in &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;seq &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 5&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &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;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;
&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;comm -12 &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^\s+at &amp;#39;&lt;/span&gt; threads-1.txt | sort -u&lt;span style=&#34;color:#f92672&#34;&gt;)&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;         &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^\s+at &amp;#39;&lt;/span&gt; threads-2.txt | sort -u&lt;span style=&#34;color:#f92672&#34;&gt;)&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;comm -12 - &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^\s+at &amp;#39;&lt;/span&gt; threads-3.txt | sort -u&lt;span style=&#34;color:#f92672&#34;&gt;)&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;comm -12 - &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^\s+at &amp;#39;&lt;/span&gt; threads-4.txt | sort -u&lt;span style=&#34;color:#f92672&#34;&gt;)&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;comm -12 - &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^\s+at &amp;#39;&lt;/span&gt; threads-5.txt | sort -u&lt;span style=&#34;color:#f92672&#34;&gt;)&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;sort | uniq -c | sort -rn | head -20
&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/06-analysis-and-profiling/05-bottleneck-pools/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/05-bottleneck-pools/</guid>
      <description>&lt;h1 id=&#34;65-瓶颈模式库一池化类&#34;&gt;6.5 瓶颈模式库（一）：池化类&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/04-thread-and-coroutine-dumps/&#34;&gt;6.4 线程与协程快照&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/06-bottleneck-data/&#34;&gt;6.6 瓶颈模式库（二）：数据与算法类&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/05-bottleneck-pools/&#34;&gt;06-analysis-and-profiling/05-bottleneck-pools&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;池化类瓶颈的共同特征是「CPU 不高但延迟高」，因为时间花在排队上而不在计算上。&lt;/strong&gt; 它们的鉴别关键都在&lt;strong&gt;饱和度指标&lt;/strong&gt;：池的 &lt;code&gt;pending&lt;/code&gt;、队列的深度、调度器的排队数。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一用机场安检理解池化类瓶颈&#34;&gt;一、用「机场安检」理解池化类瓶颈&lt;/h2&gt;
&lt;p&gt;机场安检有 &lt;strong&gt;4 个通道&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;服务慢&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;strong&gt;通道不够&lt;/strong&gt;&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;/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;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键区分&lt;/strong&gt;：&lt;strong&gt;「检查慢」和「通道少」是两件事，修法相反。&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查慢 → 优化检查（查询）&lt;/li&gt;
&lt;li&gt;通道少 → 加通道（池）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;判断方法&lt;/strong&gt;：看 &lt;code&gt;pending&lt;/code&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;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;CPU&lt;/td&gt;
					&lt;td&gt;40%（不高）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;P99&lt;/td&gt;
					&lt;td&gt;从 80 ms 涨到 400 ms&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;db_pool_pending&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;18&lt;/strong&gt; ⭐&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;db_pool_active&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;10（= &lt;code&gt;total&lt;/code&gt;，已打满）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;wall 火焰图&lt;/td&gt;
					&lt;td&gt;大量栈停在 &lt;code&gt;HikariPool.getConnection&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;线程 dump&lt;/td&gt;
					&lt;td&gt;40+ 线程停在 &lt;code&gt;HikariPool.getConnection&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-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;# ① 池状态&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 | grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;db_pool_(active|idle|pending|total)&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;psql -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT pid, now()-query_start AS dur, state, wait_event_type, left(query,60)
&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; ORDER BY dur DESC LIMIT 10;&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;psql -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT calls, mean_exec_time, total_exec_time, 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_statements ORDER BY total_exec_time DESC LIMIT 10;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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;① 先确认「是查询慢还是池小」
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ├─ 有慢查询（mean_exec_time 高）→ 优化 SQL / 加索引（❗不要先加池）
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   └─ 查询都快但仍然 pending → 用 Little&amp;#39;s Law 计算所需连接数
&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;   所需连接 = 峰值 QPS × 单次查询 P99
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   （用 P99 而不是平均，见第 0 章 0.4）
&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;strong&gt;整体可能更慢&lt;/strong&gt;，而且掩盖了真正的问题。&lt;/p&gt;</description>
    </item>
    <item>
      <title>瓶颈模式库（二）：数据与算法类</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/06-bottleneck-data/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/06-bottleneck-data/</guid>
      <description>&lt;h1 id=&#34;66-瓶颈模式库二数据与算法类&#34;&gt;6.6 瓶颈模式库（二）：数据与算法类&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/05-bottleneck-pools/&#34;&gt;6.5 瓶颈模式库（一）：池化类&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/07-traps-kotlin-and-cpp/&#34;&gt;6.7 陷阱清单：Kotlin 与 C++ 直觉&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/06-bottleneck-data/&#34;&gt;06-analysis-and-profiling/06-bottleneck-data&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;——不像池化类那么隐蔽。所以它们的排查更依赖**「知道该看哪个指标」**，而不是复杂的工具。&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;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;N+1 查询&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;DB 调用次数与请求数成正比&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pg_stat_statements&lt;/code&gt; 的 &lt;code&gt;calls&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;对比 calls 与 QPS&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;单条查询慢且随数据量恶化&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;EXPLAIN&lt;/code&gt; 的 &lt;code&gt;Seq Scan&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;EXPLAIN (ANALYZE, BUFFERS)&lt;/code&gt;&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;CPU 高但吞吐不涨，&lt;code&gt;sys&lt;/code&gt; 偏高&lt;/td&gt;
					&lt;td&gt;lock 火焰图、&lt;code&gt;BLOCKED&lt;/code&gt; 线程&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;jstack&lt;/code&gt; + &lt;code&gt;pg_locks&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;GC 停顿&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;P99 尖刺呈周期性&lt;/td&gt;
					&lt;td&gt;GC 日志停顿时间&lt;/td&gt;
					&lt;td&gt;与 P99 尖刺&lt;strong&gt;时间对齐&lt;/strong&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;周期性尖刺，DB 负载脉冲&lt;/td&gt;
					&lt;td&gt;缓存命中率、DB QPS&lt;/td&gt;
					&lt;td&gt;对齐缓存失效时间&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;序列化开销&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;CPU 火焰图顶部是序列化栈&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cpu&lt;/code&gt; 火焰图、&lt;code&gt;alloc&lt;/code&gt; 图&lt;/td&gt;
					&lt;td&gt;对比不同序列化器&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;7&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;日志同步 IO&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sys&lt;/code&gt; 高，火焰图有文件写栈&lt;/td&gt;
					&lt;td&gt;JFR &lt;code&gt;jdk.FileWrite&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;降日志级别做对照&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;8&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;无界队列 OOM&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;内存持续增长，最终 OOM&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;二模式一n1-查询&#34;&gt;二、模式一：N+1 查询&lt;/h2&gt;
&lt;h3 id=&#34;现象与验证&#34;&gt;现象与验证&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;典型症状&lt;/strong&gt;：接口 P99 与&lt;strong&gt;返回的记录数&lt;/strong&gt;成正比；QPS 不高但数据库负载很高。&lt;/p&gt;</description>
    </item>
    <item>
      <title>陷阱清单：Kotlin 与 C&#43;&#43; 直觉</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/07-traps-kotlin-and-cpp/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/07-traps-kotlin-and-cpp/</guid>
      <description>&lt;h1 id=&#34;67-陷阱清单kotlin-与-c-直觉&#34;&gt;6.7 陷阱清单：Kotlin 与 C++ 直觉&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/06-bottleneck-data/&#34;&gt;6.6 瓶颈模式库（二）&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/06-analysis-and-profiling/07-traps-kotlin-and-cpp/&#34;&gt;06-analysis-and-profiling/07-traps-kotlin-and-cpp&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;九条 Kotlin 陷阱和六条 C++ 直觉误判，是「明明代码看起来没问题，但性能就是不对」的两大来源。&lt;/strong&gt; 前者来自语言特性，后者来自&lt;strong&gt;你的经验在 JVM 上不成立&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一九条-kotlin-陷阱按危害排序&#34;&gt;一、九条 Kotlin 陷阱（按危害排序）&lt;/h2&gt;
&lt;h3 id=&#34;-在-dispatchersdefault-上做阻塞调用--最严重&#34;&gt;❶ 在 &lt;code&gt;Dispatchers.Default&lt;/code&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;&lt;span style=&#34;color:#75715e&#34;&gt;// ❌ 占满 Default 的 worker（= CPU 核数）
&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;suspend&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;find&lt;/span&gt;(id: String) = jdbcTemplate.queryForObject(&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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ✅ 切到 IO
&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;suspend&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;find&lt;/span&gt;(id: String): Order = withContext(&lt;span style=&#34;color:#a6e22e&#34;&gt;Dispatchers&lt;/span&gt;.IO) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    jdbcTemplate.queryForObject(&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;症状&lt;/strong&gt;：CPU 低、所有接口一起慢、常规指标正常。
&lt;strong&gt;验证&lt;/strong&gt;：wall 火焰图 + 「RUNNABLE == 核数」。&lt;/p&gt;
&lt;h3 id=&#34;-synchronized-跨越挂起点-&#34;&gt;❷ &lt;code&gt;synchronized&lt;/code&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;&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;suspend&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    synchronized(lock) {
&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;val&lt;/span&gt; data = loadFromDb()      &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;        cache.update(&lt;span style=&#34;color:#66d9ef&#34;&gt;data&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:#75715e&#34;&gt;// ✅ 用 Mutex（协程感知的锁）
&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; mutex = Mutex()
&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;suspend&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;() = mutex.withLock {
&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;val&lt;/span&gt; data = loadFromDb()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cache.update(&lt;span style=&#34;color:#66d9ef&#34;&gt;data&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;code&gt;synchronized&lt;/code&gt; 是线程级锁，协程会在不同线程间切换 → 语义混乱、可能死锁。&lt;/p&gt;</description>
    </item>
    <item>
      <title>结论的写法</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/08-writing-conclusions/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/08-writing-conclusions/</guid>
      <description>&lt;h1 id=&#34;68-结论的写法&#34;&gt;6.8 结论的写法&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/07-traps-kotlin-and-cpp/&#34;&gt;6.7 陷阱清单：Kotlin 与 C++ 直觉&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/09-lab6/&#34;&gt;6.9 Lab 6&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/08-writing-conclusions/&#34;&gt;06-analysis-and-profiling/08-writing-conclusions&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;：「你怎么知道是这个？」「它占多少？」「为什么不是别的？」——分别对应&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;/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;&lt;strong&gt;现象量化&lt;/strong&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;strong&gt;证据链&lt;/strong&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;strong&gt;根因&lt;/strong&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;strong&gt;贡献占比&lt;/strong&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;strong&gt;被排除的假设&lt;/strong&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;strong&gt;复现方式&lt;/strong&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;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-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 根因结论：&amp;lt;标题&amp;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. 现象
&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;| 接口 | GET /orders/{id} |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 指标 | P99 从 80ms → 400ms（P50 20→25ms） |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 时间 | 2025-01-15 14:30 开始 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 范围 | 所有实例；只影响带 user_id 的查询 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 变更 | 14:00 部署 v2.3.1 |
&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. 延迟分解
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 环节 | P99 | 占比 |
&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;| 网络 + 客户端排队 | 20 ms | 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 style=&#34;font-weight:bold&#34;&gt;**290 ms**&lt;/span&gt; | &lt;span style=&#34;font-weight:bold&#34;&gt;**72%**&lt;/span&gt; ⭐ |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 应用自身 | 13 ms | 3% |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| PostgreSQL | 65 ms | 16% |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Redis + 下游 | 12 ms | 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;&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;**v2.3.1 新增的 &lt;span style=&#34;color:#e6db74&#34;&gt;`/orders/stream`&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;`OrderStreamHandler.kt:42`&lt;/span&gt;（长轮询默认 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;&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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### 证据 1：网关侧连接等待时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;命令：curl -s gateway:9090/metrics | grep gateway_upstream_wait
输出：P99 = 340ms（基线 8ms）&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lab 6：在埋雷服务上定位三个瓶颈</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/09-lab6/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/06-analysis-and-profiling/09-lab6/</guid>
      <description>&lt;h1 id=&#34;69-lab-6在埋雷服务上定位三个瓶颈&#34;&gt;6.9 Lab 6：在埋雷服务上定位三个瓶颈&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&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/07-optimization-and-validation/&#34;&gt;第 7 章 优化与验证&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/06-analysis-and-profiling/09-lab6/&#34;&gt;06-analysis-and-profiling/09-lab6&lt;/a&gt;
预计时长：&lt;strong&gt;120 分钟&lt;/strong&gt;&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;在一个「埋了三个不同性质瓶颈」的服务上，走完整套分析流程，产出一份合格的根因结论。&lt;/strong&gt;&lt;/p&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;p&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;code&gt;GET /slow-cpu&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;CPU 密集&lt;/strong&gt;：热路径上重复编译正则&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cpu&lt;/code&gt; 火焰图&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GET /slow-io&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;阻塞 IO&lt;/strong&gt;：在 &lt;code&gt;Dispatchers.Default&lt;/code&gt; 上执行 JDBC&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wall&lt;/code&gt; 火焰图 + 协程 dump&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GET /slow-db&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;N+1&lt;/strong&gt;：循环里单条查询&lt;/td&gt;
					&lt;td&gt;DB 指标（&lt;code&gt;calls&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-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;// ① CPU 密集：每次请求都重新编译正则
&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;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/slow-cpu&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;val&lt;/span&gt; text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;.repeat(&lt;span style=&#34;color:#ae81ff&#34;&gt;20_000&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;var&lt;/span&gt; hits = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    repeat(&lt;span style=&#34;color:#ae81ff&#34;&gt;200&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;val&lt;/span&gt; re = Regex(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;\d{3}-\d{4}&amp;#34;&amp;#34;&amp;#34;&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;        hits &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; re.findAll(text).count()
&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;    call.respondText(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hits=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$hits&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;
&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;// ② 阻塞 IO：在 Default 上做阻塞调用
&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;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/slow-io&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;val&lt;/span&gt; n = ds.connection.use { c &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;          &lt;span style=&#34;color:#75715e&#34;&gt;// ← JDBC 是阻塞的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        c.createStatement().use { s &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            s.executeQuery(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;select pg_sleep(0.02), 1&amp;#34;&lt;/span&gt;).use { rs &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; rs.next(); rs.getInt(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&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;    call.respondText(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;n=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$n&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;
&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;// ③ N+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:#66d9ef&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/slow-db&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;val&lt;/span&gt; ids = (&lt;span style=&#34;color:#ae81ff&#34;&gt;1L&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;..&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;100L&lt;/span&gt;).map { (&lt;span style=&#34;color:#66d9ef&#34;&gt;it&lt;/span&gt; * &lt;span style=&#34;color:#ae81ff&#34;&gt;7919&lt;/span&gt;) % &lt;span style=&#34;color:#ae81ff&#34;&gt;100_000&lt;/span&gt; + &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;    &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; urls = ids.map { id &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;               &lt;span style=&#34;color:#75715e&#34;&gt;// ← 100 次独立查询
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ds.connection.use { c &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            c.prepareStatement(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;select url from orders where id = ?&amp;#34;&lt;/span&gt;).use { ps &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ps.setLong(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ps.executeQuery().use { rs &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (rs.next()) rs.getString(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&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;    call.respondText(urls.filterNotNull().joinToString(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;为什么要分开三个接口&lt;/strong&gt;：如果三个瓶颈混在同一个接口里，你只能看到「又慢又 CPU 高」，无法分别验证。&lt;strong&gt;分开之后，每个瓶颈的症状是干净的。&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
