<?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/01-metrics-and-slo/</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/01-metrics-and-slo/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>指标分四层，缺一层就无法定位</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/01-four-layers-of-metrics/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/01-four-layers-of-metrics/</guid>
      <description>&lt;h1 id=&#34;11-指标分四层缺一层就无法定位&#34;&gt;1.1 指标分四层，缺一层就无法定位&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：无　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/02-percentiles-and-aggregation/&#34;&gt;1.2 百分位不可平均&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/01-metrics-and-slo/01-four-layers-of-metrics/&#34;&gt;01-metrics-and-slo/01-four-layers-of-metrics&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;strong&gt;速度表&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;速度表显示 60 km/h —— 车在正常行驶。&lt;/li&gt;
&lt;li&gt;突然，速度掉到 20 km/h。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;你知道出问题了，但完全不知道原因&lt;/strong&gt;：是没油了？发动机过热？轮胎漏气？还是前面堵车？&lt;/p&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;/td&gt;
					&lt;td&gt;业务层&lt;/td&gt;
					&lt;td&gt;车跑得快不快（QPS）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;乘客的等待时间&lt;/td&gt;
					&lt;td&gt;延迟层&lt;/td&gt;
					&lt;td&gt;体验好不好（P99）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;油量、转速、水温&lt;/td&gt;
					&lt;td&gt;资源层&lt;/td&gt;
					&lt;td&gt;消耗了什么（CPU / 内存 / 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;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;strong&gt;已经发生的结果&lt;/strong&gt;」，而警告灯是「&lt;strong&gt;即将发生问题的预警&lt;/strong&gt;」。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;速度掉到 20 km/h 时，问题已经发生了，你只能被动应对。&lt;/li&gt;
&lt;li&gt;水温警告灯亮起时，你还有时间靠边停车。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&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;h3 id=&#34;第-1-层业务层--服务好不好用&#34;&gt;第 1 层：业务层 —— 「服务好不好用」&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;th&gt;常见坑&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;QPS / RPS&lt;/td&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;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;Apdex&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;/p&gt;</description>
    </item>
    <item>
      <title>百分位不可平均：直方图才是正解</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/02-percentiles-and-aggregation/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/02-percentiles-and-aggregation/</guid>
      <description>&lt;h1 id=&#34;12-百分位不可平均直方图才是正解&#34;&gt;1.2 百分位不可平均：直方图才是正解&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/01-four-layers-of-metrics/&#34;&gt;1.1 指标分四层&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/03-measurement-points/&#34;&gt;1.3 测量点&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/01-metrics-and-slo/02-percentiles-and-aggregation/&#34;&gt;01-metrics-and-slo/02-percentiles-and-aggregation&lt;/a&gt;
前置：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/00-introduction/03-latency-is-a-distribution/&#34;&gt;0.3 延迟是分布&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; 把多台机器的 P99 求平均，得到的数字不代表任何一台机器、也不代表任何用户。正确做法是：&lt;strong&gt;采集直方图（分桶统计），在查询时合并后再算百分位。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一用考试成绩理解位置与数量的区别&#34;&gt;一、用考试成绩理解「位置」与「数量」的区别&lt;/h2&gt;
&lt;p&gt;一个班 50 个学生考试。老师说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「我们班的&lt;strong&gt;平均分&lt;/strong&gt;是 78 分。」
「我们班的&lt;strong&gt;第 95 百分位分数&lt;/strong&gt;是 96 分。」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;现在把三个班合起来，问「全校的 P95 是多少」：&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;P95 分&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;一班&lt;/td&gt;
					&lt;td&gt;50&lt;/td&gt;
					&lt;td&gt;78&lt;/td&gt;
					&lt;td&gt;96&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;二班&lt;/td&gt;
					&lt;td&gt;50&lt;/td&gt;
					&lt;td&gt;80&lt;/td&gt;
					&lt;td&gt;97&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;三班&lt;/td&gt;
					&lt;td&gt;50&lt;/td&gt;
					&lt;td&gt;76&lt;/td&gt;
					&lt;td&gt;95&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;❌ 错误做法&lt;/strong&gt;：&lt;code&gt;(96 + 97 + 95) / 3 = 96&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么错&lt;/strong&gt;：「第 95 百分位」是「排在第 95% 位置上的那个分数」。三个班的「第 95% 位置」是三个不同的位置，把它们平均，得到的不是任何一个真实位置上的分数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;✅ 正确做法&lt;/strong&gt;：把 150 个分数合在一起重新排序，再取第 95% 位置。这个结果可能不是 96、97、95 中的任何一个。&lt;/p&gt;</description>
    </item>
    <item>
      <title>测量点：同一个请求，三个不同的数字</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/03-measurement-points/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/03-measurement-points/</guid>
      <description>&lt;h1 id=&#34;13-测量点同一个请求三个不同的数字&#34;&gt;1.3 测量点：同一个请求，三个不同的数字&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/02-percentiles-and-aggregation/&#34;&gt;1.2 百分位不可平均&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/04-writing-slo/&#34;&gt;1.4 SLO 的四要素写法&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/01-metrics-and-slo/03-measurement-points/&#34;&gt;01-metrics-and-slo/03-measurement-points&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;「这个接口要 200 ms」这句话，缺了最重要的一个信息：在哪测的。&lt;/strong&gt; 客户端测出 200 ms、网关测出 120 ms、服务端 handler 内部测出 30 ms——&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;/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;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;运输耗时&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;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;p&gt;&lt;strong&gt;「送达需要 3 天」这句话&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从「下单」算：3 天。这是&lt;strong&gt;用户体验&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;从「出库」算：2.5 天。这是&lt;strong&gt;物流公司内部的绩效&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;从「到达本市」算：6 小时。这是&lt;strong&gt;末端配送的效率&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三个数字都对，但&lt;strong&gt;你不能拿「末端配送 6 小时」去论证「用户 3 天能收到」&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;后端的测量点完全同理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三三个测量点&#34;&gt;三、三个测量点&lt;/h2&gt;
&lt;h3 id=&#34;31-客户端压测工具--真实用户浏览器--app&#34;&gt;3.1 客户端（压测工具 / 真实用户浏览器 / App）&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;包含：&lt;strong&gt;客户端排队 + 网络往返 + 网关 + 服务排队 + 服务处理 + 响应传输&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>SLO 的四要素写法</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/04-writing-slo/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/04-writing-slo/</guid>
      <description>&lt;h1 id=&#34;14-slo-的四要素写法&#34;&gt;1.4 SLO 的四要素写法&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/03-measurement-points/&#34;&gt;1.3 测量点&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/05-latency-budget/&#34;&gt;1.5 延迟预算&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/01-metrics-and-slo/04-writing-slo/&#34;&gt;01-metrics-and-slo/04-writing-slo&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;「P99 &amp;lt; 200 ms」不是一个 SLO，只是一半句话。&lt;/strong&gt; 完整的 SLO 必须包含四要素：&lt;strong&gt;指标 + 阈值、负载与数据前提、测量点、持续时长&lt;/strong&gt;。少了任何一项，验收时都会吵架（而且通常是上线后才吵）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一用验收合同理解-slo&#34;&gt;一、用「验收合同」理解 SLO&lt;/h2&gt;
&lt;p&gt;假设你要装修房子，和施工队签合同。你在合同上写：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「装修要好。」&lt;/p&gt;
&lt;/blockquote&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;对应 SLO 的要素&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;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;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;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;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;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;SLO 就是你和系统签的验收合同。&lt;/strong&gt; 一份只有「装修要好」的合同，结局一定是扯皮。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二四要素详解&#34;&gt;二、四要素详解&lt;/h2&gt;
&lt;h3 id=&#34;要素-1指标--阈值&#34;&gt;要素 1：指标 + 阈值&lt;/h3&gt;
&lt;p&gt;必须明确是&lt;strong&gt;哪个指标&lt;/strong&gt;（P99？P95？错误率？吞吐？）和&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;/td&gt;
					&lt;td&gt;P99 &amp;lt; 200 ms 且 P999 &amp;lt; 500 ms&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;「要稳定」&lt;/td&gt;
					&lt;td&gt;错误率 &amp;lt; 0.1%，超时率 &amp;lt; 0.05%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;「能扛住」&lt;/td&gt;
					&lt;td&gt;稳定支撑 500 RPS&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;要点&lt;/strong&gt;：延迟类 SLO 至少写两个分位数（P99 + P999，或 P95 + P99）。只写一个分位数时，你不知道「剩下那 1% 有多糟」。&lt;/p&gt;</description>
    </item>
    <item>
      <title>延迟预算：把 200 ms 拆到每一跳</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/05-latency-budget/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/05-latency-budget/</guid>
      <description>&lt;h1 id=&#34;15-延迟预算把-200-ms-拆到每一跳&#34;&gt;1.5 延迟预算：把 200 ms 拆到每一跳&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/04-writing-slo/&#34;&gt;1.4 SLO 的四要素写法&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/code/01-metrics-and-slo/05-latency-budget/&#34;&gt;01-metrics-and-slo/05-latency-budget&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;strong&gt;4 小时&lt;/strong&gt;（240 分钟）要完成三件事：去银行、去超市、回家做饭。&lt;/p&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;/td&gt;
					&lt;td&gt;40 min&lt;/td&gt;
					&lt;td&gt;35 min ✅&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;银行排队 + 办理&lt;/td&gt;
					&lt;td&gt;60 min&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;95 min&lt;/strong&gt; ⚠️&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;超市采购&lt;/td&gt;
					&lt;td&gt;50 min&lt;/td&gt;
					&lt;td&gt;45 min ✅&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;做饭&lt;/td&gt;
					&lt;td&gt;60 min&lt;/td&gt;
					&lt;td&gt;55 min ✅&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;余量&lt;/td&gt;
					&lt;td&gt;30 min&lt;/td&gt;
					&lt;td&gt;10 min&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;p&gt;&lt;strong&gt;如果没有预算&lt;/strong&gt;，你只知道「今天超时了 25 分钟」，然后要挨个回忆哪一步慢了。&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;strong&gt;目标&lt;/strong&gt;：订单查询接口，客户端视角 P99 ≤ 200 ms。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;环节&lt;/th&gt;
					&lt;th&gt;预算 (P99)&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;25 ms&lt;/td&gt;
					&lt;td&gt;同城网络、连接复用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;网关处理（TLS / 鉴权 / 限流）&lt;/td&gt;
					&lt;td&gt;15 ms&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;20 ms&lt;/td&gt;
					&lt;td&gt;饱和度升高时最先牺牲的一项&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;应用逻辑（业务 + 序列化）&lt;/td&gt;
					&lt;td&gt;50 ms&lt;/td&gt;
					&lt;td&gt;你写的代码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;├ PostgreSQL&lt;/td&gt;
					&lt;td&gt;60 ms&lt;/td&gt;
					&lt;td&gt;复杂查询上限&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;├ Redis&lt;/td&gt;
					&lt;td&gt;5 ms&lt;/td&gt;
					&lt;td&gt;单次命令&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;└ 下游 HTTP 依赖&lt;/td&gt;
					&lt;td&gt;40 ms&lt;/td&gt;
					&lt;td&gt;含重试预算&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;响应传输&lt;/td&gt;
					&lt;td&gt;10 ms&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;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;strong&gt;故意算错的&lt;/strong&gt;，用来讲第二件事：预算必须自洽。&lt;/p&gt;</description>
    </item>
    <item>
      <title>基线与容量曲线：拐点才是容量</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/06-baseline-and-capacity-curve/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/06-baseline-and-capacity-curve/</guid>
      <description>&lt;h1 id=&#34;16-基线与容量曲线拐点才是容量&#34;&gt;1.6 基线与容量曲线：拐点才是容量&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/05-latency-budget/&#34;&gt;1.5 延迟预算&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/07-experiment-metadata/&#34;&gt;1.7 实验元数据&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/01-metrics-and-slo/06-baseline-and-capacity-curve/&#34;&gt;01-metrics-and-slo/06-baseline-and-capacity-curve&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 打满时的 QPS」不是容量，「延迟开始非线性上升的那个点」才是容量。&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;很少（20%）&lt;/td&gt;
					&lt;td&gt;你可以跑到 120 km/h，速度稳定&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;中等（50%）&lt;/td&gt;
					&lt;td&gt;还是 120 km/h，几乎不受影响&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;偏多（75%）&lt;/td&gt;
					&lt;td&gt;偶尔要减速，速度掉到 100 km/h&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;接近饱和（90%）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;速度骤降到 40 km/h，开始走走停停&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;完全饱和（100%）&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;strong&gt;通行量反而下降&lt;/strong&gt;（因为车距变小、刹车波传播）。这在交通工程里叫「相变」，在排队论里就是第 0 章讲的&lt;strong&gt;非线性&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键洞察&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你绝对不会说「这条路能通行 100% 的车流」——那意味着堵死。&lt;/li&gt;
&lt;li&gt;你会说「这条路在&lt;strong&gt;开始堵&lt;/strong&gt;之前，每小时能过 2000 辆车」。&lt;/li&gt;
&lt;li&gt;那个「开始堵」的点，就是&lt;strong&gt;拐点（knee）&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;后端服务完全一样&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;QPS 低时，延迟平稳；&lt;/li&gt;
&lt;li&gt;QPS 到某个点后，延迟开始&lt;strong&gt;非线性上升&lt;/strong&gt;（拐点）；&lt;/li&gt;
&lt;li&gt;继续加压，延迟爆炸、错误率上升（崩溃点）；&lt;/li&gt;
&lt;li&gt;再加压，&lt;strong&gt;实际 QPS 反而下降&lt;/strong&gt;（因为请求超时、重试、连接被占满）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二基线没有参照物的数字没有意义&#34;&gt;二、基线：没有参照物的数字没有意义&lt;/h2&gt;
&lt;h3 id=&#34;21-一个残酷的类比&#34;&gt;2.1 一个残酷的类比&lt;/h3&gt;
&lt;p&gt;你家的体重秤显示 &lt;strong&gt;70 kg&lt;/strong&gt;。这个数字是好是坏？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果你上个月是 65 kg → 涨了 5 kg，需要关注。&lt;/li&gt;
&lt;li&gt;如果你上个月是 75 kg → 减了 5 kg，进展良好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如果你从来没有称过 → 你只知道「70 kg」，无法判断。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;性能数字完全一样：&lt;/p&gt;</description>
    </item>
    <item>
      <title>实验元数据：没有它，数字等于没有</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/07-experiment-metadata/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/07-experiment-metadata/</guid>
      <description>&lt;h1 id=&#34;17-实验元数据没有它数字等于没有&#34;&gt;1.7 实验元数据：没有它，数字等于没有&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&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/01-metrics-and-slo/08-case-study-p99-lies/&#34;&gt;1.8 案例解剖&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/01-metrics-and-slo/07-experiment-metadata/&#34;&gt;01-metrics-and-slo/07-experiment-metadata&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;blockquote&gt;
&lt;p&gt;中火，橄榄油 15 ml，蒜末 10 g，翻炒 90 秒，加盐 2 g。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一份没用的菜谱：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;用合适的火候，加点油和蒜，炒一会儿，调味。&lt;/p&gt;
&lt;/blockquote&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;「压测了一下，P99 是 180 ms」&lt;/td&gt;
					&lt;td&gt;「JDK 21 + 默认 GC、4C8G、100 万行齐夫分布、k6 恒定到达率 500/s、预热 60 秒、稳态 5 分钟，客户端测得 P99 = 180 ms」&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;h3 id=&#34;-代码版本&#34;&gt;① 代码版本&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：commit hash 或镜像 tag。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：代码变了，性能就变了。这一项缺失，整个实验无法回溯。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-jvm-版本与完整参数&#34;&gt;② JVM 版本与完整参数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：JDK 发行版与版本号 + &lt;strong&gt;完整的 JVM 启动参数&lt;/strong&gt;（堆大小、GC 选型、&lt;code&gt;-XX&lt;/code&gt; 开关）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：&lt;code&gt;-Xmx&lt;/code&gt; 从 2g 改到 4g，GC 行为完全不同；换一个 GC 可能让吞吐差 20%。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见错误&lt;/strong&gt;：只写「JDK 21」，不写堆大小和 GC 类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-机器规格&#34;&gt;③ 机器规格&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：CPU 型号与核数、内存、磁盘类型（SSD/网络盘）、NUMA、是否容器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：「4 核」不等于「4 核」——不同代 CPU 的单核性能可能差 2 倍。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见错误&lt;/strong&gt;：写「8 核 16G」，但没写是物理机、云主机还是容器。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-容器与编排配置&#34;&gt;④ 容器与编排配置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：CPU &lt;code&gt;limit&lt;/code&gt; / &lt;code&gt;request&lt;/code&gt;、内存 limit、是否有 sidecar、副本数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：&lt;strong&gt;容器 CPU 节流是「本地压测很好、上线就慢」的头号原因&lt;/strong&gt;。&lt;code&gt;limit&lt;/code&gt; 设成 1 核时，即使宿主机有 32 核，你的进程也只能用 1 核，而且会被周期性掐停。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-操作系统与内核参数&#34;&gt;⑤ 操作系统与内核参数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：OS 与内核版本、文件描述符上限、&lt;code&gt;somaxconn&lt;/code&gt;、CPU governor。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：文件描述符上限会直接限制并发连接数；CPU governor 设为省电模式会导致频率波动，让数据抖动。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-数据库与中间件&#34;&gt;⑥ 数据库与中间件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：版本、规格、关键配置（连接数上限、缓存大小、隔离级别）、连接池配置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：PostgreSQL 的 &lt;code&gt;max_connections&lt;/code&gt;、&lt;code&gt;shared_buffers&lt;/code&gt; 直接决定性能上限。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-数据集规模--分布&#34;&gt;⑦ 数据集：规模 + &lt;strong&gt;分布&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：数据量级、访问分布（均匀 / 幂律，幂律要写 alpha）、是否预热缓存、连接是否复用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：这是&lt;strong&gt;最常被忽略的一项&lt;/strong&gt;。1 万行 vs 1 亿行会导致执行计划完全不同；均匀分布 vs 幂律分布会让缓存命中率差几倍。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-压测方式&#34;&gt;⑧ 压测方式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：工具与版本、&lt;strong&gt;流量模型&lt;/strong&gt;（到达率 / 虚拟用户）、目标 QPS、预热时长、测量时长、脚本 commit。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：闭环模型会系统性低估尾延迟（第 0 章 0.6 节）。不写模型，读者无法判断数据可信度。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-测量点与观测工具&#34;&gt;⑨ 测量点与观测工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：客户端 / 网关 / 应用内（见 &lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/03-measurement-points/&#34;&gt;1.3 节&lt;/a&gt;）、观测工具与采样频率、直方图桶边界。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;：不同测量点的数字不能比较；桶边界不对会让分位数失真。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三两个真实的反例&#34;&gt;三、两个真实的反例&lt;/h2&gt;
&lt;h3 id=&#34;反例-1漏了-jvm-参数&#34;&gt;反例 1：漏了 JVM 参数&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;实验 A（上周）：P99 = 120 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;实验 B（本周）：P99 = 95 ms，结论「优化有效，提升 21%」
&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;真相：本周换了 JVM 参数（堆从 2g 到 4g，GC 从 G1 换 ZGC），
&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;：只有 JVM 参数被记录，这个错误才能被发现。&lt;/p&gt;</description>
    </item>
    <item>
      <title>案例解剖：P99 达标，用户仍然不满</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/08-case-study-p99-lies/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/08-case-study-p99-lies/</guid>
      <description>&lt;h1 id=&#34;18-案例解剖p99-达标用户仍然不满&#34;&gt;1.8 案例解剖：P99 达标，用户仍然不满&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/07-experiment-metadata/&#34;&gt;1.7 实验元数据&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/09-lab1/&#34;&gt;1.9 Lab 1&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; 这一节把第 0、1 章的所有检查点，装进一个完整的排查故事里。&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;blockquote&gt;
&lt;p&gt;「我们的订单详情页最近用户投诉变多了，说很卡。但你们的监控显示 P99 只有 180 ms，完全达标啊？」&lt;/p&gt;
&lt;/blockquote&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;订单查询接口 P99（服务端埋点）&lt;/td&gt;
					&lt;td&gt;180 ms&lt;/td&gt;
					&lt;td&gt;✅ 达标（SLO 是 200 ms）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;错误率&lt;/td&gt;
					&lt;td&gt;0.05%&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;QPS&lt;/td&gt;
					&lt;td&gt;850&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CPU&lt;/td&gt;
					&lt;td&gt;55%&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;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;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;// 问题代码
&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; timer = &lt;span style=&#34;color:#a6e22e&#34;&gt;Timer&lt;/span&gt;.builder(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http.server.requests&amp;#34;&lt;/span&gt;).register(registry)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;timer.record(duration) { &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 style=&#34;color:#75715e&#34;&gt;// 请求在超时或抛异常时，根本没有走到 record()
&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;：这个接口有 3% 的请求在 2 秒后&lt;strong&gt;超时&lt;/strong&gt;并被网关中断，但这些请求&lt;strong&gt;根本没进入延迟统计&lt;/strong&gt;——它们被算成了「错误」，从延迟样本中消失了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结果&lt;/strong&gt;：统计里只剩「又快又成功」的请求，P99 自然漂亮。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lab 1：写出你的第一份 SLO 与延迟预算</title>
      <link>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/09-lab1/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/09-lab1/</guid>
      <description>&lt;h1 id=&#34;19-lab-1写出你的第一份-slo-与延迟预算&#34;&gt;1.9 Lab 1：写出你的第一份 SLO 与延迟预算&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;上一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/08-case-study-p99-lies/&#34;&gt;1.8 案例解剖&lt;/a&gt;　|　下一节：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/02-jvm-performance-basics/&#34;&gt;第 2 章 Kotlin/JVM 性能基础&lt;/a&gt;
配套代码：&lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/code/01-metrics-and-slo/09-lab1/&#34;&gt;01-metrics-and-slo/09-lab1&lt;/a&gt;
预计时长：&lt;strong&gt;60 分钟&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;strong&gt;一个被修正的埋点&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;不需要你压测出数据（那是第 3–4 章的事），只需要你把「要测什么、怎么算达标」想清楚。&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;选 2 个接口，写完整 SLO 表&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;docs/slo.md&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;20 min&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;为较复杂的接口写延迟预算表&lt;/td&gt;
					&lt;td&gt;同上文件&lt;/td&gt;
					&lt;td&gt;20 min&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;找出并修正一个错误埋点&lt;/td&gt;
					&lt;td&gt;代码改动 + 说明&lt;/td&gt;
					&lt;td&gt;15 min&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;code&gt;docs/experiments/E01-.../README.md&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;5 min&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三任务-1slo-表&#34;&gt;三、任务 1：SLO 表&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;接口选择建议&lt;/strong&gt;：选一个「读多写少、调用数据库」的接口，和一个「写操作、有事务」的接口。这样能覆盖两种不同的延迟特征。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SLO 表必须包含四要素&lt;/strong&gt;（见 &lt;a href=&#34;https://www.dorkytiger.top/kotlin/kotlin-benchmark/01-metrics-and-slo/04-writing-slo/&#34;&gt;1.4 节&lt;/a&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;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;目标 QPS&lt;/td&gt;
					&lt;td&gt;（写&lt;strong&gt;峰值&lt;/strong&gt;，不是平均）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;P50 / P95 / P99 / P999&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;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;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;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;/p&gt;</description>
    </item>
  </channel>
</rss>
