{
    "version": "https://jsonfeed.org/version/1",
    "title": "老王的个人博客",
    "description": "这是一个 LinuxSre 相关的技术播客",
    "home_page_url": "http://blog.jaxxwang.cn",
    "items": [
        {
            "id": "http://blog.jaxxwang.cn/posts/65018325.html",
            "url": "http://blog.jaxxwang.cn/posts/65018325.html",
            "title": "01 Prometheus入门：从监控到可观测性",
            "date_published": "2026-10-23T16:00:00.000Z",
            "content_html": "<h1 id=\"第-1-章-prometheus-入门从监控到可观测性\"><a class=\"anchor\" href=\"#第-1-章-prometheus-入门从监控到可观测性\">#</a> 第 1 章　Prometheus 入门：从监控到可观测性</h1>\n<blockquote>\n<p><strong>本章导读</strong></p>\n<p>如果你已经学过 Zabbix，第一个问题大概率是：<em>&quot;既然有 Zabbix 了，为什么还要再学一套 Prometheus？&quot;</em><br />\n本章就从这个疑问出发，先把&quot; 监控 &quot; 这件事放回到更大的框架 ——<strong> 可观测性</strong>里去看，再落到 Prometheus 本身：它是什么、由哪些组件拼成、数据怎么流转、模型长什么样。</p>\n<p>本章是整门课的地基。地基打不牢，后面装 Exporter、写 PromQL、配告警、接 Grafana 都会变成 &quot;照着敲命令&quot;，一旦报错就无从下手。</p>\n</blockquote>\n<p><strong>学习目标</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">序号</th>\n<th style=\"text-align:left\">学完本章，你应当能够</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1</td>\n<td style=\"text-align:left\">说清可观测性三大支柱，以及 Zabbix / Prometheus 分别属于哪一支</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">2</td>\n<td style=\"text-align:left\">画出完整监控系统的六大环节，并说明每个环节解决什么问题</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">3</td>\n<td style=\"text-align:left\">用 &quot;四个黄金指标&quot; 设计一套自己的监控项清单</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">4</td>\n<td style=\"text-align:left\">解释时序数据库为什么比关系型数据库更适合监控场景</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">5</td>\n<td style=\"text-align:left\">讲清 Prometheus 的组件构成与四条工作流程</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">6</td>\n<td style=\"text-align:left\">对比 Pull 与 Push 两种采集模型，回答 &quot;Zabbix 与 Prometheus 的区别&quot; 这道必考题</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">7</td>\n<td style=\"text-align:left\">看懂一条 Prometheus 指标的含义：metric 名 + 标签 = 唯一的 time series</td>\n</tr>\n</tbody>\n</table>\n<hr />\n<h2 id=\"11-先破一个误解prometheus-不是-zabbix-的替代品\"><a class=\"anchor\" href=\"#11-先破一个误解prometheus-不是-zabbix-的替代品\">#</a> 1.1　先破一个误解：Prometheus 不是 Zabbix 的替代品</h2>\n<p>很多同学下意识地把新技术当成旧技术的 &quot;升级包&quot;：有了 Prometheus，Zabbix 就该淘汰了。</p>\n<p><strong>不是这样的。</strong> 在真实的互联网公司里，这两个监控系统往往是<strong>并存</strong>的，有些大厂甚至是 &quot;两套都跑、各管一摊&quot;。</p>\n<p>原因在于它们的<strong>技术基因不同</strong>：</p>\n<ul>\n<li><strong>Zabbix</strong> 诞生在 &quot;物理机 + 虚拟机&quot; 的时代，历史悠久、生态成熟稳定，最擅长监控<strong>传统形态</strong>的东西 —— 物理服务器、交换机、路由器、存储设备这类固定资产，以及运行在固定 IP 上的传统服务。它对 SNMP、IPMI 这类硬件协议的支持非常完备。</li>\n<li><strong>Prometheus</strong> 诞生在<strong>容器化 / 云原生</strong>时代，天生就是为 &quot;<strong> 目标会动态变化</strong> &quot;的环境设计的。容器今天跑在这台机器、明天漂到那台机器，IP 一直在变，靠&quot; 提前把 IP 写进配置文件 &quot; 的方式根本跟不上节奏。</li>\n</ul>\n<p>一句话概括：</p>\n<blockquote>\n<p><strong>Zabbix 擅长 &quot;管得住的固定目标&quot;，Prometheus 擅长 &quot;抓不住的动态目标&quot;。</strong></p>\n</blockquote>\n<p>当然，这并不意味着 Prometheus 不能监控传统服务器 —— 它当然能， <code>node_exporter</code>  就是干这个的。也不是说 Zabbix 不能监控容器 —— 只是要费很大劲。</p>\n<pre><code>┌────────────────────────────────────────────────────────┐\n│  一家中大型公司的典型监控版图                            │\n├────────────────────────────────────────────────────────┤\n│  机房 / 网络设备 / 老旧业务  ──►  Zabbix                 │\n│  容器平台 / 微服务 / K8s     ──►  Prometheus + Grafana   │\n└────────────────────────────────────────────────────────┘\n</code></pre>\n<p>另外要提醒一句：<strong>&quot;Prometheus&quot; 这个名字，指的其实不是一个软件，而是一整套组件的集合。</strong> 这一点和 Zabbix 很像 ——Zabbix 也是一堆东西： <code>zabbix-server</code> 、 <code>zabbix-agent</code> 、 <code>zabbix-proxy</code> 、 <code>zabbix-web</code> 、 <code>zabbix-java-gateway</code> ，还得配一个 MySQL。Prometheus 同理，只是因为它在这套架构里分量最重，所以大家习惯用它的名字指代整个体系。</p>\n<hr />\n<h2 id=\"12-把眼界放宽什么是可观测性\"><a class=\"anchor\" href=\"#12-把眼界放宽什么是可观测性\">#</a> 1.2　把眼界放宽：什么是可观测性</h2>\n<h3 id=\"121-从控制论说起\"><a class=\"anchor\" href=\"#121-从控制论说起\">#</a> 1.2.1　从控制论说起</h3>\n<p><strong>可观测性（Observability）</strong> 这个词并不是 IT 行业发明的，它诞生于几十年前的控制理论，指的是：</p>\n<blockquote>\n<p><strong>通过检查系统的 &quot;输出&quot;，来推断系统 &quot;内部状态&quot; 的能力。</strong></p>\n<p>输出能反映内部状态的程度越高，系统的可观测性就越好。</p>\n</blockquote>\n<p>举个生活化的例子：你发烧了，医生不能直接 &quot;看见&quot; 你体内的炎症，但他可以通过<strong>体温、血常规、心率</strong>这些外部输出去推断。这些可测量的输出越丰富、越精确，诊断就越准。系统运维完全是同一个道理 —— 你没法钻进服务器里看它 &quot;心情如何&quot;，只能靠它吐出来的数据判断。</p>\n<p>📌 <strong>里程碑事件</strong>：2018 年，CNCF（云原生计算基金会）率先把 &quot;可观测性&quot; 引入 IT 领域，称其为<strong>云原生时代必须具备的能力</strong>，并出版《可观测性白皮书》做了系统阐述。</p>\n<h3 id=\"122-可观测性三大支柱三大信号\"><a class=\"anchor\" href=\"#122-可观测性三大支柱三大信号\">#</a> 1.2.2　可观测性三大支柱（三大信号）</h3>\n<p>白皮书提出的 &quot;可观测性三大信号&quot;，今天已经是 IT 领域的通识：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">支柱</th>\n<th style=\"text-align:left\">回答的问题</th>\n<th style=\"text-align:left\">数据特征</th>\n<th style=\"text-align:left\">代表工具</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>指标 Metrics</strong></td>\n<td style=\"text-align:left\">系统 &quot;现在怎么样&quot;？</td>\n<td style=\"text-align:left\">数值型、有明确时间戳、可聚合</td>\n<td style=\"text-align:left\"><strong>Prometheus</strong>、Zabbix</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>日志 Logging</strong></td>\n<td style=\"text-align:left\">&quot;究竟发生了什么&quot;？</td>\n<td style=\"text-align:left\">离散事件明细、文本、体量大</td>\n<td style=\"text-align:left\">ELK（Elasticsearch + Logstash + Kibana）、Loki</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>追踪 Tracing</strong></td>\n<td style=\"text-align:left\">一次请求 &quot;经过了谁&quot;？</td>\n<td style=\"text-align:left\">调用链路、有父子关系与耗时</td>\n<td style=\"text-align:left\">SkyWalking、Jaeger、Zipkin</td>\n</tr>\n</tbody>\n</table>\n<p>三者是互补关系，不是替代关系：</p>\n<ul>\n<li><strong>指标</strong>告诉你 &quot;CPU 用了 95%&quot;—— 发现<strong>异常</strong>；</li>\n<li><strong>日志</strong>告诉你 &quot;95% 是因为某个 SQL 死循环&quot;—— 定位<strong>原因</strong>；</li>\n<li><strong>追踪</strong>告诉你 &quot;这个 SQL 是在 A→B→C 这条链路里被 C 调用的&quot;—— 锁定<strong>位置</strong>。</li>\n</ul>\n<blockquote>\n<p>⚠️ <strong>注意</strong>：Zabbix 和我们今天要学的 Prometheus，都只属于<strong>第一支柱 —— 指标监控</strong>。<br />\n日志监控要靠 ELK，链路追踪要靠 SkyWalking。这两块不在本课程范围内，但它们是你在简历和面试里非常值钱的加分项，建议课外补齐。</p>\n</blockquote>\n<hr />\n<h2 id=\"13-一个完整监控系统的六大环节\"><a class=\"anchor\" href=\"#13-一个完整监控系统的六大环节\">#</a> 1.3　一个完整监控系统的六大环节</h2>\n<p>不管用什么工具，一个完整的监控系统，数据都要依次流过下面六个环节：</p>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">flowchart</span> LR</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    A<span class=\"token text string\">[\"① 数据来源&lt;br/>产生 / 暴露\"]</span> <span class=\"token arrow operator\">--></span> B<span class=\"token text string\">[\"② 数据采集&lt;br/>周期抓取\"]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    B <span class=\"token arrow operator\">--></span> C<span class=\"token text string\">[\"③ 数据存储&lt;br/>TSDB\"]</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    C <span class=\"token arrow operator\">--></span> D<span class=\"token text string\">[\"④ 数据处理&lt;br/>聚合 / 计算\"]</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    D <span class=\"token arrow operator\">--></span> E<span class=\"token text string\">[\"⑤ 展示分析&lt;br/>图形化\"]</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    E <span class=\"token arrow operator\">--></span> F<span class=\"token text string\">[\"⑥ 告警&lt;br/>阈值触发通知\"]</span></pre></td></tr></table></figure><p>把这六环背下来，你就能在任何监控产品上 &quot;对号入座&quot;—— 看任何一个新工具，只要问自己：它负责这六环里的哪一环？剩下的靠谁补？架构立刻清晰。</p>\n<h3 id=\"131-1-数据来源数据从哪来\"><a class=\"anchor\" href=\"#131-1-数据来源数据从哪来\">#</a> 1.3.1　① 数据来源：数据从哪来</h3>\n<p>要监控，首先得有数据。数据常见的产生与暴露方式有三类：</p>\n<ul>\n<li><strong>硬件本身的记录信息</strong> —— 以文件或内存属性的形式存在（比如  <code>/proc</code>  下的各种内核指标）；</li>\n<li><strong>应用业务的接口</strong> —— 主动暴露软件自身的运行状态，例如  <code>redis info</code> 、各类  <code>/status</code>  端点；</li>\n<li><strong>相关的信息采集工具</strong> —— 方便采集数据的系统级命令或采集器。</li>\n</ul>\n<p>这里有一个关键概念：<strong>这些数据在长时间运行中，都是以固定的 &quot;属性指标&quot; 来描述它们的，我们称之为 metric。</strong></p>\n<p>监控系统要做的事，就是<strong>对每个环境、每个指标都持续获取数据，并按用户需要的方式提供出去</strong>。</p>\n<h3 id=\"132-2-数据采集怎么把数据拿过来\"><a class=\"anchor\" href=\"#132-2-数据采集怎么把数据拿过来\">#</a> 1.3.2　② 数据采集：怎么把数据拿过来</h3>\n<p>指标数据不是取一次就完事，而是要<strong>持续、周期性地采集</strong>。按采集通道划分，分为两大类：</p>\n<p><strong>软件方式</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">方式</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>agent</strong></td>\n<td style=\"text-align:left\">专用的采集代理，装在目标机上，如 Zabbix Agent、node_exporter</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>http</strong></td>\n<td style=\"text-align:left\">基于 HTTP 协议拉取（Prometheus 的主流方式）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>ssh</strong></td>\n<td style=\"text-align:left\">常见的系统通信机制，但并非所有系统都支持，效率也偏低</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>SNMP</strong></td>\n<td style=\"text-align:left\">简单网络管理协议（Simple Network Management Protocol），广泛内置于交换机、路由器等网络设备</td>\n</tr>\n</tbody>\n</table>\n<p><strong>硬件方式</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">方式</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>IPMI</strong></td>\n<td style=\"text-align:left\">智能平台管理接口（Intelligent Platform Management Interface），工业标准，用于采集硬件物理健康数据：温度、电压、风扇转速、电源状态等</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>💡 <strong>关于 IPMI 的一个实战价值</strong>：服务器主板上通常有一块独立的<strong>带外管理卡</strong>（BMC）。它走独立网络，<strong>即使业务网络断了，你依然能连上去远程开机、关机、重启、装系统、看硬件告警</strong>。机房排障时，这是救命通道。</p>\n</blockquote>\n<p>❗ <strong>为什么采集量会爆炸？</strong> 因为每个业务场景需要采集的指标数量并不确定，有时<strong>一个业务场景就要采几百个指标</strong>。再乘上 &quot;周期性采集&quot;，数据量是极其可观的。这就直接引出了下一个环节 —— 存储。</p>\n<h3 id=\"133-3-数据存储为什么必须是时序数据库\"><a class=\"anchor\" href=\"#133-3-数据存储为什么必须是时序数据库\">#</a> 1.3.3　③ 数据存储：为什么必须是时序数据库</h3>\n<p>我们采集到的是 &quot;样本数据&quot;（sample），单个样本几乎没有意义，必须<strong>存下来</strong>，后续才能做聚合分析。而且使用这些数据时，<strong>不仅要知道值是多少，还必须知道 &quot;这是什么时候的值&quot;</strong>。</p>\n<p>所以监控数据天然带一个时间维度，我们称之为<strong>时间序列数据（Time Series Data，TS）</strong>，专门存储这类数据的数据库叫<strong>时序数据库（Time Series Database，TSDB）</strong>。</p>\n<blockquote>\n<p><strong>时序数据库的定义</strong>：用于存储时间序列数据，并以时间（时间点或时间区间）建立索引的软件。</p>\n</blockquote>\n<p>对比一下就很清楚了：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\"></th>\n<th style=\"text-align:left\">Zabbix</th>\n<th style=\"text-align:left\">Prometheus</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">后端存储</td>\n<td style=\"text-align:left\">关系型数据库（MySQL 等）</td>\n<td style=\"text-align:left\"><strong>内置 TSDB（时序数据库）</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">是否需要单独部署数据库</td>\n<td style=\"text-align:left\"><strong>需要</strong></td>\n<td style=\"text-align:left\"><strong>不需要</strong>，自身即数据库</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">面向场景</td>\n<td style=\"text-align:left\">通用型，什么都能塞</td>\n<td style=\"text-align:left\">专为监控场景优化</td>\n</tr>\n</tbody>\n</table>\n<p>这是 Prometheus 一个非常特殊、也非常重要的设计：<strong>它是监控系统，同时它自己就是数据库。</strong> 装完 Prometheus，你就同时拥有了采集器和存储，不用再单独折腾一个 MySQL。</p>\n<p>时序数据库的细节，我们在 1.5 节专门展开。</p>\n<h3 id=\"134-4-数据处理原始数据往往没有意义\"><a class=\"anchor\" href=\"#134-4-数据处理原始数据往往没有意义\">#</a> 1.3.4　④ 数据处理：原始数据往往没有意义</h3>\n<p>采集到的原始数据，本身常常说明不了问题，需要经过<strong>聚合、计算、切割</strong>才可用于分析。</p>\n<p>举个贯穿全书的例子。假设我们要判断 &quot;主机内存是否吃紧&quot;，直觉上会盯住 &quot;内存可用率&quot;：</p>\n<p><span class=\"katex-display\"><span class=\"katex\"><span class=\"katex-mathml\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><semantics><mrow><mtext>内存使用率</mtext><mo>=</mo><mfrac><mrow><mtext>MemTotal</mtext><mo>−</mo><mtext>MemAvailable</mtext></mrow><mtext>MemTotal</mtext></mfrac><mo>×</mo><mn>100</mn><mi mathvariant=\"normal\">%</mi></mrow><annotation encoding=\"application/x-tex\">\\text{内存使用率} = \\frac{\\text{MemTotal} - \\text{MemAvailable}}{\\text{MemTotal}} \\times 100\\%\n</annotation></semantics></math></span><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.68333em;vertical-align:0em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">内存使用率</span></span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span><span class=\"mrel\">=</span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:2.05744em;vertical-align:-0.686em;\"></span><span class=\"mord\"><span class=\"mopen nulldelimiter\"></span><span class=\"mfrac\"><span class=\"vlist-t vlist-t2\"><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:1.37144em;\"><span style=\"top:-2.314em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord text\"><span class=\"mord\">MemTotal</span></span></span></span><span style=\"top:-3.23em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"frac-line\" style=\"border-bottom-width:0.04em;\"></span></span><span style=\"top:-3.677em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord text\"><span class=\"mord\">MemTotal</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">−</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mord text\"><span class=\"mord\">MemAvailable</span></span></span></span></span><span class=\"vlist-s\">​</span></span><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:0.686em;\"><span></span></span></span></span></span><span class=\"mclose nulldelimiter\"></span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">×</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.80556em;vertical-align:-0.05556em;\"></span><span class=\"mord\">1</span><span class=\"mord\">0</span><span class=\"mord\">0</span><span class=\"mord\">%</span></span></span></span></span></p>\n<p>当它超过 70%（等价于可用率低于 30%）时告警。</p>\n<p>你看，<strong>这个 70% 并不是采集上来的，而是算出来的</strong>。这就是数据处理的典型场景：把两个原始指标做一次运算，得到一个有业务含义的新指标，再交给告警规则去判断。</p>\n<h3 id=\"135-5-数据展示人眼看不完的数字\"><a class=\"anchor\" href=\"#135-5-数据展示人眼看不完的数字\">#</a> 1.3.5　⑤ 数据展示：人眼看不完的数字</h3>\n<p>无论是原始时序数据，还是聚合后的统计结果，数据量都极其巨大。<strong>几万条数据用表格去看，是看不出来的</strong> —— 肉眼看不出趋势和拐点。</p>\n<p>所以可视化不是 &quot;锦上添花&quot;，而是监控系统的<strong>必需品</strong>：把数据画成折线图、柱状图、饼图、热力图，趋势和异常才一眼可见。</p>\n<blockquote>\n<p>Prometheus 的做法很 &quot;洒脱&quot;：<strong>它自己不做图形界面</strong>（只带一个非常简陋的 Web UI 用来调试），把可视化这块整体外包给了 <strong>Grafana</strong>。而 Zabbix 是自带图形功能的。</p>\n<p>这正是 Prometheus&quot;功能不完整&quot; 这一特点的来源 —— 后面还会提到。</p>\n</blockquote>\n<h3 id=\"136-6-告警让系统主动来找你\"><a class=\"anchor\" href=\"#136-6-告警让系统主动来找你\">#</a> 1.3.6　⑥ 告警：让系统主动来找你</h3>\n<p>监控系统最核心的价值之一，是<strong>在你不盯着屏幕的时候替你盯着</strong>。</p>\n<p>做法是：根据日常采集的数据，分析出 &quot;正常状态&quot; 的取值区间，把它设为一个<strong>阈值</strong>。之后每次采集到实时数据，都拿它与阈值比较，一旦越界，就通过告警机制通知到人。</p>\n<p>常见通知渠道：<strong>邮件、短信、钉钉、企业微信、电话、Webhook</strong>。</p>\n<p>在 Prometheus 体系里，这件事被拆成两半：</p>\n<ul>\n<li><strong>Prometheus Server</strong>：按告警规则周期性计算，<strong>只负责产生告警指示</strong>；</li>\n<li><strong>Alertmanager</strong>：接收告警后做<strong>去重、分组、抑制、路由</strong>，再决定发给谁。</li>\n</ul>\n<hr />\n<h2 id=\"14-监控什么以及怎么监控\"><a class=\"anchor\" href=\"#14-监控什么以及怎么监控\">#</a> 1.4　监控什么，以及怎么监控</h2>\n<h3 id=\"141-监控内容面试常问的你们公司都监控了什么\"><a class=\"anchor\" href=\"#141-监控内容面试常问的你们公司都监控了什么\">#</a> 1.4.1　监控内容：面试常问的 &quot;你们公司都监控了什么&quot;</h3>\n<p>&quot;贵公司监控了哪些东西？&quot;—— 这是运维岗的高频面试题。回答不好，会显得你只是 &quot;会点软件&quot;。下面这个三层框架可以直接拿去用。</p>\n<h4 id=\"第一层资源数据系统级\"><a class=\"anchor\" href=\"#第一层资源数据系统级\">#</a> 第一层：资源数据（系统级）</h4>\n<ul>\n<li><strong>硬件设备</strong>：服务器、路由器、交换机、IO 系统</li>\n<li><strong>系统资源</strong>：OS、网络、容器、VM 实例</li>\n<li><strong>应用软件</strong>：Nginx、MySQL、Redis、Java 应用等</li>\n</ul>\n<h4 id=\"第二层业务服务\"><a class=\"anchor\" href=\"#第二层业务服务\">#</a> 第二层：业务服务</h4>\n<ul>\n<li><strong>业务状态</strong>：服务通信、服务运行、服务下线、性能指标、QPS、DAU（日活）、转化率</li>\n<li><strong>业务接口</strong>：登录、注册、聊天、留言等关键接口的成功率与耗时</li>\n<li><strong>经营指标</strong>：产品转化率、充值额度、用户投诉量</li>\n<li><strong>一般故障</strong>：访问缓慢、存储空间不足、数据同步延迟、主机宕机、主机不可达</li>\n<li><strong>严重故障</strong>：服务不可用、集群故障</li>\n</ul>\n<blockquote>\n<p>💡 <strong>加分点</strong>：能说出 &quot; 监控要区分<strong>技术指标</strong>和<strong>业务指标</strong> &quot;，说明你不是只会看 CPU 内存。面试官听到&quot; 我们监控了支付成功率而不是只监控数据库连接数 &quot;，好感度会明显上升。</p>\n</blockquote>\n<h4 id=\"第三层趋势分析\"><a class=\"anchor\" href=\"#第三层趋势分析\">#</a> 第三层：趋势分析</h4>\n<ul>\n<li><strong>数据统计</strong>：以时间序列形式展示历史数据</li>\n<li><strong>数据预测</strong>：事件什么时候会发生、会持续多久、发生概率多大</li>\n</ul>\n<p>最典型的应用是<strong>容量预测</strong>：观察一段时间内磁盘增长曲线，推算 &quot;还有多少天写满&quot;，提前扩容。等到真写满了再去处理，业务已经中断了。</p>\n<h3 id=\"142-监控方法google-的四个黄金指标\"><a class=\"anchor\" href=\"#142-监控方法google-的四个黄金指标\">#</a> 1.4.2　监控方法：Google 的四个黄金指标</h3>\n<p>Google 提出了一套用来衡量<strong>服务级别</strong>健康状况的方法论，叫<strong>四个黄金指标（Four Golden Signals）</strong>。它特别适合<strong>应用与服务</strong>层面的监控。</p>\n<h4 id=\"1-延迟latency\"><a class=\"anchor\" href=\"#1-延迟latency\">#</a> ① 延迟（Latency）</h4>\n<ul>\n<li>服务处理请求所需的时间，例如 HTTP 请求的平均延迟；</li>\n<li>应用响应时间会受到<strong>所有</strong>核心资源的影响：网络、存储、CPU、内存；</li>\n<li>❗ <strong>关键要求：必须区分成功请求的延迟和失败请求的延迟。</strong></li>\n</ul>\n<blockquote>\n<p>为什么？因为失败请求往往 &quot;很快&quot;—— 连接直接被拒绝，耗时 1ms。如果你把成功和失败的延迟混在一起算平均值，一个大量报错的服务会显得 &quot;响应飞快&quot;，这是极其危险的误导。</p>\n</blockquote>\n<h4 id=\"2-流量traffic-吞吐量\"><a class=\"anchor\" href=\"#2-流量traffic-吞吐量\">#</a> ② 流量（Traffic / 吞吐量）</h4>\n<ul>\n<li>衡量服务的<strong>容量需求</strong>；</li>\n<li>常见形式：每秒 HTTP 请求数（QPS）、数据库每秒事务数（TPS）、每秒 API 调用数。</li>\n</ul>\n<h4 id=\"3-错误errors\"><a class=\"anchor\" href=\"#3-错误errors\">#</a> ③ 错误（Errors）</h4>\n<ul>\n<li>失败请求的数量，通常用<strong>绝对值</strong>或<strong>错误率百分比</strong>表示；</li>\n<li>包含三种形态：\n<ul>\n<li><strong>显式失败</strong>：HTTP 500、连接超时；</li>\n<li><strong>隐式失败</strong>：返回 200 但内容是错误页 / 无效内容；</li>\n<li><strong>策略性失败</strong>：按业务约定算失败，例如 &quot;响应时间超过 30ms 即视为失败&quot;。</li>\n</ul>\n</li>\n</ul>\n<h4 id=\"4-饱和度saturation\"><a class=\"anchor\" href=\"#4-饱和度saturation\">#</a> ④ 饱和度（Saturation）</h4>\n<ul>\n<li>衡量资源的 &quot;满&quot; 的程度，也就是<strong>利用率</strong>；</li>\n<li>覆盖 CPU（容量、配额、节流）、内存（容量、分配）、存储（容量、分配、IO 吞吐）、网络；</li>\n<li>典型指标：CPU 使用率、内存使用率、磁盘使用率、IO 利用率。</li>\n</ul>\n<blockquote>\n<p>📌 <strong>方法论怎么用</strong>：这四个指标不是让你死记，而是给你一个<strong>设计监控项的检查表</strong>。以后设计任何一套监控，先问四句：<br />\n它慢吗？它忙吗？它错吗？它满吗？</p>\n</blockquote>\n<p>需要说明的是，成熟公司通常已经有现成的监控指标清单（Excel 表格列几百项），而且 Zabbix 的模板里也内置了海量指标。<strong>你不必全都监控</strong> —— 监控项过多会显著加重负担。<strong>挑关键的监控，不重要的不兼顾</strong>，这也是为什么你需要学会自定义模板。</p>\n<hr />\n<h2 id=\"15-监控设施的实现方式\"><a class=\"anchor\" href=\"#15-监控设施的实现方式\">#</a> 1.5　监控设施的实现方式</h2>\n<h3 id=\"151-系统命令最原始也最不该被丢掉\"><a class=\"anchor\" href=\"#151-系统命令最原始也最不该被丢掉\">#</a> 1.5.1　系统命令：最原始，也最不该被丢掉</h3>\n<p>用 Linux 自带命令了解系统状态，是最 &quot;原始&quot; 的方式。经典如  <code>top</code> 、 <code>vmstat</code> 、 <code>iostat</code> 、 <code>free</code> 、 <code>ss</code> 、 <code>sar</code>  等，能快速看清 CPU、内存、磁盘、网络、进程的情况。</p>\n<p><code>top</code>  尤其经典 ——CPU、内存、负载、进程一目了然。但它有个致命局限：</p>\n<blockquote>\n<p><strong>只适合少量主机、临时性地看一眼。</strong> 一百台机器，你不可能挨个  <code>ssh</code>  上去敲  <code>top</code> 。</p>\n</blockquote>\n<p>不过命令行的价值在于<strong>排障现场</strong>。这里有一个非常容易搞错的细节，必须讲清楚。</p>\n<h4 id=\"重点free-top-里该盯哪个内存数字\"><a class=\"anchor\" href=\"#重点free-top-里该盯哪个内存数字\">#</a> ⭐ 重点： <code>free</code>  /  <code>top</code>  里，该盯哪个内存数字？</h4>\n<p>看一个真实例子：一台 <strong>8 GB</strong> 内存的机器， <code>top</code>  显示  <code>free</code>  只有 <strong>1.3 GB</strong>。</p>\n<blockquote>\n<p>这是不是意味着内存快满了？<strong>不是。</strong></p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">字段</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">是否是关键指标</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>free</code>  / 剩余内存</td>\n<td style=\"text-align:left\"><strong>完全未被任何用途占用</strong>的内存</td>\n<td style=\"text-align:left\">❌ 不是</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>available</code>  / 可用内存</td>\n<td style=\"text-align:left\"><strong>在不触发 swap 的前提下，能腾出来给应用用的内存</strong></td>\n<td style=\"text-align:left\">✅ <strong>是</strong></td>\n</tr>\n</tbody>\n</table>\n<p>原因：Linux 会把空闲内存拿去做 <strong>page cache（缓存）</strong>，这部分内存<strong>随时可以被回收</strong>交给应用使用。所以  <code>free</code>  小是正常的、甚至是健康的 —— 它说明系统没在浪费内存。</p>\n<p><strong>结论：判断内存是否吃紧，只看  <code>available</code> 。</strong></p>\n<p>对应的使用率算法就是：</p>\n<p><span class=\"katex-display\"><span class=\"katex\"><span class=\"katex-mathml\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><semantics><mrow><mtext>使用率</mtext><mo>=</mo><mfrac><mrow><mtext>MemTotal</mtext><mo>−</mo><mtext>MemAvailable</mtext></mrow><mtext>MemTotal</mtext></mfrac><mo>×</mo><mn>100</mn><mi mathvariant=\"normal\">%</mi></mrow><annotation encoding=\"application/x-tex\">\\text{使用率} = \\frac{\\text{MemTotal} - \\text{MemAvailable}}{\\text{MemTotal}} \\times 100\\%\n</annotation></semantics></math></span><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.68333em;vertical-align:0em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">使用率</span></span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span><span class=\"mrel\">=</span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:2.05744em;vertical-align:-0.686em;\"></span><span class=\"mord\"><span class=\"mopen nulldelimiter\"></span><span class=\"mfrac\"><span class=\"vlist-t vlist-t2\"><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:1.37144em;\"><span style=\"top:-2.314em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord text\"><span class=\"mord\">MemTotal</span></span></span></span><span style=\"top:-3.23em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"frac-line\" style=\"border-bottom-width:0.04em;\"></span></span><span style=\"top:-3.677em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord text\"><span class=\"mord\">MemTotal</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">−</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mord text\"><span class=\"mord\">MemAvailable</span></span></span></span></span><span class=\"vlist-s\">​</span></span><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:0.686em;\"><span></span></span></span></span></span><span class=\"mclose nulldelimiter\"></span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">×</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.80556em;vertical-align:-0.05556em;\"></span><span class=\"mord\">1</span><span class=\"mord\">0</span><span class=\"mord\">0</span><span class=\"mord\">%</span></span></span></span></span></p>\n<p>比如上面这台机器，总 8 GB、可用 3 GB：</p>\n<p><span class=\"katex-display\"><span class=\"katex\"><span class=\"katex-mathml\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><semantics><mrow><mfrac><mrow><mn>8</mn><mo>−</mo><mn>3</mn></mrow><mn>8</mn></mfrac><mo>×</mo><mn>100</mn><mi mathvariant=\"normal\">%</mi><mo>=</mo><mn>62.5</mn><mi mathvariant=\"normal\">%</mi></mrow><annotation encoding=\"application/x-tex\">\\frac{8 - 3}{8} \\times 100\\% = 62.5\\%\n</annotation></semantics></math></span><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:2.00744em;vertical-align:-0.686em;\"></span><span class=\"mord\"><span class=\"mopen nulldelimiter\"></span><span class=\"mfrac\"><span class=\"vlist-t vlist-t2\"><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:1.32144em;\"><span style=\"top:-2.314em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord\">8</span></span></span><span style=\"top:-3.23em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"frac-line\" style=\"border-bottom-width:0.04em;\"></span></span><span style=\"top:-3.677em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord\">8</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">−</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mord\">3</span></span></span></span><span class=\"vlist-s\">​</span></span><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:0.686em;\"><span></span></span></span></span></span><span class=\"mclose nulldelimiter\"></span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">×</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.80556em;vertical-align:-0.05556em;\"></span><span class=\"mord\">1</span><span class=\"mord\">0</span><span class=\"mord\">0</span><span class=\"mord\">%</span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span><span class=\"mrel\">=</span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.80556em;vertical-align:-0.05556em;\"></span><span class=\"mord\">6</span><span class=\"mord\">2</span><span class=\"mord\">.</span><span class=\"mord\">5</span><span class=\"mord\">%</span></span></span></span></span></p>\n<p>还有一点要顺带看一眼：<strong>swap 有没有被用上</strong>。swap 大量被使用，通常是内存真的不够了的信号；swap 完全没用，说明内存还撑得住。</p>\n<blockquote>\n<p>🔗 <strong>先记住这个细节</strong>，到了本课程后面的 PromQL 部分，你会看到它的 &quot;标准答案&quot;：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token operator\">/</span> node_memory_MemTotal_bytes <span class=\"token operator\">*</span> <span class=\"token number\">100</span> <span class=\"token operator\">></span> <span class=\"token number\">70</span></pre></td></tr></table></figure><p>你会发现，<strong>理论环节讲的计算逻辑，和最终写出来的查询语句是一一对应的</strong>。这就是为什么基础概念不能跳过。</p>\n</blockquote>\n<h3 id=\"152-开源软件从-nagios-cacti-到-zabbix-prometheus\"><a class=\"anchor\" href=\"#152-开源软件从-nagios-cacti-到-zabbix-prometheus\">#</a> 1.5.2　开源软件：从 Nagios、Cacti 到 Zabbix、Prometheus</h3>\n<p>历史上流行过的监控软件不少：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">软件</th>\n<th style=\"text-align:left\">时代</th>\n<th style=\"text-align:left\">现状</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Nagios</strong></td>\n<td style=\"text-align:left\">早期</td>\n<td style=\"text-align:left\">已基本退出主流</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Cacti</strong></td>\n<td style=\"text-align:left\">早期</td>\n<td style=\"text-align:left\">以绘图见长，现已少用</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Zabbix</strong></td>\n<td style=\"text-align:left\">二十余年历史</td>\n<td style=\"text-align:left\">依然主流，传统环境首选，成熟稳定</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Prometheus</strong></td>\n<td style=\"text-align:left\">云原生时代</td>\n<td style=\"text-align:left\">容器 / 微服务 / K8s 场景的事实标准</td>\n</tr>\n</tbody>\n</table>\n<p><strong>必学结论：把 Zabbix 和 Prometheus 这两套吃透，其余可以暂时不看。</strong></p>\n<h4 id=\"国产之光夜莺nightingale\"><a class=\"anchor\" href=\"#国产之光夜莺nightingale\">#</a> 国产之光：夜莺（Nightingale）</h4>\n<p>值得一提的还有国人开源的 <strong>夜莺（Nightingale）</strong>，由滴滴团队主导，从早期的 <strong>Open-Falcon（猎鹰）</strong> 演进而来，现已完全开源免费，不少公司在用。</p>\n<p>它的特点：</p>\n<ul>\n<li><strong>中文文档、中文界面</strong>，对国内团队极其友好；</li>\n<li><strong>产品完整度高</strong>，把采集、存储、展示、告警尽量一体化，不像 Prometheus 那样需要东拼西凑一堆组件；</li>\n<li>兼容 Prometheus 生态，可以<strong>直接替代</strong> Prometheus 承担部分职责；</li>\n<li>官方甚至专门做了 &quot;夜莺 vs Prometheus&quot; 的对比文档。</li>\n</ul>\n<blockquote>\n<p>这门课我们学的仍然是 <strong>Prometheus</strong>—— 它是业界最主流、最 &quot;标准&quot; 的方案，也是所有面试的默认话题。夜莺可以作为你工作后的备选方案，也可以作为面试里 &quot;我还了解国产方案&quot; 的加分项。</p>\n</blockquote>\n<h3 id=\"153-监控平台公有云自带\"><a class=\"anchor\" href=\"#153-监控平台公有云自带\">#</a> 1.5.3　监控平台：公有云自带</h3>\n<p>如果你用的是公有云，<strong>根本不用自己部署监控系统</strong>：</p>\n<ul>\n<li><strong>华为云</strong> → 云监控服务</li>\n<li><strong>阿里云</strong> → 云监控（CloudMonitor）</li>\n<li><strong>腾讯云</strong> → 云监控</li>\n</ul>\n<p>开箱即用，能直接监控云主机、云数据库、负载均衡等云资源。</p>\n<blockquote>\n<p>但要清楚它的边界：云监控擅长 &quot;云资源本身&quot;，一旦涉及你自建的中间件、业务指标、容器内部状态，往往还是得自己上 Prometheus。<br />\n<strong>&quot;云上监控&quot; 与 &quot;自建监控&quot; 也不是替代关系，而是叠加关系。</strong></p>\n</blockquote>\n<hr />\n<h2 id=\"16-时序数据库prometheus-的性能底座\"><a class=\"anchor\" href=\"#16-时序数据库prometheus-的性能底座\">#</a> 1.6　时序数据库：Prometheus 的性能底座</h2>\n<h3 id=\"161-什么是时间序列数据\"><a class=\"anchor\" href=\"#161-什么是时间序列数据\">#</a> 1.6.1　什么是时间序列数据</h3>\n<p><strong>时间序列数据（Time Series Data）</strong>：按照时间顺序记录系统、设备状态变化的数据 ——<strong> 以时间为横坐标，数据为纵坐标</strong>。</p>\n<p>它在我们身边无处不在：主机 CPU 每秒一个采样点、智能电表每 15 分钟一个读数、股票每分钟一个价格…… 都是时间序列。</p>\n<p><strong>时间序列数据库（TSDB）</strong> 则是一种高性能、低成本、稳定可靠的<strong>在线</strong>时序数据服务，提供高效读写、高压缩比存储、时序数据插值及聚合计算等能力。</p>\n<blockquote>\n<p>权威排名可参考 <a href=\"https://db-engines.com/en/ranking/time+series+dbms\">https://db-engines.com/en/ranking/time+series+dbms</a></p>\n</blockquote>\n<p><strong>典型应用场景</strong>：</p>\n<ul>\n<li><strong>物联网（IoT）</strong>：海量设备状态数据与业务消息，用于设备监控、业务分析预测、故障诊断；</li>\n<li><strong>工业 / 能源</strong>：电力、化工、制造行业的实时设备状态检测、故障发现、趋势分析（EMS 能源管理系统、生产安全监控系统、电力检测系统）；</li>\n<li><strong>系统运维与业务实时监控</strong>：大规模应用集群与机房设备监控，关注资源利用率与业务趋势，实现数据化运营与自动化运维。</li>\n</ul>\n<h3 id=\"162-时间序列数据的五个特点\"><a class=\"anchor\" href=\"#162-时间序列数据的五个特点\">#</a> 1.6.2　时间序列数据的五个特点</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">特点</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">对设计的启示</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>写多改少</strong></td>\n<td style=\"text-align:left\">绝大多数是顺序追加写入，几乎不修改</td>\n<td style=\"text-align:left\">可极端优化写入路径，无需复杂事务</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>删除成段</strong></td>\n<td style=\"text-align:left\">通常删除一整段时间的数据（如保留 15 天）</td>\n<td style=\"text-align:left\">按时间段分块存储，整块删除即可</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>读有序</strong></td>\n<td style=\"text-align:left\">查询基本是升序或降序扫描</td>\n<td style=\"text-align:left\">按时间做索引，顺序读</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>压缩高效</strong></td>\n<td style=\"text-align:left\">单点平均存储降至 <strong>1~2 字节</strong>，可节省约 <strong>90%</strong> 空间</td>\n<td style=\"text-align:left\">专用压缩算法，同时加快写入</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>性能高</strong></td>\n<td style=\"text-align:left\">每秒百万级数据点写入；亿级数据点聚合结果<strong>秒级</strong>返回</td>\n<td style=\"text-align:left\">面向列式 / 块式存储，而非通用行存</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"163-和关系型数据库比到底强在哪\"><a class=\"anchor\" href=\"#163-和关系型数据库比到底强在哪\">#</a> 1.6.3　和关系型数据库比，到底强在哪</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">维度</th>\n<th style=\"text-align:left\">关系型数据库（MySQL）</th>\n<th style=\"text-align:left\">时序数据库（TSDB）</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">通用性</td>\n<td style=\"text-align:left\"><strong>高</strong>，什么数据都能塞</td>\n<td style=\"text-align:left\">只擅长时序数据</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">监控场景性能</td>\n<td style=\"text-align:left\">一般</td>\n<td style=\"text-align:left\"><strong>极高</strong>（百万级写入 / 秒）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">压缩率</td>\n<td style=\"text-align:left\">一般</td>\n<td style=\"text-align:left\"><strong>高</strong>（节省约 90% 空间）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">数据模型</td>\n<td style=\"text-align:left\">表 / 行 / 主外键 / 强关联</td>\n<td style=\"text-align:left\">度量 + 标签 + 时间戳，结构极简</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">典型使用者</td>\n<td style=\"text-align:left\">Zabbix</td>\n<td style=\"text-align:left\"><strong>Prometheus</strong>、InfluxDB、VictoriaMetrics、TDengine</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>一句话记住：<strong>关系型数据库追求 &quot;通用&quot;，时序数据库追求 &quot;在时间这个维度上极致&quot;。</strong><br />\n这也是为什么在大规模容器化监控场景中，用 Prometheus 替代 Zabbix，性能表现会有明显提升。</p>\n</blockquote>\n<hr />\n<h2 id=\"17-prometheus-其人其名\"><a class=\"anchor\" href=\"#17-prometheus-其人其名\">#</a> 1.7　Prometheus 其人其名</h2>\n<h3 id=\"171-名字的由来\"><a class=\"anchor\" href=\"#171-名字的由来\">#</a> 1.7.1　名字的由来</h3>\n<p><strong>Prometheus（普罗米修斯）</strong> 是希腊神话中的一位神祇：他从太阳神阿波罗那里盗走火种送给人类，给人类带来了光明，因此成为一位受人敬仰的神。</p>\n<p>有意思的是，几乎每个文明都有类似 &quot;为人类带来光明&quot; 的传说（中国的燧人氏钻木取火、盘古开天、女娲造人……）。给一个监控系统起这个名字，寓意大约是：<strong>它在黑暗中为你点亮火光，让你看见系统的真实状态。</strong></p>\n<h3 id=\"172-它到底是什么\"><a class=\"anchor\" href=\"#172-它到底是什么\">#</a> 1.7.2　它到底是什么</h3>\n<p>准确地说：</p>\n<blockquote>\n<p><strong>Prometheus 是一款时序（time series）数据库（TSDB），同时也是一款用于实现 &quot;基于目标（Target）&quot; 的监控系统的关键组件。</strong></p>\n</blockquote>\n<p>它加上 <strong>Alertmanager、Pushgateway、Grafana</strong> 等外围组件，才构成一套完整的监控系统。</p>\n<h3 id=\"173-发展简史\"><a class=\"anchor\" href=\"#173-发展简史\">#</a> 1.7.3　发展简史</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">时间</th>\n<th style=\"text-align:left\">事件</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">灵感来源</td>\n<td style=\"text-align:left\">Google 内部的 <strong>BorgMon</strong> 监控系统（可理解为 BorgMon 的开源精神后继者）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>2012</strong></td>\n<td style=\"text-align:left\">由 SoundCloud 的前 Google 员工创建，作为社区开源项目开发</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>2015</strong></td>\n<td style=\"text-align:left\">正式对外发布</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>2016</strong></td>\n<td style=\"text-align:left\">加入 <strong>CNCF</strong>（云原生计算基金会），成为继 Kubernetes 之后第二个由 CNCF 托管的项目</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">其后</td>\n<td style=\"text-align:left\">从 CNCF <strong>毕业</strong>（Graduated），成为成熟项目</td>\n</tr>\n</tbody>\n</table>\n<p><strong>技术栈</strong>：完全由 <strong>Go</strong> 语言开发，编译后是<strong>单一静态二进制文件</strong>，无需任何运行时依赖，部署极为简单。</p>\n<ul>\n<li>官网：<a href=\"https://prometheus.io/\">https://prometheus.io/</a></li>\n<li>文档：<a href=\"https://prometheus.io/docs/introduction/overview/\">https://prometheus.io/docs/introduction/overview/</a></li>\n<li>GitHub：<a href=\"https://github.com/prometheus\">https://github.com/prometheus</a></li>\n<li>CNCF 全景图：<a href=\"https://landscape.cncf.io/\">https://landscape.cncf.io/</a></li>\n</ul>\n<blockquote>\n<p>💡 <strong>顺带一提</strong>：CNCF 现在成员极多，分类也细（应用定义与镜像构建、数据库、可观测性……）。MySQL、Redis、PostgreSQL、Zabbix、Prometheus、Jenkins 都在其中。业界有句玩笑话：<strong>&quot;不加入 CNCF，就显得有点落伍了。&quot;</strong> 这从侧面说明 Prometheus 不是孤立的工具，而是整个云原生生态的一环。</p>\n</blockquote>\n<hr />\n<h2 id=\"18-prometheus-的核心特点与不足\"><a class=\"anchor\" href=\"#18-prometheus-的核心特点与不足\">#</a> 1.8　Prometheus 的核心特点与不足</h2>\n<h3 id=\"181-核心特点\"><a class=\"anchor\" href=\"#181-核心特点\">#</a> 1.8.1　核心特点</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">特点</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>多维数据模型</strong></td>\n<td style=\"text-align:left\">时间序列由 &quot;度量名 + 键值对标签&quot; 组成，维度极其灵活</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>内置 TSDB</strong></td>\n<td style=\"text-align:left\">自带时序数据库，无需外部依赖，单机即可完整运行</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>PromQL</strong></td>\n<td style=\"text-align:left\">功能强大的查询语言，支持复杂查询与聚合，是图表与告警的基础</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>HTTP Pull 采集</strong></td>\n<td style=\"text-align:left\">主动向目标拉取指标，而非被动等待推送</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Pushgateway</strong></td>\n<td style=\"text-align:left\">为瞬时 / 短周期任务提供 &quot;推&quot; 的补充通道</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>目标发现（Service Discovery）</strong></td>\n<td style=\"text-align:left\">支持静态配置与自动发现（文件、DNS、Consul、K8s 等）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>丰富可视化</strong></td>\n<td style=\"text-align:left\">通过第三方 Dashboard（Grafana）实现</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>丰富的 Exporter 生态</strong></td>\n<td style=\"text-align:left\">几乎每种中间件都有现成的采集器</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"182-数据层面的特点\"><a class=\"anchor\" href=\"#182-数据层面的特点\">#</a> 1.8.2　数据层面的特点</h3>\n<ul>\n<li><strong>监控指标</strong>采用 Prometheus 自有的文本格式（&quot;Prometheus 格式&quot;），在监控领域极其常见；</li>\n<li><strong>数据标签</strong>支持多维标签，<strong>每个独立的标签组合都代表一个独立的时间序列</strong>；</li>\n<li><strong>数据处理</strong>内置多种聚合、切割、切片能力；</li>\n<li><strong>数据存储</strong>以双精度浮点型（float64）存储样本值。</li>\n</ul>\n<blockquote>\n<p>🔍 <strong>严谨补充</strong>：Prometheus 原生样本值只有  <code>float64</code>  一种类型；字符串只出现在  <code># HELP</code>  之类的元数据里。很多资料写 &quot;支持浮点型和字符串存储&quot;，容易让人误以为可以存文本指标 —— 实际不行。<strong>存文本明细那是日志系统（ELK/Loki）的活。</strong></p>\n</blockquote>\n<h3 id=\"183-适用场景\"><a class=\"anchor\" href=\"#183-适用场景\">#</a> 1.8.3　适用场景</h3>\n<ul>\n<li><strong>记录任何纯数字的时间序列</strong>；</li>\n<li>既适合<strong>以机器为中心</strong>的监控（主机、中间件），也适合<strong>高度动态的面向服务体系结构</strong>（微服务）；</li>\n<li>在微服务世界中，<strong>对多维数据收集与查询的支持是它的特别优势</strong>。</li>\n</ul>\n<p>Prometheus 的设计<strong>以可靠性为第一优先级</strong>，定位是 &quot;<strong> 故障期间要用的系统</strong> &quot;：</p>\n<blockquote>\n<p>每个 Prometheus Server 都是<strong>独立</strong>的，不依赖网络存储或其他远程服务。当基础设施的其他部分崩了，你依然可以依靠它 —— 而且不需要预先搭建庞大的基础设施就能用起来。</p>\n</blockquote>\n<p>但要注意代价：</p>\n<blockquote>\n<p><strong>如果你需要 100% 的准确性，Prometheus 不是好选择。</strong> 因为它采集的数据可能不够详细、不够完整（会丢点、会采样）。</p>\n<p>正确做法：<strong>计费、审计这类要求绝对精确的场景，用专门的系统；Prometheus 负责其余的监控。</strong></p>\n</blockquote>\n<h3 id=\"184-prometheus-的四个不足\"><a class=\"anchor\" href=\"#184-prometheus-的四个不足\">#</a> 1.8.4　Prometheus 的四个不足</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">不足</th>\n<th style=\"text-align:left\">说明</th>\n<th style=\"text-align:left\">应对思路</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>不支持集群化</strong></td>\n<td style=\"text-align:left\">原生单机，无内置 HA 集群方案</td>\n<td style=\"text-align:left\">双机 &quot;跑两份相同配置&quot; + 联邦（Federation）；或使用 Thanos / VictoriaMetrics</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>规模过大时有性能瓶颈</strong></td>\n<td style=\"text-align:left\">单机承载的目标数、序列数有天花板</td>\n<td style=\"text-align:left\">分片、联邦、远程存储</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>中文支持不好</strong></td>\n<td style=\"text-align:left\">界面默认英文</td>\n<td style=\"text-align:left\">配合 Grafana 做中文化面板</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>功能不完整</strong></td>\n<td style=\"text-align:left\">无原生图形界面、无原生告警发送能力</td>\n<td style=\"text-align:left\">必须配合 Grafana + Alertmanager</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ 对比一下：Zabbix 是自带图形界面的，所以 &quot;要装 Grafana&quot; 这件事，从 Zabbix 转过来的同学一开始会觉得别扭。</p>\n<p>另外补充一个资深运维才知道的八卦：<strong>Zabbix 中文界面乱码问题存在二十年了，官方为什么不修？</strong> 不是技术问题，是<strong>字体版权问题</strong> —— 它不能内置有版权的商业字体，只能由用户自己把系统中的中文字体拷过去配置。类似的 &quot;历史遗留问题&quot;，往往都不是技术原因，理解这一点能让你少走很多弯路。</p>\n</blockquote>\n<hr />\n<h2 id=\"19-pull-与-push两种数据获取模型\"><a class=\"anchor\" href=\"#19-pull-与-push两种数据获取模型\">#</a> 1.9　Pull 与 Push：两种数据获取模型</h2>\n<h3 id=\"191-prometheus-的选择只拉不推\"><a class=\"anchor\" href=\"#191-prometheus-的选择只拉不推\">#</a> 1.9.1　Prometheus 的选择：只拉不推</h3>\n<p>这是 Prometheus 与其它 TSDB 相比<strong>最典型的一个特性</strong>：</p>\n<blockquote>\n<p><strong>Prometheus 主动从各个 Target 上 &quot;拉取（Pull）&quot; 数据</strong>，而不是等待被监控端 &quot;推送（Push）&quot;。</p>\n</blockquote>\n<p>对应到 Zabbix 的语境里，它相当于 Zabbix 的<strong>被动模式</strong>。</p>\n<h3 id=\"192-先把-zabbix-的推拉搞清楚\"><a class=\"anchor\" href=\"#192-先把-zabbix-的推拉搞清楚\">#</a> 1.9.2　先把 Zabbix 的推拉搞清楚</h3>\n<p>这是最容易被讲混的地方，我们用 &quot;谁主动&quot; 来判断，一秒钟分清：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">模式</th>\n<th style=\"text-align:left\">谁主动</th>\n<th style=\"text-align:left\">动作方向</th>\n<th style=\"text-align:left\">对 Zabbix Server 的影响</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>被动模式</strong>（默认）</td>\n<td style=\"text-align:left\"><strong>Server 主动</strong></td>\n<td style=\"text-align:left\">Server → Agent 索要数据</td>\n<td style=\"text-align:left\">Server 要挨个问 100 台机器 = 100 次请求，<strong>负担重</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>主动模式</strong></td>\n<td style=\"text-align:left\"><strong>Agent 主动</strong></td>\n<td style=\"text-align:left\">Agent → Server 推送数据</td>\n<td style=\"text-align:left\">Server 只等着接收，<strong>负担轻，性能更好</strong></td>\n</tr>\n</tbody>\n</table>\n<p>所以 Zabbix 的<strong>性能优化手段之一，就是把被动模式改成主动模式</strong>：让 Agent 主动把数据推给 Server。</p>\n<blockquote>\n<p>🧠 <strong>记忆技巧</strong>：不要记 &quot;推 / 拉&quot; 这两个字，记 **&quot;谁是主动方&quot;**。</p>\n<ul>\n<li>Zabbix 被动模式 = Server 主动拉 = 对应 Prometheus 的做法</li>\n<li>Zabbix 主动模式 = Agent 主动推 = 对应 InfluxDB 的做法</li>\n</ul>\n</blockquote>\n<h3 id=\"193-三种系统的对照\"><a class=\"anchor\" href=\"#193-三种系统的对照\">#</a> 1.9.3　三种系统的对照</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">系统</th>\n<th style=\"text-align:left\">采集模型</th>\n<th style=\"text-align:left\">对应 Zabbix 的说法</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Zabbix</strong></td>\n<td style=\"text-align:left\">推、拉<strong>都支持</strong></td>\n<td style=\"text-align:left\">主动模式 + 被动模式</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Prometheus</strong></td>\n<td style=\"text-align:left\"><strong>只支持拉（Pull）</strong></td>\n<td style=\"text-align:left\">仅相当于<strong>被动模式</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>InfluxDB</strong></td>\n<td style=\"text-align:left\">推（Push）</td>\n<td style=\"text-align:left\">相当于<strong>主动模式</strong></td>\n</tr>\n</tbody>\n</table>\n<p><strong>Prometheus 只支持 Pull，不支持 Push。这一点务必记住。</strong></p>\n<h3 id=\"194-pull-模型为什么是优点而不是缺点\"><a class=\"anchor\" href=\"#194-pull-模型为什么是优点而不是缺点\">#</a> 1.9.4　Pull 模型为什么是 &quot;优点&quot; 而不是 &quot;缺点&quot;</h3>\n<p>表面上看，Pull 很吃亏：Server 要主动去问每一台机器，理论上性能不如被推。但 Prometheus 为什么坚持这么做？</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">Pull 的优势</th>\n<th style=\"text-align:left\">解释</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>集中控制</strong></td>\n<td style=\"text-align:left\">抓什么目标、按什么频率抓、抓哪些指标，全部集中在 Server 端配置，无需改动被监控端</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>健康状态天然可知</strong></td>\n<td style=\"text-align:left\">抓不到 = 目标挂了。Prometheus 会自动生成  <code>up</code>  指标，<strong>探活是免费的</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>调试极其方便</strong></td>\n<td style=\"text-align:left\">浏览器直接打开  <code>http://目标:端口/metrics</code>  就能看到全部指标，不依赖任何推送服务</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>目标可控可审计</strong></td>\n<td style=\"text-align:left\">Server 端就是唯一事实来源，不会出现 &quot;谁偷偷推了脏数据&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>契合动态环境</strong></td>\n<td style=\"text-align:left\">配合服务发现，目标增删自动跟上，无需在每个容器里配推送地址</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p><strong>Pull 的核心目标</strong>：Prometheus 的根本目标是收集 <strong>Target 上已经预先完成聚合的聚合型数据</strong>，而不是做一个由事件驱动的存储系统。</p>\n<p>换句话说：<strong>指标该在哪儿算好，就在哪儿算好；Prometheus 只负责 &quot;取走成品&quot;。</strong></p>\n</blockquote>\n<p>关于 &quot;性能不如推&quot; 的担忧：理论上有影响，但 Prometheus 用的是 &quot;专为监控优化的 TSDB&quot;，而不是 MySQL 这种通用关系库，<strong>实际差距远没有想象中大</strong>。</p>\n<blockquote>\n<p>🎯 <strong>面试直达：Zabbix 与 Prometheus 有什么区别？</strong></p>\n<p>按下面五点作答，条理清晰、直接给分：</p>\n<ol>\n<li><strong>采集模型</strong>：Zabbix 推拉都支持（默认被动 = 拉，可改主动 = 推）；Prometheus <strong>只支持 Pull</strong>。</li>\n<li><strong>存储</strong>：Zabbix 依赖<strong>关系型数据库</strong>（MySQL）；Prometheus <strong>内置时序数据库 TSDB</strong>。</li>\n<li><strong>数据模型</strong>：Zabbix 以主机 / 监控项为中心；Prometheus 是<strong>多维标签模型</strong>， <code>metric + labels</code>  唯一确定一条时间序列。</li>\n<li><strong>动态环境适配</strong>：Prometheus 原生<strong>服务发现</strong>，天然适配容器 / K8s；Zabbix 靠 Agent 固定部署，容器场景笨重。</li>\n<li><strong>生态定位</strong>：Prometheus 无图形、无告警发送能力，需配 Grafana + Alertmanager；Zabbix <strong>开箱即用、功能完整</strong>。</li>\n</ol>\n<p>再加一句收尾：&quot;<strong> 两者不是替代关系，很多公司同时使用</strong> &quot;—— 这一句往往就是面试官想听到的深度。</p>\n</blockquote>\n<hr />\n<h2 id=\"110-prometheus-架构\"><a class=\"anchor\" href=\"#110-prometheus-架构\">#</a> 1.10　Prometheus 架构</h2>\n<h3 id=\"1101-整体架构图\"><a class=\"anchor\" href=\"#1101-整体架构图\">#</a> 1.10.1　整体架构图</h3>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">flowchart</span> LR</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    SD<span class=\"token text string\">[\"服务发现&lt;br/>文件 / DNS / Consul / K8s\"]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token keyword\">subgraph</span> TARGETS<span class=\"token text string\">[\"被监控目标（Target）\"]</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>        E1<span class=\"token text string\">[\"Exporters&lt;br/>node_exporter&lt;br/>mysqld_exporter ...\"]</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>        E2<span class=\"token text string\">[\"Instrumentation&lt;br/>应用内嵌客户端库\"]</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>        PG<span class=\"token text string\">[\"Pushgateway&lt;br/>短周期 / 批处理任务\"]</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>        PS2<span class=\"token text string\">[\"其它 Prometheus&lt;br/>联邦 / 级联\"]</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token keyword\">end</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    PS<span class=\"token text string\">[\"Prometheus Server&lt;br/>① Retrieval 抓取&lt;br/>② TSDB 本地存储&lt;br/>③ Rules 规则计算\"]</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>    AM<span class=\"token text string\">[\"Alertmanager&lt;br/>去重 · 分组 · 抑制 · 路由\"]</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    R<span class=\"token text string\">[\"告警接收方&lt;br/>邮件 / 钉钉 / 企业微信 / Webhook\"]</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>    G<span class=\"token text string\">[\"Grafana / Web UI&lt;br/>可视化\"]</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    API<span class=\"token text string\">[\"HTTP API&lt;br/>供外部集成\"]</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>    SD <span class=\"token arrow operator\">--></span> PS</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    E1 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull|</span> PS</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    E2 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull|</span> PS</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    PG <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull|</span> PS</pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    PS2 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull|</span> PS</pre></td></tr><tr><td data-num=\"23\"></td><td><pre>    PS <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Push Alerts|</span> AM</pre></td></tr><tr><td data-num=\"24\"></td><td><pre>    AM <span class=\"token arrow operator\">--></span> R</pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    PS <span class=\"token arrow operator\">--></span> G</pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    PS <span class=\"token arrow operator\">--></span> API</pre></td></tr></table></figure><h3 id=\"1102-组件职责速查表\"><a class=\"anchor\" href=\"#1102-组件职责速查表\">#</a> 1.10.2　组件职责速查表</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">组件</th>\n<th style=\"text-align:left\">职责</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Prometheus Server</strong></td>\n<td style=\"text-align:left\">核心。彼此独立运行，仅依靠<strong>本地存储</strong>实现核心功能：抓取时序数据、规则处理、生成告警</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Client Library（客户端库）</strong></td>\n<td style=\"text-align:left\">嵌入到被监控服务中，直接生成并暴露符合 Prometheus 规范的 metrics。Server 来 pull 时直接返回<strong>实时状态</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Exporters</strong></td>\n<td style=\"text-align:left\">部署在第三方软件主机上，把<strong>本身不支持 Prometheus</strong> 的服务的指标，转换 / 聚合为 Prometheus 格式并暴露出来</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Pushgateway</strong></td>\n<td style=\"text-align:left\">接收短周期任务主动推送的指标，再由 Server 拉取。<strong>弥补 Pull 模型无法采集 &quot;转瞬即逝&quot; 任务的短板</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Alertmanager</strong></td>\n<td style=\"text-align:left\">接收 Server 的告警，做<strong>去重、分组、路由</strong>，再高效地发送给接收方</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Data Visualization</strong></td>\n<td style=\"text-align:left\">Prometheus 自带 Web UI + <strong>Grafana</strong> 等第三方方案</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Service Discovery</strong></td>\n<td style=\"text-align:left\">动态发现待监控的 Target，<strong>容器化环境中尤为关键</strong>；该能力目前由 Server 内建支持</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>📌 <strong>几乎所有组件都用 Go 编写</strong>，因此都极易构建、部署为静态二进制文件。这也是整个生态 &quot;一个 tar 包解压就能跑&quot; 的原因。</p>\n</blockquote>\n<h3 id=\"1103-三种数据进入口怎么选\"><a class=\"anchor\" href=\"#1103-三种数据进入口怎么选\">#</a> 1.10.3　三种 &quot;数据进入口&quot; 怎么选</h3>\n<p>Prometheus 默认支持三种从目标获取指标数据的途径，<strong>新手最容易在这里选错</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">方式</th>\n<th style=\"text-align:left\">适用对象</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Instrumentation</strong></td>\n<td style=\"text-align:left\"><strong>新应用</strong>（自己能改代码）</td>\n<td style=\"text-align:left\">在代码里引入客户端库（Go / Java / Python…）埋点并暴露 HTTP 端点。最 &quot;原生&quot; 的方式</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Exporters</strong></td>\n<td style=\"text-align:left\"><strong>老应用 / 第三方软件</strong>（改不了代码）</td>\n<td style=\"text-align:left\">如 MySQL、Redis、Nginx、HAProxy，用官方或社区的 exporter 去抓它们的原始指标并转换格式</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Pushgateway</strong></td>\n<td style=\"text-align:left\"><strong>短周期任务 / 批处理</strong></td>\n<td style=\"text-align:left\">任务运行时间极短，Server 还没来 pull 它就已经退出了，所以只能 &quot;先推到一个中转站&quot;，Server 再从中转站 pull</td>\n</tr>\n</tbody>\n</table>\n<p><strong>选型口诀</strong>：</p>\n<pre><code>能改代码 → Instrumentation\n不能改代码，但它一直活着 → Exporter\n活得太短，来不及被拉 → Pushgateway\n</code></pre>\n<blockquote>\n<p>⚠️ <strong>关于 Pushgateway 的两个重要提醒</strong>：</p>\n<ol>\n<li>它只是 Pull 模型的<strong>补充</strong>，不是让你把 Prometheus 用成 Push 系统；</li>\n<li>它<strong>不做过期清理</strong> —— 推上去的指标会一直存在。所以<strong>不要用它来上报 &quot;长期运行服务&quot; 的指标</strong>（服务挂了，旧数据还在，会造成 &quot;假存活&quot;）。官方明确建议：<strong>机器层面、服务层面的常规指标用 Exporter，不要用 Pushgateway。</strong></li>\n</ol>\n</blockquote>\n<h3 id=\"1104-工作流程四步走\"><a class=\"anchor\" href=\"#1104-工作流程四步走\">#</a> 1.10.4　工作流程：四步走</h3>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">sequenceDiagram</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token keyword\">participant</span> SD as 服务发现</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token keyword\">participant</span> PS as Prometheus Server</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token keyword\">participant</span> T as Target / Exporter</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token keyword\">participant</span> AM as Alertmanager</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token keyword\">participant</span> V as Grafana</pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    SD<span class=\"token arrow operator\">->></span>PS<span class=\"token operator\">:</span> 告知当前有哪些目标</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token keyword\">loop</span> 每个 scrape_interval</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>        PS<span class=\"token arrow operator\">->></span>T<span class=\"token operator\">:</span> GET /metrics <span class=\"token text string\">(Pull)</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>        T<span class=\"token arrow operator\">-->></span>PS<span class=\"token operator\">:</span> 返回文本格式指标</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>        PS<span class=\"token arrow operator\">->></span>PS<span class=\"token operator\">:</span> 写入 TSDB（内存 + WAL + Block）</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>        PS<span class=\"token arrow operator\">->></span>PS<span class=\"token operator\">:</span> 按告警规则周期性计算</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    <span class=\"token keyword\">end</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>    PS<span class=\"token arrow operator\">->></span>AM<span class=\"token operator\">:</span> 推送触发的告警</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    AM<span class=\"token arrow operator\">->></span>AM<span class=\"token operator\">:</span> 去重 / 分组 / 抑制 / 路由</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    AM<span class=\"token arrow operator\">-->></span>AM<span class=\"token operator\">:</span> 发送到邮件、钉钉等</pre></td></tr><tr><td data-num=\"18\"></td><td><pre>    V<span class=\"token arrow operator\">->></span>PS<span class=\"token operator\">:</span> PromQL 查询</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    PS<span class=\"token arrow operator\">-->></span>V<span class=\"token operator\">:</span> 返回时序数据</pre></td></tr></table></figure><p>用文字再复述一遍，这四步能背下来最好：</p>\n<ol>\n<li><strong>抓取</strong>：Prometheus Server 定期从配置好的 Jobs / Exporters 中<strong>拉取（Pull）</strong> Metrics；也会拉取 Pushgateway 上的指标（其数据是其他节点 Push 上来的）；也可以从<strong>其它 Prometheus Server</strong> 拉取（联邦）。</li>\n<li><strong>存储与规则计算</strong>：Server 将采集到的指标存到<strong>本地 TSDB</strong>，并周期性运行已定义的 <strong>Alert Rules</strong>；产生新序列或触发告警时，向 <strong>Alertmanager</strong> 推送告警。<strong>（每个 Server 独立运行、本地存储，因此天然具备一定程度的冗余能力）</strong></li>\n<li><strong>告警分发</strong>：Alertmanager 依据配置对告警做<strong>去重、分组</strong>，按 ** 路由（route）** 规则发送到对应接收方。</li>\n<li><strong>可视化</strong>：集成 <strong>Grafana</strong> 或其他 API 作为图形界面，展示采集到的数据。</li>\n</ol>\n<h3 id=\"1105-prometheus-只做一件事\"><a class=\"anchor\" href=\"#1105-prometheus-只做一件事\">#</a> 1.10.5　&quot;Prometheus 只做一件事&quot;</h3>\n<p>这一点必须建立正确的认知，否则你会一直困惑 &quot;为什么还缺这缺那&quot;：</p>\n<blockquote>\n<p><strong>Prometheus 只负责 &quot;时序型指标数据&quot; 的采集与存储。</strong></p>\n<p>数据的分析、聚合、直观展示、告警发送，<strong>都不由 Prometheus Server 负责</strong>，必须配合其它组件完成。</p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">我要的功能</th>\n<th style=\"text-align:left\">谁来做</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">抓取指标</td>\n<td style=\"text-align:left\">Prometheus Server</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">存指标</td>\n<td style=\"text-align:left\">Prometheus Server（内置 TSDB）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">查询 / 聚合</td>\n<td style=\"text-align:left\">PromQL（Server 内建）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">画图</td>\n<td style=\"text-align:left\"><strong>Grafana</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">发告警</td>\n<td style=\"text-align:left\"><strong>Alertmanager</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">采集各类中间件</td>\n<td style=\"text-align:left\"><strong>Exporters</strong>（官方 + 社区，生态极丰富）</td>\n</tr>\n</tbody>\n</table>\n<p>Exporter 清单见：<a href=\"https://prometheus.io/docs/instrumenting/exporters/\">https://prometheus.io/docs/instrumenting/exporters/</a></p>\n<hr />\n<h2 id=\"111-prometheus-数据模型\"><a class=\"anchor\" href=\"#111-prometheus-数据模型\">#</a> 1.11　Prometheus 数据模型</h2>\n<h3 id=\"1111-一切皆为时间序列\"><a class=\"anchor\" href=\"#1111-一切皆为时间序列\">#</a> 1.11.1　一切皆为时间序列</h3>\n<p>Prometheus 中存储的数据，全部是<strong>时间序列</strong> —— 即基于同一度量标准、或同一时间维度的数据流。</p>\n<blockquote>\n<p>除了正常存储原始时间序列，Prometheus 还会<strong>基于原始数据临时生成新的时间序列</strong>（例如 PromQL 的聚合结果），作为后续查询的依据或结果。</p>\n</blockquote>\n<p><strong>核心公式，请务必刻在脑子里：</strong></p>\n<p><span class=\"katex-display\"><span class=\"katex\"><span class=\"katex-mathml\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><semantics><mrow><menclose notation=\"box\"><mstyle scriptlevel=\"0\" displaystyle=\"false\"><mstyle scriptlevel=\"0\" displaystyle=\"false\"><mstyle scriptlevel=\"0\" displaystyle=\"true\"><mrow><mtext>时间序列</mtext><mo>=</mo><mtext>metric 名称</mtext><mo>+</mo><mtext>一组标签（键值对）</mtext><mo>+</mo><mtext>时间戳</mtext><mo>+</mo><mtext>样本值</mtext></mrow></mstyle></mstyle></mstyle></menclose></mrow><annotation encoding=\"application/x-tex\">\\boxed{\\text{时间序列} = \\text{metric 名称} + \\text{一组标签（键值对）} + \\text{时间戳} + \\text{样本值}}\n</annotation></semantics></math></span><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:1.44666em;vertical-align:-0.42333em;\"></span><span class=\"mord\"><span class=\"vlist-t vlist-t2\"><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:1.02333em;\"><span style=\"top:-3.44666em;\"><span class=\"pstrut\" style=\"height:3.44666em;\"></span><span class=\"boxpad\"><span class=\"mord\"><span class=\"mord\"><span class=\"mord text\"><span class=\"mord cjk_fallback\">时间序列</span></span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span><span class=\"mrel\">=</span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span><span class=\"mord text\"><span class=\"mord\">metric </span><span class=\"mord cjk_fallback\">名称</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">+</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">一组标签（键值对）</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">+</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">时间戳</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">+</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">样本值</span></span></span></span></span></span><span style=\"top:-3.02333em;\"><span class=\"pstrut\" style=\"height:3.44666em;\"></span><span class=\"stretchy fbox\" style=\"height:1.44666em;border-style:solid;border-width:0.04em;\"></span></span></span><span class=\"vlist-s\">​</span></span><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:0.42333em;\"><span></span></span></span></span></span></span></span></span></span></p>\n<p>其中，<strong>metric 名称 + 标签集合</strong>共同构成这条序列的<strong>唯一标识</strong>。</p>\n<blockquote>\n<p>💡 关键推论：<strong>只要任意一个标签的值变了（包括新增或删除标签），就产生了一条全新的时间序列。</strong><br />\n这就是为什么 &quot;标签设计&quot; 在 Prometheus 里如此重要 —— 标签设计不当会导致<strong>序列爆炸</strong>（cardinality explosion），直接把内存打满。这是第七章 &quot;标签管理&quot; 的核心话题。</p>\n</blockquote>\n<h3 id=\"1112-metric-名称\"><a class=\"anchor\" href=\"#1112-metric-名称\">#</a> 1.11.2　Metric 名称</h3>\n<ul>\n<li>必须<strong>有意义</strong>，用于表示 metric 的一般性功能，例如  <code>http_requests_total</code>  表示 HTTP 请求总数（ <code>_total</code>  后缀是 Counter 类型的约定）；</li>\n<li>命名规范：由 <strong>ASCII 字母、数字、下划线、冒号</strong> 组成。</li>\n</ul>\n<p><strong>准确的合法字符集（正则）</strong>：</p>\n<figure class=\"highlight regex\"><figcaption data-lang=\"regex\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre># metric 名称</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token char-class\"><span class=\"token char-class-punctuation punctuation\">[</span><span class=\"token range\">a<span class=\"token range-punctuation operator\">-</span>z</span><span class=\"token range\">A<span class=\"token range-punctuation operator\">-</span>Z</span>_:<span class=\"token char-class-punctuation punctuation\">]</span></span><span class=\"token char-class\"><span class=\"token char-class-punctuation punctuation\">[</span><span class=\"token range\">a<span class=\"token range-punctuation operator\">-</span>z</span><span class=\"token range\">A<span class=\"token range-punctuation operator\">-</span>Z</span><span class=\"token range\">0<span class=\"token range-punctuation operator\">-</span>9</span>_:<span class=\"token char-class-punctuation punctuation\">]</span></span><span class=\"token quantifier number\">*</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre># 标签名称</pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token char-class\"><span class=\"token char-class-punctuation punctuation\">[</span><span class=\"token range\">a<span class=\"token range-punctuation operator\">-</span>z</span><span class=\"token range\">A<span class=\"token range-punctuation operator\">-</span>Z</span>_<span class=\"token char-class-punctuation punctuation\">]</span></span><span class=\"token char-class\"><span class=\"token char-class-punctuation punctuation\">[</span><span class=\"token range\">a<span class=\"token range-punctuation operator\">-</span>z</span><span class=\"token range\">A<span class=\"token range-punctuation operator\">-</span>Z</span><span class=\"token range\">0<span class=\"token range-punctuation operator\">-</span>9</span>_<span class=\"token char-class-punctuation punctuation\">]</span></span><span class=\"token quantifier number\">*</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>常见误区纠偏</strong>：不少课件把这条正则简写成  <code>a-zA-Z_:*</code> ，看着像 &quot;允许出现星号&quot;，实际是笔误。记住上表两条规则即可 ——<strong> 首字符不能是数字</strong>，metric 名允许冒号，标签名不允许冒号。</p>\n</blockquote>\n<p><strong>关于冒号的保留说明</strong>：</p>\n<blockquote>\n<p><strong>冒号（ <code>:</code> ）是为用户定义的记录规则（recording rule）保留的</strong>，不要用在普通的 exporter 指标名里。</p>\n</blockquote>\n<h3 id=\"1113-标签label\"><a class=\"anchor\" href=\"#1113-标签label\">#</a> 1.11.3　标签（Label）</h3>\n<p>标签以<strong>键值对</strong>形式存在，用于表示时间序列的<strong>不同维度</strong>。</p>\n<p><strong>基本格式</strong>：</p>\n<pre><code>&lt;metric name&gt;&#123;&lt;label name&gt;=&lt;label value&gt;, ...&#125;\n</code></pre>\n<p><strong>示例</strong>：</p>\n<pre><code>http_requests_total&#123;method=&quot;POST&quot;, endpoint=&quot;/api/tracks&quot;&#125;\n</code></pre>\n<p><strong>解读</strong>：</p>\n<ul>\n<li><code>http_requests_total&#123;method=&quot;POST&quot;&#125;</code>  —— 所有 HTTP 请求中的 <strong>POST</strong> 请求；</li>\n<li>加上  <code>endpoint=&quot;/api/tracks&quot;</code>  —— 这些请求的 URL 是  <code>/api/tracks</code> ；</li>\n<li>如果  <code>method=&quot;GET&quot;</code> ，那它就是<strong>另一条完全不同的时间序列</strong>。</li>\n</ul>\n<p><strong>标签的命名与取值规则</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">规则</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">键名合法字符</td>\n<td style=\"text-align:left\">ASCII 字母、数字、下划线，正则  <code>[a-zA-Z_][a-zA-Z0-9_]*</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong> <code>__</code>  开头</strong></td>\n<td style=\"text-align:left\"><strong>保留给内部使用</strong>，用户不要使用（如  <code>__name__</code>  是 metric 名的内部表示）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">标签值</td>\n<td style=\"text-align:left\">可以是<strong>任意 Unicode 字符</strong>（可以写中文）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">空标签值</td>\n<td style=\"text-align:left\">被认为<strong>等同于标签不存在</strong>（等价于没有这个标签）</td>\n</tr>\n</tbody>\n</table>\n<p><strong>查询语言（PromQL）正是基于这些维度进行过滤与聚合的</strong> —— 这是 Prometheus 强大灵活性的根源：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 按 method 维度过滤</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"POST\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 按 method 维度聚合</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token keyword\">sum</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">(</span><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><h3 id=\"1114-数据格式exposition-format\"><a class=\"anchor\" href=\"#1114-数据格式exposition-format\">#</a> 1.11.4　数据格式（Exposition Format）</h3>\n<p>Exporter 把采集到的数据转换为<strong>纯文本格式</strong>，通过 HTTP 响应返回给 Prometheus Server。</p>\n<p><strong>格式规则</strong>：</p>\n<ul>\n<li>以 ** 行（ <code>\\n</code> ）** 为单位，<strong>空行被忽略</strong>，最后一行为空行；</li>\n<li>文本内容分四类：</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">行首标记</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code># HELP</code></td>\n<td style=\"text-align:left\">metric 的<strong>帮助说明</strong>（人类可读描述）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code># TYPE</code></td>\n<td style=\"text-align:left\">声明 metric <strong>类型</strong>： <code>counter</code>  /  <code>gauge</code>  /  <code>histogram</code>  /  <code>summary</code>  /  <code>untyped</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>#</code>  开头（其他）</td>\n<td style=\"text-align:left\">一般注释，供人阅读，<strong>Prometheus 会忽略</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">其他行</td>\n<td style=\"text-align:left\">真正的样本数据： <code>指标名&#123;标签&#125; 值 [时间戳]</code></td>\n</tr>\n</tbody>\n</table>\n<p><strong>一个真实的  <code>/metrics</code>  输出片段</strong>：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre># HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.</pre></td></tr><tr><td data-num=\"2\"></td><td><pre># TYPE node_cpu_seconds_total counter</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"idle\"&#125; 1.2345678e+06</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"system\"&#125; 34567.89</pre></td></tr><tr><td data-num=\"5\"></td><td><pre># HELP node_load1 1m load average.</pre></td></tr><tr><td data-num=\"6\"></td><td><pre># TYPE node_load1 gauge</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>node_load1 0.52</pre></td></tr></table></figure><p><strong>四种核心数据类型速览</strong>（第 2 章会详细展开）：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">类型</th>\n<th style=\"text-align:left\">特征</th>\n<th style=\"text-align:left\">典型例子</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Counter</strong></td>\n<td style=\"text-align:left\">只增不减（除非重置）的累计值</td>\n<td style=\"text-align:left\"><code>http_requests_total</code> 、 <code>node_cpu_seconds_total</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Gauge</strong></td>\n<td style=\"text-align:left\">可增可减的瞬时值</td>\n<td style=\"text-align:left\"><code>node_load1</code> 、 <code>node_memory_MemAvailable_bytes</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Histogram</strong></td>\n<td style=\"text-align:left\">按桶（bucket）统计分布，可算分位数</td>\n<td style=\"text-align:left\"><code>http_request_duration_seconds_bucket</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Summary</strong></td>\n<td style=\"text-align:left\">客户端直接计算分位数</td>\n<td style=\"text-align:left\"><code>rpc_duration_seconds&#123;quantile=&quot;0.99&quot;&#125;</code></td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"1115-job任务与-instance实例\"><a class=\"anchor\" href=\"#1115-job任务与-instance实例\">#</a> 1.11.5　Job（任务）与 Instance（实例）</h3>\n<p>这两个词在配置文件、PromQL、Grafana 面板里到处出现，必须分清。</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">概念</th>\n<th style=\"text-align:left\">定义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Instance（实例）</strong></td>\n<td style=\"text-align:left\">一个单独的 scrape 目标，通常写作  <code>IP:PORT</code> ，<strong>对应单个应用的进程</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Job（任务）</strong></td>\n<td style=\"text-align:left\"><strong>一组同种类型的 instances 集合</strong>，主要用于保证可扩展性与可靠性</td>\n</tr>\n</tbody>\n</table>\n<p><strong>官方式的例子</strong>：一个 API 服务 job 包含四个 instances：</p>\n<pre><code>job: api-server\n├── instance 1: 1.2.3.4:5670\n├── instance 2: 1.2.3.4:5671\n├── instance 3: 5.6.7.8:5670\n└── instance 4: 5.6.7.8:5671\n</code></pre>\n<blockquote>\n<p>🧠 <strong>类比</strong>： <code>job</code>  是 &quot;<strong> 一个部门的岗位名称</strong> &quot;， <code>instance</code>  是 &quot;<strong> 这个岗位上具体的人</strong> &quot;。一个岗位可以有多个人轮值（多副本），这就是可扩展性；某个人请假了别人还在（副本冗余），这就是可靠性。</p>\n</blockquote>\n<p><strong>自动生成的内置指标</strong>：Prometheus 在每次抓取后，会为目标自动生成一组带  <code>job</code>  和  <code>instance</code>  标签的元指标。这些指标<strong>不需要你在目标上暴露</strong>，是 &quot;白送&quot; 的运维利器：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">指标</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">典型用途</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>up&#123;job,instance&#125;</code></td>\n<td style=\"text-align:left\">目标是否健康：<strong>1 正常，0 不正常</strong></td>\n<td style=\"text-align:left\"><strong>最常用的存活告警</strong>： <code>up == 0</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>scrape_duration_seconds&#123;job,instance&#125;</code></td>\n<td style=\"text-align:left\">本次抓取耗时</td>\n<td style=\"text-align:left\">发现抓取缓慢的目标</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>scrape_samples_scraped&#123;job,instance&#125;</code></td>\n<td style=\"text-align:left\">本次抓取到的<strong>样本数量</strong></td>\n<td style=\"text-align:left\">监控指标量是否异常膨胀</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>scrape_samples_post_metric_relabeling&#123;job,instance&#125;</code></td>\n<td style=\"text-align:left\">relabel 之后剩余的样本数</td>\n<td style=\"text-align:left\">验证 relabel 规则效果</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>scrape_series_added&#123;job,instance&#125;</code></td>\n<td style=\"text-align:left\">本次抓取<strong>新增</strong>的序列数（约数）</td>\n<td style=\"text-align:left\"><strong>发现序列爆炸的早期信号</strong></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>💡 <strong>实战价值</strong>： <code>scrape_series_added</code>  突然飙升，往往意味着某个应用偷偷加了高基数标签，或者发生了一次重启导致新序列涌入。提前发现，能救你一命。</p>\n</blockquote>\n<h3 id=\"1116-本节小结\"><a class=\"anchor\" href=\"#1116-本节小结\">#</a> 1.11.6　本节小结</h3>\n<pre><code>数据模型：metric 名称 + 标签（= 唯一时间序列）\n数据类型：Counter / Gauge / Histogram / Summary（+ untyped）\n组织结构：多个 instances 组成一个 job\n命名规则：名称 [a-zA-Z_:][a-zA-Z0-9_:]* ｜ 标签 [a-zA-Z_][a-zA-Z0-9_]*\n</code></pre>\n<hr />\n<h2 id=\"112-prometheus-数据处理四部曲\"><a class=\"anchor\" href=\"#112-prometheus-数据处理四部曲\">#</a> 1.12　Prometheus 数据处理四部曲</h2>\n<h3 id=\"1121-数据获取一切基于-http\"><a class=\"anchor\" href=\"#1121-数据获取一切基于-http\">#</a> 1.12.1　数据获取：一切基于 HTTP</h3>\n<p>Prometheus 采集指标数据的方式，本质上是 <strong>HTTP Call</strong>：从目标配置文件中指定的网络端点（endpoint，即  <code>IP:Port</code> ，代表一个应用）上<strong>周期性</strong>获取指标。一个端点上通常不止一个指标，而是成百上千个。</p>\n<p>这里有一个<strong>根本性约束，必须理解</strong>：</p>\n<blockquote>\n<p><strong>Prometheus 的所有指标都必须以 HTTP 方式暴露出来。</strong></p>\n<p>因此 Prometheus <strong>无法直接获取内核数据、硬件数据</strong> —— 它只能通过其它机制间接获得（例如  <code>node_exporter</code>  读取  <code>/proc</code>  后再转换为 HTTP 端点暴露）。</p>\n</blockquote>\n<p>这就是为什么 &quot;安装一个 exporter&quot; 几乎是所有监控任务的起点。</p>\n<h3 id=\"1122-数据存储本地-tsdb-的分层结构\"><a class=\"anchor\" href=\"#1122-数据存储本地-tsdb-的分层结构\">#</a> 1.12.2　数据存储：本地 TSDB 的分层结构</h3>\n<p>Prometheus 采用<strong>自定义格式</strong>将时间序列存储在<strong>本地磁盘</strong>上，结构相当精妙：</p>\n<ul>\n<li>本地 TSDB 以<strong>每 2 小时为间隔</strong>切分为一个 <strong>Block</strong>；</li>\n<li>每个 Block 内部又分为多个 <strong>Chunk 文件</strong>；</li>\n<li><strong>Chunk 是存储的基本单位</strong>，用来存放采集到的时序数据（包括元数据 metadata）；</li>\n<li><strong>index 索引文件</strong>：对 metrics（对应一次 KV 采集数据）和 labels（标签）建立索引后存储在 Block 中。</li>\n</ul>\n<p><strong>写入路径与 WAL 保护机制</strong>：</p>\n<blockquote>\n<p>Prometheus 平时把采集到的数据<strong>先都放在内存</strong>里，以类似缓存的方式加快搜索和访问；<br />\n同时通过 <strong>WAL（Write-Ahead Logging，预写日志）</strong> 把数据落盘到  <code>wal</code>  目录；<br />\n当进程崩溃或宕机重启时，<strong>依靠 WAL 恢复数据并重新加载到内存</strong>。</p>\n</blockquote>\n<p><strong>真实的  <code>data</code>  目录长这样</strong>：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>/usr/local/prometheus/data</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>├── 01G9RSD61ZEF16T5YGE91K49MZ/    ← 一个 Block（约 2 小时的数据）</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>│   ├── chunks/                    ← 压缩后的样本数据</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>│   │   └── 000001</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>│   ├── index                      ← 标签与序列的索引</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>│   ├── meta.json                  ← 该 Block 的元信息（时间范围、样本数等）</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>│   └── tombstones                 ← 删除标记（软删除）</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>├── 01G9RZ8VXF2FHHB18CW0594P8T/</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>│   ├── chunks/000001</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>│   ├── index</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>│   ├── meta.json</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>│   └── tombstones</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>├── chunks_head/                   ← ┐</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>│   ├── 000002                     │  当前正在写入的\"头部块\"</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>│   └── 000003                     ← ┘</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>├── lock                           ← 进程锁，防止多实例共用目录</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>├── queries.active                 ← 正在执行的查询</pre></td></tr><tr><td data-num=\"18\"></td><td><pre>└── wal/                           ← 预写日志，宕机恢复用</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    ├── 00000000</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    ├── 00000001</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    └── 00000002</pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>生产提醒</strong>：</p>\n<ul>\n<li>数据目录<strong>不要放在共享存储上</strong>（NFS 会破坏  <code>lock</code>  与 WAL 语义）；</li>\n<li><strong>不要用  <code>rm</code>  直接删 Block 目录</strong>，用官方 API 或配置保留策略；</li>\n<li>磁盘最好是 <strong>SSD</strong>，TSDB 对随机 IO 敏感。</li>\n</ul>\n</blockquote>\n<h3 id=\"1123-数据分析promql\"><a class=\"anchor\" href=\"#1123-数据分析promql\">#</a> 1.12.3　数据分析：PromQL</h3>\n<p>Prometheus 提供了专门的查询语言 <strong>PromQL（Prometheus Query Language）</strong>，支持实时查询与聚合运算，是图表展示与告警规则的共同基础。</p>\n<p><strong>PromQL 处理两种核心向量：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">向量类型</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">直观理解</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>即时向量（Instant Vector）</strong></td>\n<td style=\"text-align:left\">最近一次抓取的<strong>单个时间戳</strong>上的一组数据</td>\n<td style=\"text-align:left\"><strong>一个时间点</strong>的数据</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>范围向量（Range Vector）</strong></td>\n<td style=\"text-align:left\">指定时间范围内的<strong>所有时间戳</strong>上的数据</td>\n<td style=\"text-align:left\"><strong>一个时间段</strong>的数据</td>\n</tr>\n</tbody>\n</table>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 即时向量：此刻的 CPU 空闲时间总量</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"idle\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 范围向量：过去 5 分钟的所有采样点（注意 [5m]）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"idle\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span></pre></td></tr></table></figure><blockquote>\n<p>两者最直观的区别：<strong>范围向量不能直接画成折线图</strong>，必须先经过  <code>rate()</code> 、 <code>avg_over_time()</code>  这类函数 &quot;降维&quot; 成即时向量才行。这是新手最常踩的坑之一。</p>\n</blockquote>\n<p>PromQL 同时内置了大量处理函数（数学运算、聚合、时间函数、 <code>rate</code> / <code>increase</code> 、 <code>histogram_quantile</code>  等），第 5～6 章会逐一展开。</p>\n<h3 id=\"1124-数据告警职责分离的设计\"><a class=\"anchor\" href=\"#1124-数据告警职责分离的设计\">#</a> 1.12.4　数据告警：职责分离的设计</h3>\n<p>Prometheus 的告警是一条<strong>明确分权</strong>的链路：</p>\n<pre><code>Prometheus Server                     Alertmanager\n─────────────────                     ─────────────\n按告警规则周期性计算   ──告警指示──►   去重 → 分组 → 抑制 → 路由\n（只负责&quot;发现问题&quot;）                  （只负责&quot;通知谁&quot;）\n</code></pre>\n<ul>\n<li><strong>告警指示</strong>由 Prometheus Server 基于用户提供的  <code>alerting rules</code>  <strong>周期性计算生成</strong>；</li>\n<li><strong>Alertmanager</strong> 接收到告警指示后，基于用户定义的<strong>告警路由（route）</strong>，向告警接收人发送告警信息。</li>\n</ul>\n<blockquote>\n<p>💡 <strong>为什么这样设计？</strong> 因为 &quot;判断异常&quot; 和 &quot;决定通知&quot; 是两件完全不同的事。前者是<strong>时序计算</strong>（Prometheus 擅长），后者是<strong>消息治理</strong>（去重、静默、值班表、升级策略 ——Alertmanager 擅长）。拆开之后，两边都能做得更好，也让 Prometheus 保持了 &quot;单一职责&quot;。</p>\n</blockquote>\n<hr />\n<h2 id=\"113-本章小结\"><a class=\"anchor\" href=\"#113-本章小结\">#</a> 1.13　本章小结</h2>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>mindmap</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  root<span class=\"token text string\">((\"Prometheus&lt;br/>入门\"))</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    可观测性</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>      指标 Metrics</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>      日志 Logging</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      追踪 Tracing</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    六大环节</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>      数据来源</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>      数据采集</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>      数据存储 TSDB</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      数据处理</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>      数据展示</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>      数据告警</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    监控方法</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>      四个黄金指标</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>      延迟 流量 错误 饱和度</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    存储</pre></td></tr><tr><td data-num=\"18\"></td><td><pre>      时序数据五特点</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>      压缩 90%</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>      百万级写入</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    架构</pre></td></tr><tr><td data-num=\"22\"></td><td><pre>      Server 核心</pre></td></tr><tr><td data-num=\"23\"></td><td><pre>      Exporters</pre></td></tr><tr><td data-num=\"24\"></td><td><pre>      Pushgateway</pre></td></tr><tr><td data-num=\"25\"></td><td><pre>      Alertmanager</pre></td></tr><tr><td data-num=\"26\"></td><td><pre>      Grafana</pre></td></tr><tr><td data-num=\"27\"></td><td><pre>      Service Discovery</pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    Pull 模型</pre></td></tr><tr><td data-num=\"29\"></td><td><pre>      只拉不推</pre></td></tr><tr><td data-num=\"30\"></td><td><pre>      集中控制</pre></td></tr><tr><td data-num=\"31\"></td><td><pre>      up 免费探活</pre></td></tr><tr><td data-num=\"32\"></td><td><pre>    数据模型</pre></td></tr><tr><td data-num=\"33\"></td><td><pre>      metric 名 + 标签</pre></td></tr><tr><td data-num=\"34\"></td><td><pre>      四种类型</pre></td></tr><tr><td data-num=\"35\"></td><td><pre>      job / instance</pre></td></tr></table></figure><p><strong>必须带走的一句话</strong>：</p>\n<blockquote>\n<p>Prometheus 是一套 &quot;<strong> 以 Pull 方式采集、用多维标签建模、把数据存进内置 TSDB、靠 PromQL 分析、由 Grafana 展示、交给 Alertmanager 告警</strong> &quot; 的监控组件集合。<br />\n它只做 &quot;指标&quot; 这一支柱，也只做 &quot;采集 + 存储 + 查询&quot; 这三件事 ——<strong> 其它都得靠生态补齐</strong>，而这恰恰是它最强大的地方。</p>\n</blockquote>\n<hr />\n<h2 id=\"114-面试高频问答\"><a class=\"anchor\" href=\"#114-面试高频问答\">#</a> 1.14　面试高频问答</h2>\n<p><strong>Q1：你们公司为什么同时用 Zabbix 和 Prometheus？</strong></p>\n<blockquote>\n<p>因为两者定位不同。Zabbix 擅长传统固定资产和网络设备监控（SNMP/IPMI 生态完善、开箱即用），Prometheus 擅长容器化、动态变化的微服务环境（服务发现 + 多维标签）。老业务用 Zabbix，容器平台用 Prometheus，是很常见的组合。</p>\n</blockquote>\n<p><strong>Q2：Prometheus 的采集模型是什么？和 Zabbix 有什么不同？</strong></p>\n<blockquote>\n<p>Prometheus <strong>只支持 Pull</strong>，相当于 Zabbix 的被动模式；Zabbix <strong>推拉都支持</strong>（默认被动，可改主动）。InfluxDB 则是 Push。<br />\nPull 的好处是配置集中在 Server 端、 <code>up</code>  指标免费探活、调试方便、天然配合服务发现。</p>\n</blockquote>\n<p><strong>Q3：Prometheus 为什么性能好？</strong></p>\n<blockquote>\n<p>核心是存储：它用的是自研 TSDB（时序数据库），针对 &quot;写多改少、删除成段、读有序&quot; 的特点做了分块存储和专用压缩，单点平均 1~2 字节，可节省约 90% 空间，支持百万级写入 / 秒、亿级聚合秒级返回；而 Zabbix 用通用关系库，不是为监控场景优化的。</p>\n</blockquote>\n<p><strong>Q4：什么是时间序列？唯一标识是什么？</strong></p>\n<blockquote>\n<p>时间序列是按时间顺序记录的、同一度量维度的数据流。唯一标识是 <strong>metric 名称 + 一组标签</strong>。任何一个标签值变化（新增或删除标签），都会产生一条新的时间序列。</p>\n</blockquote>\n<p><strong>Q5：Prometheus 有哪些不足？怎么弥补？</strong></p>\n<blockquote>\n<p>① 不支持集群（用双机 + 联邦，或 Thanos/VictoriaMetrics）；② 规模过大有瓶颈（分片、联邦、远程存储）；③ 中文支持差（Grafana 面板中文化）；④ 功能不完整（配 Grafana + Alertmanager）。</p>\n</blockquote>\n<p><strong>Q6： <code>up</code>  指标是干什么的？</strong></p>\n<blockquote>\n<p>Prometheus 每次抓取后自动生成的元指标， <code>1</code>  表示目标健康、 <code>0</code>  表示抓取失败。最经典的存活告警就是  <code>up == 0</code> 。</p>\n</blockquote>\n<hr />\n<h2 id=\"115-动手练习\"><a class=\"anchor\" href=\"#115-动手练习\">#</a> 1.15　动手练习</h2>\n<h3 id=\"练习-1观察题-亲手看一眼-metrics\"><a class=\"anchor\" href=\"#练习-1观察题-亲手看一眼-metrics\">#</a> 练习 1（观察题）　亲手看一眼 /metrics</h3>\n<p>准备一台 Linux 机器（或虚拟机），下载  <code>node_exporter</code>  并运行，然后：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 终端 1：启动 exporter（默认端口 9100）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>./node_exporter</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 终端 2：查看原始指标输出</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://localhost:9100/metrics <span class=\"token operator\">|</span> <span class=\"token function\">head</span> <span class=\"token parameter variable\">-50</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 找出所有 HELP/TYPE 声明</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://localhost:9100/metrics <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token parameter variable\">-E</span> <span class=\"token string\">'^# (HELP|TYPE)'</span> <span class=\"token operator\">|</span> <span class=\"token function\">head</span> <span class=\"token parameter variable\">-20</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 找出内存相关指标</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://localhost:9100/metrics <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> node_memory_Mem</pre></td></tr></table></figure><p><strong>要回答的问题</strong>：</p>\n<ol>\n<li><code>node_memory_MemTotal_bytes</code>  是什么类型？（Counter 还是 Gauge？为什么？）</li>\n<li><code>node_cpu_seconds_total</code>  是 Counter，那你怎么算出 &quot;当前 CPU 使用率&quot;？只用一次抓取的值能算出来吗？</li>\n<li>用本章的内存公式，算出你这台机器当前的内存使用率。</li>\n</ol>\n<h3 id=\"练习-2思考题-pull-还是-push\"><a class=\"anchor\" href=\"#练习-2思考题-pull-还是-push\">#</a> 练习 2（思考题）　Pull 还是 Push？</h3>\n<p>以下场景分别该用哪种方式？</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">场景</th>\n<th style=\"text-align:left\">你的答案</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">Nginx 反向代理（长期运行）</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">每天凌晨跑 30 秒的备份脚本，要记录耗时与退出码</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">你自己用 Go 写的 API 服务</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">机房核心交换机</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>参考答案：① Exporter（ <code>nginx_exporter</code> ）；② Pushgateway；③ Instrumentation（客户端库埋点）；④ Exporter（ <code>snmp_exporter</code> ）。</p>\n</blockquote>\n<h3 id=\"练习-3设计题-用四个黄金指标设计监控清单\"><a class=\"anchor\" href=\"#练习-3设计题-用四个黄金指标设计监控清单\">#</a> 练习 3（设计题）　用四个黄金指标设计监控清单</h3>\n<p>假设你要监控一个 &quot;用户登录&quot; 接口，请用<strong>延迟 / 流量 / 错误 / 饱和度</strong>四个维度，各写出至少 2 个具体监控项。</p>\n<blockquote>\n<p>提示：延迟要区分成功与失败；流量可用 QPS；错误可用 HTTP 5xx 率；饱和度可看该服务所依赖的数据库连接池使用率。</p>\n</blockquote>\n<h3 id=\"练习-4原理题-为什么-free-小不是问题\"><a class=\"anchor\" href=\"#练习-4原理题-为什么-free-小不是问题\">#</a> 练习 4（原理题）　为什么  <code>free</code>  小不是问题？</h3>\n<p>在一台机器上执行  <code>free -h</code> ，观察  <code>free</code>  与  <code>available</code>  两列的差异，并解释：</p>\n<ol>\n<li>为什么两者差距可能很大？</li>\n<li>如果  <code>swap</code>  开始被大量使用，说明什么？</li>\n<li>用公式算出使用率，并说出对应的告警阈值。</li>\n</ol>\n<hr />\n<h2 id=\"116-下章预告\"><a class=\"anchor\" href=\"#116-下章预告\">#</a> 1.16　下章预告</h2>\n<p>本章我们把 Prometheus&quot;是什么、为什么、由什么组成&quot; 讲透了。下一章将正式动手：</p>\n<ul>\n<li>下载与部署 Prometheus Server</li>\n<li>读懂  <code>prometheus.yml</code>  的每一个字段</li>\n<li>配置第一个静态 Target</li>\n<li>在 Web UI 里写出你的第一条 PromQL</li>\n<li>认识 Counter / Gauge / Histogram / Summary 的本质差异</li>\n</ul>\n<p><strong>先把本章的架构图画三遍</strong> —— 后面所有命令和配置，都是在给这张图 &quot;接线&quot;。</p>\n",
            "tags": [
                "Prometheus"
            ]
        },
        {
            "id": "http://blog.jaxxwang.cn/posts/1096553236.html",
            "url": "http://blog.jaxxwang.cn/posts/1096553236.html",
            "title": "03 PromQL：把指标变成答案",
            "date_published": "2026-10-23T16:00:00.000Z",
            "content_html": "<h1 id=\"第-3-章-promql把指标变成答案\"><a class=\"anchor\" href=\"#第-3-章-promql把指标变成答案\">#</a> 第 3 章　PromQL：把指标变成答案</h1>\n<blockquote>\n<p><strong>本章导读</strong></p>\n<p>第 2 章结束时，你已经能在 Grafana 上看到四台主机的 CPU 曲线了。但那张图是<strong>别人写好模板给你的</strong> —— 你并不知道里面那句表达式在算什么。</p>\n<p>本章解决的就是这个问题。学完本章，你应当能够<strong>看着一条指标名，就知道该怎么查、能不能直接画、要不要套函数</strong>。</p>\n<p>这是全课程技术含量最高的一章，也是最容易 &quot;看懂但写不出&quot; 的一章。建议边读边在 9090 的 Graph 页面里敲 ——<strong>PromQL 是肌肉记忆，不是阅读理解。</strong></p>\n</blockquote>\n<p><strong>学习目标</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">序号</th>\n<th style=\"text-align:left\">学完本章，你应当能够</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1</td>\n<td style=\"text-align:left\">说清 Sample、Time Series、Instant Vector、Range Vector、Scalar 的关系</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">2</td>\n<td style=\"text-align:left\">熟练使用四种匹配器与  <code>offset</code> ，写出精准的过滤条件</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">3</td>\n<td style=\"text-align:left\">判断一个指标属于 Counter / Gauge / Histogram / Summary，并决定该不该套函数</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">4</td>\n<td style=\"text-align:left\">用算术、比较、 <code>bool</code>  修饰符写出 &quot;内存使用率&quot;&quot; 磁盘使用率 &quot; 这类业务指标</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">5</td>\n<td style=\"text-align:left\">用  <code>by</code>  /  <code>without</code>  完成分组统计，正确计算 &quot;占比&quot; 类指标</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">6</td>\n<td style=\"text-align:left\">准确区分  <code>increase</code>  /  <code>rate</code>  /  <code>irate</code>  /  <code>delta</code>  /  <code>idelta</code> ，并说明各自适用场景</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">7</td>\n<td style=\"text-align:left\">理解  <code>ignoring</code>  /  <code>on</code>  /  <code>group_left</code>  /  <code>group_right</code>  解决什么问题</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">8</td>\n<td style=\"text-align:left\">排查 &quot;表达式没结果&quot; 和 &quot;vector cannot contain metrics with the same labelset&quot; 两类高频报错</td>\n</tr>\n</tbody>\n</table>\n<hr />\n<h2 id=\"31-先把地基夯死时间序列与样本\"><a class=\"anchor\" href=\"#31-先把地基夯死时间序列与样本\">#</a> 3.1　先把地基夯死：时间序列与样本</h2>\n<h3 id=\"311-时间序列time-series\"><a class=\"anchor\" href=\"#311-时间序列time-series\">#</a> 3.1.1　时间序列（Time Series）</h3>\n<p>Prometheus 采用<strong>时间序列</strong>存储监控数据。</p>\n<blockquote>\n<p><strong>时间序列</strong>：按照时间顺序记录系统、设备或应用状态变化的数据集合。</p>\n</blockquote>\n<p>数据按固定采集周期（如 15s、30s）不断采集，随着时间推移形成一串离散的数据点 —— 这就是时间序列。</p>\n<p>放到坐标系里就非常直观：<strong>X 轴是时间，Y 轴是数值</strong>，把点连起来就是我们看到的监控曲线。Grafana 里那一条条折线，本质就是若干个时间序列。</p>\n<h3 id=\"312-样本sample\"><a class=\"anchor\" href=\"#312-样本sample\">#</a> 3.1.2　样本（Sample）</h3>\n<p>每采集一次，就产生<strong>一个样本</strong>。一个 Sample 由两部分组成：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">组成</th>\n<th style=\"text-align:left\">内容</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>key</strong></td>\n<td style=\"text-align:left\">Metric 名称 + Label 集合 + <strong>Timestamp</strong>（毫秒精度）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>value</strong></td>\n<td style=\"text-align:left\"><strong>float64</strong> 格式的数值</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>📌 <strong>记住这个 &quot;没有例外&quot; 的事实</strong>：Prometheus 的样本值<strong>只能是 float64</strong>。<br />\n没有字符串、没有布尔、没有整型。你看到的  <code>1</code> 、 <code>0</code> 、 <code>200</code> ，全是浮点数的字面表现。</p>\n</blockquote>\n<h3 id=\"313-唯一标识与五条铁律\"><a class=\"anchor\" href=\"#313-唯一标识与五条铁律\">#</a> 3.1.3　唯一标识与五条铁律</h3>\n<p><strong>时间序列的唯一标识 = Metric Name + Label Set。</strong></p>\n<p>围绕这句话，有五条推论必须记牢：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">#</th>\n<th style=\"text-align:left\">铁律</th>\n<th style=\"text-align:left\">后果</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1</td>\n<td style=\"text-align:left\">指标名 + 标签的<strong>特定组合</strong>代表一条时间序列</td>\n<td style=\"text-align:left\">查询时永远在 &quot;选序列&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">2</td>\n<td style=\"text-align:left\"><strong>不同指标名</strong>代表不同时间序列</td>\n<td style=\"text-align:left\">名字就是身份</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">3</td>\n<td style=\"text-align:left\"><strong>指标名相同、标签不同</strong>，是不同时间序列</td>\n<td style=\"text-align:left\"><code>method=&quot;GET&quot;</code>  与  <code>method=&quot;POST&quot;</code>  是两条</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">4</td>\n<td style=\"text-align:left\"><strong>更改任何标签值</strong>（含增删标签）都会创建<strong>新序列</strong></td>\n<td style=\"text-align:left\">标签一改，历史数据就 &quot;接不上&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">5</td>\n<td style=\"text-align:left\">应尽量保持标签<strong>稳定</strong></td>\n<td style=\"text-align:left\">标签乱变 → 序列爆炸 → 图形 / 告警 / 记录规则全部失效</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ 第 4、5 条是<strong>生产事故级别</strong>的认知。第 4 章讲标签管理时，你会亲眼看到 &quot;改了一个标签，图上出现断层&quot; 的现象 —— 那正是这条铁律在起作用。</p>\n</blockquote>\n<h3 id=\"314-指标的两种书写形式\"><a class=\"anchor\" href=\"#314-指标的两种书写形式\">#</a> 3.1.4　指标的两种书写形式</h3>\n<pre><code>http_requests_total&#123;method=&quot;GET&quot;, code=&quot;200&quot;&#125;          # 常规写法\n&#123;__name__=&quot;http_requests_total&quot;, method=&quot;GET&quot;&#125;         # 等价写法\n</code></pre>\n<p>第二种写法里出现了  <code>__name__</code> —— 这就是第 1 章提过的<strong>内部保留标签</strong>，它存的正是指标名本身。</p>\n<blockquote>\n<p>💡 <strong>为什么要知道  <code>__name__</code> ？</strong> 因为它让你可以<strong>用正则批量选择指标名</strong>：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">__name__</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"prometheus_http_.*\"</span><span class=\"token punctuation\">&#125;</span></span>     # 所有以 prometheus_http_ 开头的指标</pre></td></tr></table></figure><p>而在  <code>metric_relabel_configs</code>  里 &quot;按指标名前缀批量丢弃&quot; 时，用的也正是它。</p>\n</blockquote>\n<hr />\n<h2 id=\"32-四种表达式类型promql-的类型系统\"><a class=\"anchor\" href=\"#32-四种表达式类型promql-的类型系统\">#</a> 3.2　四种表达式类型：PromQL 的 &quot;类型系统&quot;</h2>\n<h3 id=\"321-什么是-promql\"><a class=\"anchor\" href=\"#321-什么是-promql\">#</a> 3.2.1　什么是 PromQL</h3>\n<p>官方文档：<a href=\"https://prometheus.io/docs/prometheus/latest/querying/basics/\">https://prometheus.io/docs/prometheus/latest/querying/basics/</a></p>\n<blockquote>\n<p>PromQL（Prometheus Query Language）是 Prometheus 内置的<strong>函数式表达式语言</strong>，用于实时查找和聚合时间序列数据。</p>\n</blockquote>\n<p>它的结果有三个去处：</p>\n<ol>\n<li><strong>图表展示</strong>（Grafana / 内置 Graph）；</li>\n<li><strong>表格展示</strong>（表达式浏览器）；</li>\n<li><strong>HTTP API</strong> 提供给外部系统（告警、自动化平台、自研大屏）。</li>\n</ol>\n<blockquote>\n<p>📌 <strong>默认时间基准</strong>：不指定时间时，<strong>以 &quot;当前时间&quot; 为基准点</strong>取数。</p>\n</blockquote>\n<h3 id=\"322-四种结果类型\"><a class=\"anchor\" href=\"#322-四种结果类型\">#</a> 3.2.2　四种结果类型</h3>\n<p>任何一个 PromQL 表达式（或子表达式），计算结果必为以下四种之一：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">类型</th>\n<th style=\"text-align:left\">中文</th>\n<th style=\"text-align:left\">定义</th>\n<th style=\"text-align:left\">直观理解</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>instant vector</strong></td>\n<td style=\"text-align:left\">即时向量</td>\n<td style=\"text-align:left\">一组时间序列，每条序列各含<strong>一个</strong>样本，<strong>共享同一时间戳</strong></td>\n<td style=\"text-align:left\"><strong>一个时间点</strong>上的一组数</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>range vector</strong></td>\n<td style=\"text-align:left\">范围向量</td>\n<td style=\"text-align:left\">一组时间序列，每条序列含<strong>一串</strong>随时间变化的样本</td>\n<td style=\"text-align:left\"><strong>一个时间段</strong>内的一组数</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>scalar</strong></td>\n<td style=\"text-align:left\">标量</td>\n<td style=\"text-align:left\">一个简单的浮点数值</td>\n<td style=\"text-align:left\">一个 &quot;裸数字&quot;，如  <code>1024</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>string</strong></td>\n<td style=\"text-align:left\">字符串</td>\n<td style=\"text-align:left\">一个简单字符串</td>\n<td style=\"text-align:left\">目前基本用不到</td>\n</tr>\n</tbody>\n</table>\n<pre><code>instant vector  →  node_load1\n                   ↑ 4 台机器 = 4 条序列，每条 1 个值\n\nrange vector    →  node_load1[5m]\n                   ↑ 4 台机器 = 4 条序列，每条 20 个值（15s×20=5m）\n\nscalar          →  1024\nstring          →  &quot;hello&quot;\n</code></pre>\n<h3 id=\"323-最实用的规则什么场景要什么类型\"><a class=\"anchor\" href=\"#323-最实用的规则什么场景要什么类型\">#</a> 3.2.3　⭐ 最实用的规则：什么场景要什么类型</h3>\n<p>这是新手最容易栽跟头的地方。三类约束必须背下来：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">场景</th>\n<th style=\"text-align:left\">要求的类型</th>\n<th style=\"text-align:left\">违反后的报错</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>画折线图</strong></td>\n<td style=\"text-align:left\"><strong>只能是 instant vector</strong></td>\n<td style=\"text-align:left\">图表画不出来</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>用  <code>rate</code>  /  <code>increase</code>  /  <code>irate</code>  等速率函数</strong></td>\n<td style=\"text-align:left\"><strong>必须是 range vector</strong></td>\n<td style=\"text-align:left\">报  <code>expected type range vector</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>在表达式浏览器里直接查 range vector</strong></td>\n<td style=\"text-align:left\">❌ <strong>不允许</strong></td>\n<td style=\"text-align:left\"><code>invalid expression type &quot;range vector&quot; for range query, must be Scalar or instant Vector</code></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>🧠 <strong>一句话总结</strong>：<br />\n<strong>范围向量永远不能 &quot;出门&quot;，它只能在函数括号里活着。</strong></p>\n<p>所以要画图， <code>node_load1[5m]</code>  必须<strong>降维</strong>：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">avg_over_time</span><span class=\"token punctuation\">(</span>node_load1<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span>     # range → instant，可以画了</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span>     # range → instant，可以画了</pre></td></tr></table></figure></blockquote>\n<h3 id=\"324-用-api-直接查数据\"><a class=\"anchor\" href=\"#324-用-api-直接查数据\">#</a> 3.2.4　用 API 直接查数据</h3>\n<p>PromQL 不只能在界面里敲，它本质是一个 HTTP API。</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ① 即时查询：当前请求数</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-G</span> http://192.168.80.101:9090/api/v1/query <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  --data-urlencode <span class=\"token string\">'query=prometheus_http_requests_total'</span> <span class=\"token operator\">|</span> jq</pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ② 指定时间点查询</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-G</span> http://192.168.80.101:9090/api/v1/query <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  --data-urlencode <span class=\"token string\">'query=prometheus_http_requests_total'</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  --data-urlencode <span class=\"token string\">\"time=<span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">date</span> +%s<span class=\"token variable\">)</span></span>\"</span> <span class=\"token operator\">|</span> jq</pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># ③ 带标签过滤（正则）</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-G</span> http://192.168.80.101:9090/api/v1/query <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  --data-urlencode <span class=\"token string\">'query=node_memory_MemFree_bytes&#123;instance=~\"192.168.80.(101|102):9100\"&#125;'</span> <span class=\"token operator\">|</span> jq</pre></td></tr><tr><td data-num=\"13\"></td><td><pre></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token comment\"># ④ 范围查询：必须给 start /end/step</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-G</span> http://192.168.80.101:9090/api/v1/query_range <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>  --data-urlencode <span class=\"token string\">'query=rate(node_cpu_seconds_total&#123;mode!=\"idle\"&#125;[5m])'</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  --data-urlencode <span class=\"token string\">\"start=<span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">date</span> <span class=\"token parameter variable\">-d</span> <span class=\"token string\">'-1 hour'</span> +%s<span class=\"token variable\">)</span></span>\"</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  --data-urlencode <span class=\"token string\">\"end=<span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">date</span> +%s<span class=\"token variable\">)</span></span>\"</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>  --data-urlencode <span class=\"token string\">'step=15'</span> <span class=\"token operator\">|</span> jq</pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>这套 API 的实际价值</strong>：所有 &quot;把监控数据接到自研平台&quot; 的需求，本质都是调  <code>/api/v1/query_range</code> 。学会它，你就能把 Prometheus 变成任何系统的数据源。</p>\n</blockquote>\n<h3 id=\"325-字面量数字与字符串\"><a class=\"anchor\" href=\"#325-字面量数字与字符串\">#</a> 3.2.5　字面量：数字与字符串</h3>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 数字：[-] digits [.digits]</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token number\">2</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token number\">2.43</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token number\">-2.43</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 字符串：单引号 / 双引号 / 反引号</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>\"this is a string\"</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>'these are unescaped: \\n \\t'</pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">`</span>these are not unescaped: \\n ' \" \\t<span class=\"token punctuation\">`</span></pre></td></tr></table></figure><p>反引号的作用：<strong>不做转义</strong>。写正则时特别有用（正则里的  <code>\\d</code> 、 <code>\\d+</code>  用双引号写会被当作转义符处理）。</p>\n<hr />\n<h2 id=\"33-数据选择器从百万序列里挑出你要的\"><a class=\"anchor\" href=\"#33-数据选择器从百万序列里挑出你要的\">#</a> 3.3　数据选择器：从百万序列里挑出你要的</h2>\n<h3 id=\"331-统一语法\"><a class=\"anchor\" href=\"#331-统一语法\">#</a> 3.3.1　统一语法</h3>\n<pre><code>metrics_name&#123;筛选label=值,...&#125;[&lt;时间范围&gt;] offset &lt;偏移&gt;\n</code></pre>\n<p>一条表达式的三个可选部件：<strong>指标名</strong> → <strong>标签匹配器</strong> → <strong>时间修饰</strong>。</p>\n<h3 id=\"332-即时向量选择器instant-vector-selector\"><a class=\"anchor\" href=\"#332-即时向量选择器instant-vector-selector\">#</a> 3.3.2　即时向量选择器（Instant Vector Selector）</h3>\n<p><strong>获取 0 个、1 个或多个时间序列的即时样本值。</strong></p>\n<p>由两部分组成，<strong>至少要给出一个</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">部分</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">是否可省</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>指标名称</strong></td>\n<td style=\"text-align:left\">限定是哪个指标</td>\n<td style=\"text-align:left\">可省</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>匹配器（Matcher）</strong></td>\n<td style=\"text-align:left\">定义在  <code>&#123;&#125;</code>  内，过滤标签</td>\n<td style=\"text-align:left\">可省</td>\n</tr>\n</tbody>\n</table>\n<h4 id=\"用法一只给指标名\"><a class=\"anchor\" href=\"#用法一只给指标名\">#</a> 用法一：只给指标名</h4>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>node_filefd_allocated</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>prometheus_http_requests_total</pre></td></tr></table></figure><blockquote>\n<p>💡  <code>http_requests_total</code>  与  <code>http_requests_total&#123;&#125;</code>  <strong>完全等价</strong>。空花括号不改变语义。</p>\n</blockquote>\n<h4 id=\"用法二用-__name__-匹配多个指标名\"><a class=\"anchor\" href=\"#用法二用-__name__-匹配多个指标名\">#</a> 用法二：用  <code>__name__</code>  匹配多个指标名</h4>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">__name__</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus_http_requests_total\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">__name__</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"^prometheus_http_.*\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><h4 id=\"用法三只给匹配器\"><a class=\"anchor\" href=\"#用法三只给匹配器\">#</a> 用法三：只给匹配器</h4>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"node_exporter\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ 这种写法会返回<strong>所有</strong>带该标签的指标 —— 可能横跨很多不同指标名，结果集极大。<strong>慎用。</strong></p>\n</blockquote>\n<h4 id=\"用法四指标名-匹配器最常用\"><a class=\"anchor\" href=\"#用法四指标名-匹配器最常用\">#</a> 用法四：指标名 + 匹配器（最常用）</h4>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"get\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><h4 id=\"四种匹配操作符\"><a class=\"anchor\" href=\"#四种匹配操作符\">#</a> ⭐ 四种匹配操作符</h4>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">操作符</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>=</code></td>\n<td style=\"text-align:left\">精确匹配</td>\n<td style=\"text-align:left\">值完全相等</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>!=</code></td>\n<td style=\"text-align:left\">不匹配</td>\n<td style=\"text-align:left\">值不完全相等</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>=~</code></td>\n<td style=\"text-align:left\"><strong>正则匹配</strong></td>\n<td style=\"text-align:left\"><strong>必须整值匹配（全锚定）</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>!~</code></td>\n<td style=\"text-align:left\">正则不匹配</td>\n<td style=\"text-align:left\">取反</td>\n</tr>\n</tbody>\n</table>\n<p><strong>关于  <code>=~</code>  的全锚定，务必记住：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ❌ 错误：以为能匹配 \"get\"、\"gets\"… 实际什么都匹配不到（除非值就是 \"ge\"）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"^ge\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># ✅ 正确：显式补齐</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"^ge.*\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><blockquote>\n<p>🧠 Prometheus 的正则<strong>自动加了  <code>^...$</code> </strong>。这是它和 grep 最大的区别，也是新手最高频的错误之一。</p>\n</blockquote>\n<p><strong>多值用  <code>|</code>  表示 &quot;或&quot;：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">env</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"staging|testing|development\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><p><strong>多条件用逗号  <code>,</code>  分隔（逻辑与）：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\".*meta.*\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node_memory_MemFree_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"10.0.0.(101|102):9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>node_memory_MemAvailable_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"10.0.0.20[0-9]:9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>node_memory_MemAvailable_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">!~</span><span class=\"token label-value attr-value\">\"10.0.0.20[12]:9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><h4 id=\"️-空标签值的特殊性\"><a class=\"anchor\" href=\"#️-空标签值的特殊性\">#</a> ⚠️ 空标签值的特殊性</h4>\n<blockquote>\n<p><strong>匹配到空值的匹配器，会让 &quot;根本没有这个标签&quot; 的时间序列也符合条件。</strong></p>\n</blockquote>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">env</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><p>这条不仅匹配  <code>env=&quot;&quot;</code>  的序列，还匹配<strong>完全不含  <code>env</code>  标签</strong>的所有  <code>http_requests_total</code>  序列。</p>\n<h4 id=\"️-一个硬性约束\"><a class=\"anchor\" href=\"#️-一个硬性约束\">#</a> ⚠️ 一个硬性约束</h4>\n<blockquote>\n<p><strong>向量选择器至少要包含一个指标名，或者至少一个 &quot;非空值&quot; 的标签匹配器。</strong></p>\n</blockquote>\n<p>所以下面这两种写法是<strong>非法</strong>的：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\".*\"</span><span class=\"token punctuation\">&#125;</span></span>      # ❌ 正则能匹配空 → 相当于没限定</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"\"</span><span class=\"token punctuation\">&#125;</span></span>         # ❌ 同上</pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>原因</strong>：这两种写法在语义上等于 &quot;把整个数据库都选出来&quot;。Prometheus 直接拒绝，防止你一条查询把内存打满。</p>\n</blockquote>\n<h3 id=\"333-范围向量选择器range-vector-selector\"><a class=\"anchor\" href=\"#333-范围向量选择器range-vector-selector\">#</a> 3.3.3　范围向量选择器（Range Vector Selector）</h3>\n<p>在即时选择器后面加一个  <code>[]</code>  时间范围即可。</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span></pre></td></tr></table></figure><p><strong>时间单位的规则：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">单位</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">单位</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>s</code></td>\n<td style=\"text-align:left\">秒</td>\n<td style=\"text-align:left\"><code>d</code></td>\n<td style=\"text-align:left\">日</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>m</code></td>\n<td style=\"text-align:left\">分</td>\n<td style=\"text-align:left\"><code>w</code></td>\n<td style=\"text-align:left\">周</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>h</code></td>\n<td style=\"text-align:left\">时</td>\n<td style=\"text-align:left\"><code>y</code></td>\n<td style=\"text-align:left\">年</td>\n</tr>\n</tbody>\n</table>\n<p>两条限制：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">1h30m</span><span class=\"token punctuation\">]</span></span>      # ✅ 允许串联，且必须\"由大到小\"</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">.</span>5h<span class=\"token punctuation\">]</span>       # ❌ 不允许小数，必须是整数时间单位</pre></td></tr></table></figure><h4 id=\"为什么统计结果不那么整\"><a class=\"anchor\" href=\"#为什么统计结果不那么整\">#</a> ⭐ 为什么统计结果 &quot;不那么整&quot;？</h4>\n<p>这是一个非常好的理解 Prometheus 设计的机会。</p>\n<blockquote>\n<p><strong>不同时间序列的抓取时间点，并不严格对齐。</strong></p>\n</blockquote>\n<p>原因：如果所有 target 都在同一毫秒被抓取，几百上千个 target 会在那一瞬间把 Prometheus 压出尖峰。所以 Prometheus 会<strong>刻意为每个 target 稍微错峰</strong>（差几毫秒到几百毫秒）。</p>\n<p>后果：<strong>趋势上准确，绝对数值上并不精确。</strong> 比如  <code>[1m]</code>  在 10s 间隔下，采样点数可能是 6 个，也可能是 5 个或 7 个。</p>\n<blockquote>\n<p>💡 这解释了大量 &quot; 为什么  <code>increase()</code>  算出来是  <code>5.8</code>  而不是  <code>6</code> &quot; 的困惑。<strong>不是 bug，是设计。</strong></p>\n</blockquote>\n<h3 id=\"334-偏移修饰符-offset\"><a class=\"anchor\" href=\"#334-偏移修饰符-offset\">#</a> 3.3.4　偏移修饰符  <code>offset</code></h3>\n<p><strong>所有选择器默认以 &quot;当前时间&quot; 为基准。 <code>offset</code>  就是把这根基准线往回推。</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 5 分钟之前的即时值</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>prometheus_http_requests_total <span class=\"token keyword\">offset</span> <span class=\"token context-range\"><span class=\"token range-duration number\">5m</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"200\"</span><span class=\"token punctuation\">&#125;</span></span> <span class=\"token keyword\">offset</span> <span class=\"token context-range\"><span class=\"token range-duration number\">5m</span></span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 1 天之前的那 5 分钟区间</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span> <span class=\"token keyword\">offset</span> <span class=\"token context-range\"><span class=\"token range-duration number\">1d</span></span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># 3 分钟之前的那 5 分钟区间</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/metrics\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span> <span class=\"token keyword\">offset</span> <span class=\"token context-range\"><span class=\"token range-duration number\">3m</span></span></pre></td></tr></table></figure><p><strong>三条要点：</strong></p>\n<ol>\n<li><code>offset</code>  <strong>必须紧跟</strong>在选择器后面，中间不能断开；</li>\n<li><code>offset</code>  偏移的是<strong>时间基点</strong>，不是区间长度；</li>\n<li>既有范围又有偏移时：<strong>先定基点，再取范围</strong>。 <code>[5m] offset 3m</code>  = &quot;3 分钟前那一刻，往前数 5 分钟&quot;。</li>\n</ol>\n<blockquote>\n<p>💡 <strong>典型用途：环比</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 现在的 QPS 与 1 小时前对比</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> <span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span> <span class=\"token keyword\">offset</span> <span class=\"token context-range\"><span class=\"token range-duration number\">1h</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure></blockquote>\n<hr />\n<h2 id=\"34-四种指标类型决定这个数能不能直接画\"><a class=\"anchor\" href=\"#34-四种指标类型决定这个数能不能直接画\">#</a> 3.4　四种指标类型：决定 &quot;这个数能不能直接画&quot;</h2>\n<h3 id=\"341-先看一组真实的统计数据\"><a class=\"anchor\" href=\"#341-先看一组真实的统计数据\">#</a> 3.4.1　先看一组真实的统计数据</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># Prometheus 自身的指标类型分布</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://prometheus:9090/metrics <span class=\"token operator\">|</span> <span class=\"token function\">awk</span> <span class=\"token string\">'$2==\"TYPE\"&#123;t[$NF]++&#125;END&#123;for(i in t) print t[i], i&#125;'</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 93 counter</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 74 gauge</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\">#  7 histogram</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 12 summary</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># Node Exporter 的指标类型分布</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://node01:9100/metrics <span class=\"token operator\">|</span> <span class=\"token function\">awk</span> <span class=\"token string\">'$2==\"TYPE\"&#123;t[$NF]++&#125;END&#123;for(i in t) print t[i], i&#125;'</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 199 gauge</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token comment\">#  74 counter</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token comment\">#  47 untyped</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token comment\">#   1 summary</span></pre></td></tr></table></figure><blockquote>\n<p>💡 这个小命令很值得收藏：<strong> <code>awk '$2==&quot;TYPE&quot;'</code>  直接统计某个 Exporter 暴露了多少种、什么类型的指标</strong>。评估一个 Exporter 的 &quot;指标规模&quot; 时非常好用。</p>\n</blockquote>\n<p>注意  <code>untyped</code>  的存在 —— 它是历史遗留，行为接近 gauge，<strong>新写的 Exporter 不应该产出 untyped</strong>。</p>\n<h3 id=\"342-counter计数器\"><a class=\"anchor\" href=\"#342-counter计数器\">#</a> 3.4.2　Counter（计数器）</h3>\n<blockquote>\n<p><strong>单调递增</strong>的累计值，从 0 开始，<strong>只增不减，除非进程重启归零</strong>。</p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">项目</th>\n<th style=\"text-align:left\">内容</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">特征</td>\n<td style=\"text-align:left\">只能增加，可被重置为 0（重新计数）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">典型场景</td>\n<td style=\"text-align:left\">用户访问量、请求总数、任务完成数、错误总数</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">命名约定</td>\n<td style=\"text-align:left\">常以 <strong> <code>_total</code> </strong> 结尾</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">能否表示递减</td>\n<td style=\"text-align:left\">❌ <strong>不能</strong></td>\n</tr>\n</tbody>\n</table>\n<p><strong>范例：</strong></p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre># HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.</pre></td></tr><tr><td data-num=\"2\"></td><td><pre># TYPE node_cpu_seconds_total counter</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"idle\"&#125;    28375.49</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"iowait\"&#125;      4.82</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"irq\"&#125;         0</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"nice\"&#125;        0</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"softirq\"&#125;     0.09</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"steal\"&#125;       0</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"system\"&#125;      4.43</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>node_cpu_seconds_total&#123;cpu=\"0\",mode=\"user\"&#125;        0.36</pre></td></tr></table></figure><h4 id=\"核心认知counter-的总数几乎没有意义\"><a class=\"anchor\" href=\"#核心认知counter-的总数几乎没有意义\">#</a> ⭐ 核心认知：Counter 的总数几乎没有意义</h4>\n<p><code>node_cpu_seconds_total&#123;cpu=&quot;0&quot;,mode=&quot;idle&quot;&#125; = 28375.49</code>  —— 这个数字本身说明不了任何问题。它只是 &quot;从开机到现在，CPU 0 空闲了多少秒&quot;。</p>\n<blockquote>\n<p><strong>有价值的是它的 &quot;变化速度&quot;。</strong></p>\n</blockquote>\n<p>所以 Counter <strong>几乎从不直接使用</strong>，而是配函数降维：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">函数</th>\n<th style=\"text-align:left\">得到什么</th>\n<th style=\"text-align:left\">用途</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>rate()</code></td>\n<td style=\"text-align:left\">每秒平均增长率</td>\n<td style=\"text-align:left\">⭐ 算 QPS、CPU 使用率</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>irate()</code></td>\n<td style=\"text-align:left\">最近两点的瞬时增长率</td>\n<td style=\"text-align:left\">看突发尖峰</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>increase()</code></td>\n<td style=\"text-align:left\">区间内增长总量</td>\n<td style=\"text-align:left\">算 &quot;这段时间一共处理了多少&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>topk()</code></td>\n<td style=\"text-align:left\">排名前 K 的序列</td>\n<td style=\"text-align:left\">找最忙的接口</td>\n</tr>\n</tbody>\n</table>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 找出请求总数排名前 3 的时间序列</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">topk</span><span class=\"token punctuation\">(</span><span class=\"token number\">3</span><span class=\"token punctuation\">,</span> http_requests_total<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2 小时内的平均增长速率（各序列）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">2h</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 2 小时内最灵敏的瞬时速率</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token function\">irate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">2h</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>Counter 重置的处理</strong>：进程重启后 Counter 归零，直接相减会得到<strong>负数</strong>。<br />\n <code>rate()</code>  /  <code>irate()</code>  /  <code>increase()</code>  <strong>已经内置处理了重置</strong>（自动检测下降并补偿），所以<strong>永远用函数算，不要自己写  <code>current - offset</code> </strong>。</p>\n</blockquote>\n<h3 id=\"343-gauge计量器\"><a class=\"anchor\" href=\"#343-gauge计量器\">#</a> 3.4.3　Gauge（计量器）</h3>\n<blockquote>\n<p><strong>可增可减</strong>的瞬时状态值。</p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">项目</th>\n<th style=\"text-align:left\">内容</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">特征</td>\n<td style=\"text-align:left\">任意波动，可以上升也可以下降</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">典型场景</td>\n<td style=\"text-align:left\">硬盘剩余空间、当前内存使用量、待处理任务数、并发请求数、负载</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">常见操作</td>\n<td style=\"text-align:left\"><code>sum</code>  /  <code>avg</code>  /  <code>min</code>  /  <code>max</code>  /  <code>delta</code>  /  <code>predict_linear</code></td>\n</tr>\n</tbody>\n</table>\n<p><strong>范例：</strong></p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre># TYPE go_memstats_alloc_bytes gauge</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>go_memstats_alloc_bytes 2.017896e+06</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre># TYPE node_load1 gauge</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>node_load1  0</pre></td></tr><tr><td data-num=\"6\"></td><td><pre># TYPE node_load15 gauge</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>node_load15 0</pre></td></tr></table></figure><p><strong>两个实战函数：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># delta：区间首尾之差（\"比 2 小时前升高 / 降低了多少\"）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">delta</span><span class=\"token punctuation\">(</span>cpu_temp_celsius<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">host</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus.example.com\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">2h</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># predict_linear：基于线性回归，预测 t 秒后的值</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ⭐ 容量预测：按最近 6 小时的趋势，预测 4 小时后根分区可用空间是否将小于 0</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token function\">predict_linear</span><span class=\"token punctuation\">(</span>node_filesystem_free_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mountpoint</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">6h</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">,</span> <span class=\"token number\">4</span><span class=\"token operator\">*</span><span class=\"token number\">3600</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">&lt;</span> <span class=\"token number\">0</span></pre></td></tr></table></figure><blockquote>\n<p>💡 最后这条表达式就是第 1 章讲的 &quot;<strong> 趋势分析</strong> &quot; 的落地写法：不是等磁盘满了才告警，而是<strong>提前 4 小时预测它要满</strong>。</p>\n</blockquote>\n<h3 id=\"344-histogram直方图\"><a class=\"anchor\" href=\"#344-histogram直方图\">#</a> 3.4.4　Histogram（直方图）</h3>\n<blockquote>\n<p>用于<strong>统计数据分布</strong>。服务端（Prometheus）负责计算分位数。</p>\n</blockquote>\n<p><strong>核心机制：累积桶（Cumulative Bucket）</strong></p>\n<p>把取值范围切成若干连续、相邻但不重叠的区间（bucket），统计每个区间里有多少个观测值。<strong>累积</strong>的意思是： <code>le=&quot;0.1&quot;</code>  的桶里，<strong>包含了所有 ≤0.1 的样本</strong>，也自然被计入  <code>le=&quot;0.5&quot;</code>  的桶。</p>\n<p><strong>一个 Histogram 指标会展开成多条时间序列：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">序列</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>&lt;basename&gt;_bucket&#123;le=&quot;&lt;上界&gt;&quot;&#125;</code></td>\n<td style=\"text-align:left\">落入该桶（含更小桶）的样本数</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>&lt;basename&gt;_bucket&#123;le=&quot;+Inf&quot;&#125;</code></td>\n<td style=\"text-align:left\">全部样本数（最后一个桶）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>&lt;basename&gt;_sum</code></td>\n<td style=\"text-align:left\">所有观测值的<strong>总和</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>&lt;basename&gt;_count</code></td>\n<td style=\"text-align:left\">观测<strong>总次数</strong>（本质是 Counter）</td>\n</tr>\n</tbody>\n</table>\n<p><strong>范例：</strong></p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre># TYPE prometheus_tsdb_compaction_chunk_range_seconds histogram</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"100\"&#125;        0</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"400\"&#125;        0</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"1600\"&#125;       0</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"6400\"&#125;       0</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"25600\"&#125;      0</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"102400\"&#125;     0</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"409600\"&#125;     0</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"1.6384e+06\"&#125; 0</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"6.5536e+06\"&#125; 6028</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"2.62144e+07\"&#125; 6028</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_bucket&#123;le=\"+Inf\"&#125;      6028</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_sum   1.0734846288e+10</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>prometheus_tsdb_compaction_chunk_range_seconds_count 6028</pre></td></tr></table></figure><p><strong>读法</strong>：</p>\n<ul>\n<li>有 6028 次压缩，<strong>全部</strong>落在 6.55e+06 秒以内（因为从  <code>le=6.5536e+06</code>  开始就跳到 6028 了）；</li>\n<li>平均耗时 =  <code>_sum / _count</code>  = 10734846288 / 6028 ≈ 178 万秒。</li>\n</ul>\n<p><strong>计算分位数：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 过去 10 分钟，HTTP 请求持续时间的第 90 百分位数</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">histogram_quantile</span><span class=\"token punctuation\">(</span><span class=\"token number\">0.9</span><span class=\"token punctuation\">,</span> <span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>prometheus_http_request_duration_seconds_bucket<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">10m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><p><strong>Histogram 的三个优势：</strong></p>\n<ul>\n<li><strong>桶设计一次，服务端随意算</strong>（P50 / P90 / P99 都能事后算）；</li>\n<li><strong>支持聚合</strong>（多实例的桶可以相加后再算分位）；</li>\n<li>单独提供  <code>_sum</code>  和  <code>_count</code> ，从而可以算平均值。</li>\n</ul>\n<h3 id=\"345-summary摘要\"><a class=\"anchor\" href=\"#345-summary摘要\">#</a> 3.4.5　Summary（摘要）</h3>\n<blockquote>\n<p>与 Histogram 类似，但<strong>分位数在客户端就算好了</strong>。</p>\n</blockquote>\n<p><strong>一个 Summary 的序列构成：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">序列</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>&lt;basename&gt;&#123;quantile=&quot;&lt;x&gt;&quot;&#125;</code></td>\n<td style=\"text-align:left\">分位点  <code>x</code>  对应的值（0 ≤ x ≤ 1）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>&lt;basename&gt;_sum</code></td>\n<td style=\"text-align:left\">样本值之和</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>&lt;basename&gt;_count</code></td>\n<td style=\"text-align:left\">样本总数</td>\n</tr>\n</tbody>\n</table>\n<p><strong>范例：</strong></p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre># TYPE go_gc_duration_seconds summary</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>go_gc_duration_seconds&#123;quantile=\"0\"&#125;    3.4414e-05</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>go_gc_duration_seconds&#123;quantile=\"0.25\"&#125; 5.0434e-05</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>go_gc_duration_seconds&#123;quantile=\"0.5\"&#125;  6.5102e-05</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>go_gc_duration_seconds&#123;quantile=\"0.75\"&#125; 9.2624e-05</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>go_gc_duration_seconds&#123;quantile=\"1\"&#125;    0.00109096</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>go_gc_duration_seconds_sum   0.02311494</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>go_gc_duration_seconds_count 229</pre></td></tr></table></figure><h3 id=\"346-histogram-vs-summary一表定生死\"><a class=\"anchor\" href=\"#346-histogram-vs-summary一表定生死\">#</a> 3.4.6　Histogram vs Summary：一表定生死</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">维度</th>\n<th style=\"text-align:left\">Histogram</th>\n<th style=\"text-align:left\">Summary</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>分位数在哪算</strong></td>\n<td style=\"text-align:left\"><strong>Prometheus 服务端</strong>（ <code>histogram_quantile</code> ）</td>\n<td style=\"text-align:left\"><strong>客户端</strong>（每次采样时算好）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>能否事后换分位数</strong></td>\n<td style=\"text-align:left\">✅ 任意（P50/P90/P99 随时算）</td>\n<td style=\"text-align:left\">❌ 只能用客户端预定义的</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>能否多实例聚合</strong></td>\n<td style=\"text-align:left\">✅ 桶可相加后再算</td>\n<td style=\"text-align:left\">❌ <strong>分位数不可聚合</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>客户端开销</strong></td>\n<td style=\"text-align:left\">小（只是计数）</td>\n<td style=\"text-align:left\">大（要维护滑动窗口与分位计算）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>服务端开销</strong></td>\n<td style=\"text-align:left\">大（分位计算消耗资源）</td>\n<td style=\"text-align:left\">小（直接读数）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>准确性</strong></td>\n<td style=\"text-align:left\">受桶划分影响，<strong>是估算值</strong></td>\n<td style=\"text-align:left\">客户端流式计算，相对精确</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>典型用途</strong></td>\n<td style=\"text-align:left\">⭐ <strong>绝大多数场景首选</strong>（请求耗时、响应大小）</td>\n<td style=\"text-align:left\">分位数固定、实例少、不能聚合的场景</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>🧠 <strong>选型口诀</strong>：<strong>能用 Histogram 就用 Histogram。</strong></p>\n<p>因为 &quot;分位数不能聚合&quot; 是致命缺陷：你有 10 个实例，每个实例的 P99 是 100ms，<strong>整体 P99 绝不是 100ms</strong>—— 它可能差得很远。只有 Histogram 的桶相加后才能算整体的分位数。</p>\n<p>唯一例外：客户端只需暴露一个固定的高分位数（如 SLO 的 P99.9），且不需要聚合。</p>\n</blockquote>\n<blockquote>\n<p>⚠️ <strong>严谨补充</strong>：笔记里说 Summary &quot;不支持 sum 或 avg 一类的聚合运算&quot;——<strong> 这句话只对分位数成立</strong>。 <code>&lt;basename&gt;_sum</code>  和  <code>&lt;basename&gt;_count</code>  是可以正常聚合的（它们本质是 Counter）。所以 Summary <strong>可以算平均值</strong>，<strong>不能算分位数</strong>。</p>\n</blockquote>\n<h3 id=\"347-一张决策树\"><a class=\"anchor\" href=\"#347-一张决策树\">#</a> 3.4.7　一张决策树</h3>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">flowchart</span> TD</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    A<span class=\"token text string\">[\"拿到一个指标\"]</span> <span class=\"token arrow operator\">--></span> B<span class=\"token text string\">&#123;\"名字带 _total&lt;br/>或 HELP 写 counter？\"&#125;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    B <span class=\"token arrow operator\">--></span><span class=\"token label property\">|是|</span> C<span class=\"token text string\">[\"Counter&lt;br/>必须配 rate / irate / increase\"]</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    B <span class=\"token arrow operator\">--></span><span class=\"token label property\">|否|</span> D<span class=\"token text string\">&#123;\"名字带 _bucket&lt;br/>或 quantile？\"&#125;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    D <span class=\"token arrow operator\">--></span><span class=\"token label property\">|_bucket|</span> E<span class=\"token text string\">[\"Histogram&lt;br/>histogram_quantile 算分位\"]</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    D <span class=\"token arrow operator\">--></span><span class=\"token label property\">|quantile|</span> F<span class=\"token text string\">[\"Summary&lt;br/>直接读分位值\"]</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    D <span class=\"token arrow operator\">--></span><span class=\"token label property\">|都不是|</span> G<span class=\"token text string\">[\"Gauge&lt;br/>可直接画 / sum / avg / delta\"]</span></pre></td></tr></table></figure><hr />\n<h2 id=\"35-二元运算符从原始数据到业务指标\"><a class=\"anchor\" href=\"#35-二元运算符从原始数据到业务指标\">#</a> 3.5　二元运算符：从 &quot;原始数据&quot; 到 &quot;业务指标&quot;</h2>\n<p>官方文档：<a href=\"https://prometheus.io/docs/prometheus/latest/querying/operators/\">https://prometheus.io/docs/prometheus/latest/querying/operators/</a></p>\n<p>三类二元运算符：<strong>算术</strong>、<strong>比较</strong>、<strong>逻辑</strong>。</p>\n<h3 id=\"351-算术运算符\"><a class=\"anchor\" href=\"#351-算术运算符\">#</a> 3.5.1　算术运算符</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">运算符</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>+</code></td>\n<td style=\"text-align:left\">加</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>-</code></td>\n<td style=\"text-align:left\">减</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>*</code></td>\n<td style=\"text-align:left\">乘</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>/</code></td>\n<td style=\"text-align:left\">除</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>%</code></td>\n<td style=\"text-align:left\">取模</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>^</code></td>\n<td style=\"text-align:left\">幂运算</td>\n</tr>\n</tbody>\n</table>\n<p><strong>最实用的四个用法：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ① 单位换算：字节 → MB（除两次 1024）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>node_memory_MemFree_bytes <span class=\"token operator\">/</span> <span class=\"token number\">1024</span> <span class=\"token operator\">/</span> <span class=\"token number\">1024</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node_memory_MemFree_bytes <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1024</span> <span class=\"token operator\">*</span> <span class=\"token number\">1024</span><span class=\"token punctuation\">)</span>      # 等价写法</pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ② 可用内存百分比</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>node_memory_MemAvailable_bytes <span class=\"token operator\">/</span> node_memory_MemTotal_bytes <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># ③ 内存使用率</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token operator\">/</span> node_memory_MemTotal_bytes <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token comment\"># ④ 根分区磁盘使用率</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token punctuation\">(</span>node_filesystem_size_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mountpoint</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/\"</span><span class=\"token punctuation\">&#125;</span></span> <span class=\"token operator\">-</span> node_filesystem_free_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mountpoint</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token operator\">/</span> node_filesystem_size_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mountpoint</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/\"</span><span class=\"token punctuation\">&#125;</span></span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr></table></figure><blockquote>\n<p>🔗 <strong>呼应第 1 章</strong>：1.4 节讲 &quot;数据处理&quot; 时，我们推导过内存使用率公式；1.5.1 节讲  <code>free</code>  vs  <code>available</code>  时，我们强调过 &quot;只看 available&quot;。<strong>上面第 ③ 条就是那个知识点的最终落地形态。</strong></p>\n</blockquote>\n<h4 id=\"关于字节换算成-gb\"><a class=\"anchor\" href=\"#关于字节换算成-gb\">#</a> ⭐ 关于 &quot;字节换算成 GB&quot;</h4>\n<p>严格来说 <strong>1 GB = 1024³ 字节 = 1073741824</strong>。所以：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>node_memory_MemTotal_bytes <span class=\"token operator\">/</span> <span class=\"token number\">1024</span> <span class=\"token operator\">/</span> <span class=\"token number\">1024</span> <span class=\"token operator\">/</span> <span class=\"token number\">1024</span>     # 严格的 GiB</pre></td></tr></table></figure><p>但很多运维习惯用  <code>1024^3</code>  而口语称 &quot;GB&quot;。<strong>在面板上标注清楚单位（GiB 还是 GB）</strong>，比争论哪个更对更有意义。</p>\n<h3 id=\"352-比较运算符\"><a class=\"anchor\" href=\"#352-比较运算符\">#</a> 3.5.2　比较运算符</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">运算符</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>==</code></td>\n<td style=\"text-align:left\">等于</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>!=</code></td>\n<td style=\"text-align:left\">不等于</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>&gt;</code>   <code>&gt;=</code></td>\n<td style=\"text-align:left\">大于 / 大于等于</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>&lt;</code>   <code>&lt;=</code></td>\n<td style=\"text-align:left\">小于 / 小于等于</td>\n</tr>\n</tbody>\n</table>\n<h4 id=\"关键区别加不加-bool\"><a class=\"anchor\" href=\"#关键区别加不加-bool\">#</a> ⭐ 关键区别：加不加  <code>bool</code></h4>\n<p>这是 PromQL 与 &quot;普通编程语言&quot; 最大的不同点，必须理解透。</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">写法</th>\n<th style=\"text-align:left\">语义</th>\n<th style=\"text-align:left\">结果</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>expr &gt; 80</code></td>\n<td style=\"text-align:left\"><strong>过滤（filter）</strong></td>\n<td style=\"text-align:left\">只保留 &quot;比较成立&quot; 的序列，<strong>不成立的直接消失</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>expr &gt; bool 80</code></td>\n<td style=\"text-align:left\"><strong>转换（bool）</strong></td>\n<td style=\"text-align:left\">保留所有序列，成立的输出  <code>1</code> ，不成立的输出  <code>0</code></td>\n</tr>\n</tbody>\n</table>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 只看 \"内存利用率 > 80%\" 的主机（结果集里没有那些主机，它们 \"消失\" 了）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">(</span><span class=\"token number\">1</span> <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes <span class=\"token operator\">/</span> node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span> <span class=\"token operator\">></span> <span class=\"token number\">80</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 输出 0/1，所有主机都保留（适合画状态图、做告警计数）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">(</span><span class=\"token number\">1</span> <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes <span class=\"token operator\">/</span> node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span> <span class=\"token operator\">></span> bool <span class=\"token number\">80</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 请求数是否超过 1000 → 超了是 1，没超是 0</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>prometheus_http_requests_total <span class=\"token operator\">></span> bool <span class=\"token number\">1000</span></pre></td></tr></table></figure><blockquote>\n<p>📌 <strong>官方说明</strong>：使用  <code>bool</code>  后，<strong>布尔运算不会过滤时间序列</strong>，而是依次把每个样本与标量比较，结果  <code>0</code>  或  <code>1</code>  形成一条新时间序列。</p>\n<p>🎯 <strong>告警规则里大量使用 +bool 会比较 &quot;好用&quot;，但要注意</strong>：告警规则本身用  <code>expr &gt; 80</code>  就够了（Alertmanager 只需要 &quot;有没有结果&quot;）。<strong> <code>bool</code>  更适合画 &quot;状态图&quot; 和做 &quot;计数&quot;</strong>（如  <code>count(up == bool 0)</code>  数挂了几台）。</p>\n</blockquote>\n<h3 id=\"353-逻辑运算符集合运算\"><a class=\"anchor\" href=\"#353-逻辑运算符集合运算\">#</a> 3.5.3　逻辑运算符（集合运算）</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">运算符</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">类比 SQL</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>and</code></td>\n<td style=\"text-align:left\">交集</td>\n<td style=\"text-align:left\"><code>INNER JOIN</code>  /  <code>INTERSECT</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>or</code></td>\n<td style=\"text-align:left\">并集</td>\n<td style=\"text-align:left\"><code>UNION</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>unless</code></td>\n<td style=\"text-align:left\">补集（排除）</td>\n<td style=\"text-align:left\"><code>EXCEPT</code>  /  <code>NOT IN</code></td>\n</tr>\n</tbody>\n</table>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 并集：两个序列都出现（注意两者指标名不同，结果会各自保留）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>node_memory_MemTotal_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"10.0.0.104:9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token operator\">or</span> node_memory_MemFree_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"10.0.0.105:9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 交集：两边都存在的序列才保留（左侧的序列留下，但只用左侧的 \"身份\" 匹配）</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>node_memory_MemTotal_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"10.0.0.101:9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token operator\">and</span> node_memory_MemFree_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"10.0.0.104:9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\"># 补集：从左侧排除掉右侧匹配到的</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>node_memory_MemTotal_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"k8s-node\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token operator\">unless</span> node_memory_MemTotal_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"10.0.0.104:9100\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>注意  <code>and</code>  容易踩的坑</strong>：<br />\n <code>and</code>  的结果<strong>保留左侧的序列和值</strong>，右侧只是用来 &quot;做匹配判断&quot;。<br />\n上面第二个例子里，左右两边的  <code>instance</code>  不同（101 vs 104），<strong>没有共同的标签集 → 交集为空 → 结果什么都没有</strong>。这是新手最迷惑的地方。</p>\n</blockquote>\n<blockquote>\n<p>📌 <strong>限制</strong>： <code>and</code>  /  <code>or</code>  /  <code>unless</code>  <strong>只支持两个即时向量之间运算</strong>，<strong>不支持标量参与</strong>。<br />\n（算术与比较运算符<strong>是可以</strong>和标量运算的，例如  <code>* 100</code> 、 <code>&gt; 80</code> 。笔记里 &quot;不支持标量参与运算&quot; 这句话，仅针对逻辑运算符。）</p>\n</blockquote>\n<h3 id=\"354-运算符优先级\"><a class=\"anchor\" href=\"#354-运算符优先级\">#</a> 3.5.4　运算符优先级</h3>\n<p>从高到低：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">优先级</th>\n<th style=\"text-align:left\">运算符</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1</td>\n<td style=\"text-align:left\"><code>^</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">2</td>\n<td style=\"text-align:left\"><code>*</code>   <code>/</code>   <code>%</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">3</td>\n<td style=\"text-align:left\"><code>+</code>   <code>-</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">4</td>\n<td style=\"text-align:left\"><code>==</code>   <code>!=</code>   <code>&lt;=</code>   <code>&lt;</code>   <code>&gt;=</code>   <code>&gt;</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">5</td>\n<td style=\"text-align:left\"><code>and</code>   <code>unless</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">6</td>\n<td style=\"text-align:left\"><code>or</code></td>\n</tr>\n</tbody>\n</table>\n<p>规则：</p>\n<ul>\n<li>同优先级<strong>左结合</strong>（ <code>^</code>  例外，它是<strong>右结合</strong>）；</li>\n<li>用  <code>()</code>  改变次序 ——<strong> 永远推荐显式加括号</strong>，可读性远胜于背优先级表。</li>\n</ul>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 建议这样写，而不是依赖优先级</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> node_memory_MemTotal_bytes <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr></table></figure><hr />\n<h2 id=\"36-向量匹配让两个指标对上号\"><a class=\"anchor\" href=\"#36-向量匹配让两个指标对上号\">#</a> 3.6　向量匹配：让两个指标 &quot;对上号&quot;</h2>\n<h3 id=\"361-默认规则标签必须完全一致\"><a class=\"anchor\" href=\"#361-默认规则标签必须完全一致\">#</a> 3.6.1　默认规则：标签必须完全一致</h3>\n<p>两个向量做二元运算时，Prometheus 要给左边每条序列在右边找到 &quot;同一条&quot; 序列。</p>\n<blockquote>\n<p><strong>默认要求：除  <code>__name__</code>  之外，所有标签必须完全一致。</strong></p>\n</blockquote>\n<p>大部分时候这没问题（比如  <code>sum / count</code> ，都是同一条序列的总和与总数）。但一旦两边标签 &quot;不完全一样&quot;，就匹配不上。</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>go_gc_duration_seconds_sum<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus:9090\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token operator\">/</span> go_gc_duration_seconds_count<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus:9090\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"prometheus\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr></table></figure><p>上面这样能算（两边标签一致），但如果写成：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>go_gc_duration_seconds_sum <span class=\"token operator\">/</span> go_gc_duration_seconds_count      # ✅ 也能算（同名标签）</pre></td></tr></table></figure><p>一旦两侧标签集不同，就需要<strong>匹配修饰符</strong>。</p>\n<h3 id=\"362-ignoring-与-on\"><a class=\"anchor\" href=\"#362-ignoring-与-on\">#</a> 3.6.2　 <code>ignoring</code>  与  <code>on</code></h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">关键字</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>ignoring(&lt;labels&gt;)</code></td>\n<td style=\"text-align:left\">匹配时<strong>忽略</strong>这些标签</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>on(&lt;labels&gt;)</code></td>\n<td style=\"text-align:left\">匹配时<strong>只使用</strong>这些标签</td>\n</tr>\n</tbody>\n</table>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span> <span class=\"token operator\">&lt;</span>bin<span class=\"token operator\">-</span>op<span class=\"token operator\">></span> <span class=\"token keyword\">ignoring</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">label list</span>><span class=\"token punctuation\">)</span></span> <span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span> <span class=\"token operator\">&lt;</span>bin<span class=\"token operator\">-</span>op<span class=\"token operator\">></span> <span class=\"token keyword\">on</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">label list</span>><span class=\"token punctuation\">)</span></span> <span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span></pre></td></tr></table></figure><h3 id=\"363-一对一匹配one-to-one\"><a class=\"anchor\" href=\"#363-一对一匹配one-to-one\">#</a> 3.6.3　一对一匹配（One-to-one）</h3>\n<p><strong>用官方例子把这件事讲透。</strong> 输入数据：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre># 左侧：按 method + code 统计的 5 分钟错误率</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>method_code:http_errors:rate5m&#123;method=\"get\",  code=\"500\"&#125; 24</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>method_code:http_errors:rate5m&#123;method=\"get\",  code=\"404\"&#125; 30</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>method_code:http_errors:rate5m&#123;method=\"put\",  code=\"501\"&#125;  3</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>method_code:http_errors:rate5m&#123;method=\"post\", code=\"500\"&#125;  6</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>method_code:http_errors:rate5m&#123;method=\"post\", code=\"404\"&#125; 21</pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre># 右侧：按 method 统计的 5 分钟总请求量</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>method:http_requests:rate5m&#123;method=\"get\"&#125;  600</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>method:http_requests:rate5m&#123;method=\"del\"&#125;   34</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>method:http_requests:rate5m&#123;method=\"post\"&#125; 120</pre></td></tr></table></figure><p><strong>需求：算出 &quot;每个 method 下 code=500 的请求占比&quot;。</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>method_code:http_errors:rate5m<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"500\"</span><span class=\"token punctuation\">&#125;</span></span> <span class=\"token operator\">/</span> <span class=\"token keyword\">ignoring</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">)</span></span> method:http_requests:rate5m</pre></td></tr></table></figure><p><strong>为什么必须加  <code>ignoring(code)</code> ？</strong></p>\n<p>因为左边有  <code>method</code>  和  <code>code</code>  两个标签，右边只有  <code>method</code> 。<strong>不忽略  <code>code</code> ，两边标签永远对不上，结果为空。</strong></p>\n<p><strong>结果</strong>：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>&#123;method=\"get\"&#125;  0.04    # 24 / 600</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>&#123;method=\"post\"&#125; 0.05    #  6 / 120</pre></td></tr></table></figure><p><strong>注意两个现象</strong>：</p>\n<ul>\n<li>结果里<strong>没有  <code>put</code>  和  <code>del</code> </strong>—— 因为右侧没有  <code>put</code>  的序列， <code>del</code>  左侧也没有对应项，<strong>无匹配的条目直接被丢弃</strong>；</li>\n<li>结果是<strong>一条序列</strong>（每个 method 一条），因为  <code>code</code>  被忽略掉了。</li>\n</ul>\n<h3 id=\"364-多对一-一对多group_left-与-group_right\"><a class=\"anchor\" href=\"#364-多对一-一对多group_left-与-group_right\">#</a> 3.6.4　多对一 / 一对多： <code>group_left</code>  与  <code>group_right</code></h3>\n<p>上例中，如果我想<strong>同时</strong>算出 500 和 404 的占比，左侧一个  <code>method</code>  对应<strong>多条</strong>序列（多个 code），右侧一个  <code>method</code>  只有一条 —— 这就是<strong>多对一</strong>。</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>method_code:http_errors:rate5m <span class=\"token operator\">/</span> <span class=\"token keyword\">ignoring</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">)</span></span> <span class=\"token keyword\">group_left</span> method:http_requests:rate5m</pre></td></tr></table></figure><p><strong>结果</strong>：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>&#123;method=\"get\",  code=\"500\"&#125; 0.04    # 24 / 600</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>&#123;method=\"get\",  code=\"404\"&#125; 0.05    # 30 / 600</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>&#123;method=\"post\", code=\"500\"&#125; 0.05    #  6 / 120</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>&#123;method=\"post\", code=\"404\"&#125; 0.175   # 21 / 120</pre></td></tr></table></figure><p><strong> <code>group_left</code>  /  <code>group_right</code>  的语义：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">关键字</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">记忆法</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>group_left</code></td>\n<td style=\"text-align:left\"><strong>左侧为 &quot;多&quot;</strong>，右侧为&quot; 一 &quot;</td>\n<td style=\"text-align:left\">把右侧那一条值，<strong>广播</strong>给左侧的多条</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>group_right</code></td>\n<td style=\"text-align:left\"><strong>右侧为 &quot;多&quot;</strong>，左侧为&quot; 一 &quot;</td>\n<td style=\"text-align:left\">反方向</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>🧠 <strong>一句话记住</strong>：<strong> <code>left</code>  /  <code>right</code>  标记的是 &quot;多&quot; 的那一侧。</strong><br />\n名字有点反直觉 —— 它不是说 &quot;多的一方在左边&quot;，而是说 &quot;<strong> 多的一侧是 left（或 right）</strong>&quot;。</p>\n</blockquote>\n<p><strong>完整语法（四个字段可组合）：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span> <span class=\"token operator\">&lt;</span>bin<span class=\"token operator\">-</span>op<span class=\"token operator\">></span> <span class=\"token keyword\">ignoring</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span> <span class=\"token keyword\">group_left</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span>  <span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span> <span class=\"token operator\">&lt;</span>bin<span class=\"token operator\">-</span>op<span class=\"token operator\">></span> <span class=\"token keyword\">ignoring</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span> <span class=\"token keyword\">group_right</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span> <span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span> <span class=\"token operator\">&lt;</span>bin<span class=\"token operator\">-</span>op<span class=\"token operator\">></span> <span class=\"token keyword\">on</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span>      <span class=\"token keyword\">group_left</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span>  <span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span> <span class=\"token operator\">&lt;</span>bin<span class=\"token operator\">-</span>op<span class=\"token operator\">></span> <span class=\"token keyword\">on</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span>      <span class=\"token keyword\">group_right</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span>&lt;<span class=\"token label-key attr-name\">labels</span>><span class=\"token punctuation\">)</span></span> <span class=\"token operator\">&lt;</span>vector expr<span class=\"token operator\">></span></pre></td></tr></table></figure><blockquote>\n<p>💡  <code>group_left(...)</code>  括号里可以写 &quot;<strong> 要从右侧额外带过来的标签</strong> &quot;。这是 kube-prometheus 里做  <code>kube_pod_info * on(pod) group_left(node) ...</code>  这类关联时的关键技巧。</p>\n<p><strong>但请注意课件的态度</strong>：向量匹配本身比较复杂，<strong>初级运维阶段用得不多</strong>。先理解 &quot;为什么需要 ignoring&quot;，等 4.x 讲 k8s 与服务发现时再回头啃多对多。</p>\n</blockquote>\n<h3 id=\"365-高频报错vector-cannot-contain-metrics-with-the-same-labelset\"><a class=\"anchor\" href=\"#365-高频报错vector-cannot-contain-metrics-with-the-same-labelset\">#</a> 3.6.5　⭐ 高频报错： <code>vector cannot contain metrics with the same labelset</code></h3>\n<p>先看一个 &quot;看起来对、其实错&quot; 的写法：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ❌ 报告里常见的错误写法</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"200\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/-/reload\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/-/ready\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><p><strong>问题在哪？</strong></p>\n<ul>\n<li>左侧：<strong>带  <code>code</code> 、 <code>handler</code> 、 <code>instance</code> 、 <code>job</code>  四个标签</strong>的一条序列；</li>\n<li>右侧： <code>sum()</code>  之后<strong>所有标签被清空</strong>（只剩空标签集）的一条序列。</li>\n</ul>\n<p>两边标签完全对不上 → <strong>无匹配 → 结果为空</strong>。（不是语法错，是<strong>逻辑错</strong>，最坑的一类）</p>\n<p>正确写法（两边都聚合成同样 &quot;无标签&quot; 的形态）：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ✅ 200 响应码占全部请求的百分比</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"200\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/-/reload\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><p>另一个典型场景：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ✅ /metrics 这个 handler 占所有 handler 的百分比</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/metrics\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>规律</strong>：算 &quot;占比&quot; 时，<strong>分子分母必须用相同的聚合维度</strong>。<br />\n分子  <code>sum(...)</code>  单序列、分母  <code>sum(...)</code>  单序列 → 一对一，完美匹配。</p>\n</blockquote>\n<hr />\n<h2 id=\"37-聚合操作从一堆数到一个结论\"><a class=\"anchor\" href=\"#37-聚合操作从一堆数到一个结论\">#</a> 3.7　聚合操作：从 &quot;一堆数&quot; 到 &quot;一个结论&quot;</h2>\n<h3 id=\"371-为什么必须聚合\"><a class=\"anchor\" href=\"#371-为什么必须聚合\">#</a> 3.7.1　为什么必须聚合</h3>\n<blockquote>\n<p><strong>单个指标的价值不大。</strong> 监控场景中往往需要把一组指标 &quot;联合&quot; 起来看。</p>\n</blockquote>\n<p>聚合的本质：<strong>对一组值进行计算，返回单个值或少量值</strong> —— 也就是数据库里说的 &quot;聚合函数&quot;。</p>\n<h3 id=\"372-11-种聚合操作\"><a class=\"anchor\" href=\"#372-11-种聚合操作\">#</a> 3.7.2　11 种聚合操作</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">操作符</th>\n<th style=\"text-align:left\">作用</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>sum()</code></td>\n<td style=\"text-align:left\">求和</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>avg()</code></td>\n<td style=\"text-align:left\">求平均值（指标数据分析的标准方法）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>min()</code></td>\n<td style=\"text-align:left\">最小值</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>max()</code></td>\n<td style=\"text-align:left\">最大值</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>count()</code></td>\n<td style=\"text-align:left\">统计<strong>时间序列条数</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>count_values()</code></td>\n<td style=\"text-align:left\">按<strong>样本值</strong>分组计数（值计数）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>topk()</code></td>\n<td style=\"text-align:left\">降序返回前 K 个<strong>最大值</strong>的序列</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>bottomk()</code></td>\n<td style=\"text-align:left\">升序返回前 K 个<strong>最小值</strong>的序列</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>quantile()</code></td>\n<td style=\"text-align:left\">返回分组内指定<strong>分位数</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>stddev()</code></td>\n<td style=\"text-align:left\">标准差（波动程度）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>stdvar()</code></td>\n<td style=\"text-align:left\">方差（求标准差的中间量）</td>\n</tr>\n</tbody>\n</table>\n<p><strong>两种格式：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 普通聚合</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>聚合操作符<span class=\"token punctuation\">(</span>表达式<span class=\"token punctuation\">)</span>                     →  <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 需要额外参数的聚合</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>聚合操作符<span class=\"token punctuation\">(</span>参数<span class=\"token punctuation\">,</span> 表达式<span class=\"token punctuation\">)</span>               →  <span class=\"token keyword\">topk</span><span class=\"token punctuation\">(</span><span class=\"token number\">5</span><span class=\"token punctuation\">,</span> http_requests_total<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>                                         <span class=\"token keyword\">count_values</span><span class=\"token punctuation\">(</span>\"os_version\"<span class=\"token punctuation\">,</span> node_os_version<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>                                         <span class=\"token keyword\">quantile</span><span class=\"token punctuation\">(</span><span class=\"token number\">0.9</span><span class=\"token punctuation\">,</span> http_request_duration_seconds<span class=\"token punctuation\">)</span></pre></td></tr></table></figure><h3 id=\"373-by-与-without等价于-sql-的-group-by\"><a class=\"anchor\" href=\"#373-by-与-without等价于-sql-的-group-by\">#</a> 3.7.3　⭐  <code>by</code>  与  <code>without</code> ：等价于 SQL 的 GROUP BY</h3>\n<p>这是本章最重要的语法点之一。</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">关键字</th>\n<th style=\"text-align:left\">语义</th>\n<th style=\"text-align:left\">类比</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong> <code>by(&lt;labels&gt;)</code> </strong></td>\n<td style=\"text-align:left\"><strong>只</strong>按这些标签分组统计，结果里<strong>只保留</strong>这些标签</td>\n<td style=\"text-align:left\"><code>GROUP BY &lt;labels&gt;</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong> <code>without(&lt;labels&gt;)</code> </strong></td>\n<td style=\"text-align:left\"><strong>排除</strong>这些标签，用<strong>其余所有标签</strong>分组统计</td>\n<td style=\"text-align:left\"><code>GROUP BY 除这些之外的所有列</code></td>\n</tr>\n</tbody>\n</table>\n<p><strong>两种书写位置，完全等价：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 格式 1：by/without 写在括号外（推荐，读起来更像 SQL）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token keyword\">without</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">)</span></span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 格式 2：by/without 写在函数名后</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token keyword\">sum</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token keyword\">sum</span> <span class=\"token keyword\">without</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span></pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>选哪个？</strong> 官方文档示例用格式 2 较多，但格式 1 更接近 SQL 直觉。<strong>团队统一即可，别混用。</strong></p>\n</blockquote>\n<h3 id=\"374-一串由浅入深的例子\"><a class=\"anchor\" href=\"#374-一串由浅入深的例子\">#</a> 3.7.4　一串由浅入深的例子</h3>\n<p>先看数据长什么样：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>node_os_version&#123;id=\"ubuntu\", id_like=\"debian\", instance=\"10.0.0.200:9100\", job=\"node_exporter\", name=\"Ubuntu\"&#125; 1</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>node_os_version&#123;id=\"ubuntu\", id_like=\"debian\", instance=\"10.0.0.201:9100\", job=\"node_exporter\", name=\"Ubuntu\"&#125; 1</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node_os_version&#123;id=\"ubuntu\", id_like=\"debian\", instance=\"10.0.0.202:9100\", job=\"node_exporter\", name=\"Ubuntu\"&#125; 1</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>node_os_version&#123;id=\"ubuntu\", id_like=\"debian\", instance=\"10.0.0.203:9100\", job=\"node_exporter\", name=\"Ubuntu\"&#125; 1</pre></td></tr></table></figure><p><strong>① 数一数有几台 Ubuntu 主机</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">count</span><span class=\"token punctuation\">(</span>node_os_version<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">id</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"ubuntu\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span>        # → <span class=\"token number\">4</span></pre></td></tr></table></figure><p><strong>② 按操作系统版本分别统计数量</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">count_values</span><span class=\"token punctuation\">(</span>\"os_version\"<span class=\"token punctuation\">,</span> node_os_version<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># &#123;os_version=\"22.04\"&#125; 4</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># &#123;os_version=\"20.04\"&#125; 2</span></pre></td></tr></table></figure><blockquote>\n<p>💡  <code>count_values(&quot;标签名&quot;, expr)</code>  会<strong>创建一个新标签</strong>，值为样本值本身，然后统计每个值出现了几次。这是 &quot;按值分布统计&quot; 的神器。</p>\n</blockquote>\n<p><strong>③ 所有主机的内存总和</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span>            # 单条结果，无标签</pre></td></tr></table></figure><p><strong>④ 每台主机的内存总量</strong>（分组）</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># &#123;instance=\"10.0.0.101:9100\"&#125; 2.1e+09</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># &#123;instance=\"10.0.0.102:9100\"&#125; 2.1e+09</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># ...</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>注意一个容易迷惑的现象</strong>： <code>sum(...) without (instance, job)</code>  和  <code>sum(...) by (instance)</code>  <strong>结果不同</strong>！</p>\n<ul>\n<li><code>by(instance)</code>  → 结果只有  <code>instance</code>  标签；</li>\n<li><code>without(instance, job)</code>  → 结果保留  <code>instance</code> / <code>job</code>  之外的<strong>所有</strong>标签（比如  <code>cpu</code> 、 <code>mode</code> ）。</li>\n</ul>\n<p><strong>想清楚 &quot;我要的结果带哪些标签&quot;，再决定用  <code>by</code>  还是  <code>without</code> 。</strong></p>\n</blockquote>\n<p><strong>⑤ 数每台主机的 CPU 核心数</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">count</span><span class=\"token punctuation\">(</span>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"system\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span>              # 所有主机加起来多少个核</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">count</span><span class=\"token punctuation\">(</span>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"system\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span> # 每台主机几个核</pre></td></tr></table></figure><blockquote>\n<p>💡 这个技巧很实用： <code>node_cpu_seconds_total</code>  每条序列对应一个  <code>cpu</code>  核心，<strong>数序列条数 = 数核心数</strong>。</p>\n</blockquote>\n<p><strong>⑥ 找最忙的接口 / 最大的值</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">max</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">max</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token keyword\">topk</span><span class=\"token punctuation\">(</span><span class=\"token number\">5</span><span class=\"token punctuation\">,</span> prometheus_http_requests_total<span class=\"token punctuation\">)</span>      # 前 <span class=\"token number\">5</span> 大</pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token keyword\">bottomk</span><span class=\"token punctuation\">(</span><span class=\"token number\">5</span><span class=\"token punctuation\">,</span> prometheus_http_requests_total<span class=\"token punctuation\">)</span>   # 前 <span class=\"token number\">5</span> 小</pre></td></tr></table></figure><blockquote>\n<p>💡  <code>topk</code>  /  <code>bottomk</code>  相当于 SQL 的  <code>ORDER BY ... LIMIT K</code> 。<strong>注意： <code>topk</code>  会保留原始标签</strong>（不是聚合掉），所以你能看到 &quot;是哪条序列&quot;。</p>\n</blockquote>\n<p><strong>⑦ 按 mode 分组看 CPU 时间</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_cpu_seconds_total<span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">)</span></span></pre></td></tr></table></figure><p><strong>⑧ 多维度分组</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">count</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">)</span></span></pre></td></tr></table></figure><h3 id=\"375-报错现场算占比时的标签不匹配\"><a class=\"anchor\" href=\"#375-报错现场算占比时的标签不匹配\">#</a> 3.7.5　⭐ 报错现场：算 &quot;占比&quot; 时的标签不匹配</h3>\n<p>这是运维工作中<strong>最高频的 PromQL 报错</strong>，值得单独讲。</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ❌ 报错：vector cannot contain metrics with the same labelset</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>nginx_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">path</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/api\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"GET\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"200\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>nginx_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">path</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/api\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"GET\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><p><strong>症状</strong>：要么报  <code>labelset</code>  冲突，要么<strong>返回空</strong>。</p>\n<p><strong>根因</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">侧</th>\n<th style=\"text-align:left\">标签集</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">左</td>\n<td style=\"text-align:left\"><code>path</code> 、 <code>method</code> 、 <code>code</code> 、 <code>instance</code> 、 <code>job</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">右</td>\n<td style=\"text-align:left\">空（ <code>sum()</code>  清空了所有标签）</td>\n</tr>\n</tbody>\n</table>\n<p>标签对不上 → 要么无匹配（空结果），要么在全无标签的情况下多对一冲突。</p>\n<p><strong>正确写法 —— 两边聚合到同一粒度：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ✅ 200 占比</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>nginx_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">path</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/api\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"GET\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"200\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>nginx_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">path</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/api\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"GET\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr></table></figure><p><strong>如果确实要保留  <code>code</code>  维度：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ✅ 每个 code 占该 path+method 总量的比例</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>nginx_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">path</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/api\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"GET\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">)</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">ignoring</span><span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">)</span></span> <span class=\"token keyword\">group_right</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>nginx_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">path</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/api\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">method</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"GET\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><blockquote>\n<p>🎯 <strong>面试加分点</strong>：能说出 &quot;算占比时分子分母必须同粒度聚合&quot; 并且知道用  <code>ignoring</code>  +  <code>group_right</code>  保留维度，说明你真的写过 PromQL，不是背的。</p>\n</blockquote>\n<hr />\n<h2 id=\"38-功能函数让-counter-变得有意义\"><a class=\"anchor\" href=\"#38-功能函数让-counter-变得有意义\">#</a> 3.8　功能函数：让 Counter 变得有意义</h2>\n<p>官方文档：<a href=\"https://prometheus.io/docs/prometheus/latest/querying/functions/\">https://prometheus.io/docs/prometheus/latest/querying/functions/</a></p>\n<p>Prometheus 内置函数有数十个，按官方分组主要分四类：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">分类</th>\n<th style=\"text-align:left\">代表函数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>计算相关</strong></td>\n<td style=\"text-align:left\"><code>abs</code>   <code>deriv</code>   <code>exp</code>   <code>ln</code>   <code>log2</code>   <code>log10</code>   <code>sqrt</code>   <code>ceil</code>   <code>floor</code>   <code>round</code>   <code>delta</code>   <code>idelta</code>   <code>increase</code>   <code>rate</code>   <code>irate</code>   <code>resets</code>   <code>holt_winters</code>   <code>histogram_quantile</code>   <code>predict_linear</code>   <code>*_over_time</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>取样相关</strong></td>\n<td style=\"text-align:left\"><code>absent</code>   <code>sort</code>   <code>sort_desc</code>   <code>changes</code>   <code>scalar</code>   <code>clamp_max</code>   <code>clamp_min</code>   <code>absent_over_time</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>时间相关</strong></td>\n<td style=\"text-align:left\"><code>time</code>   <code>timestamp</code>   <code>hour</code>   <code>minute</code>   <code>month</code>   <code>year</code>   <code>day_of_month</code>   <code>day_of_week</code>   <code>days_in_month</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>标签相关</strong></td>\n<td style=\"text-align:left\"><code>label_join</code>   <code>label_replace</code></td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"381-取整三兄弟别搞混\"><a class=\"anchor\" href=\"#381-取整三兄弟别搞混\">#</a> 3.8.1　取整三兄弟（别搞混）</h3>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">ceil</span><span class=\"token punctuation\">(</span>node_load15 <span class=\"token operator\">*</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>      # 向上取整：<span class=\"token number\">4.1</span> → <span class=\"token number\">5</span><span class=\"token punctuation\">,</span> <span class=\"token number\">4.9</span> → <span class=\"token number\">5</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">floor</span><span class=\"token punctuation\">(</span>node_load15 <span class=\"token operator\">*</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>     # 向下取整：<span class=\"token number\">4.1</span> → <span class=\"token number\">4</span><span class=\"token punctuation\">,</span> <span class=\"token number\">4.9</span> → <span class=\"token number\">4</span>  ← 直接砍掉小数，不看大小</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">round</span><span class=\"token punctuation\">(</span>node_load15 <span class=\"token operator\">*</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>     # 四舍五入：<span class=\"token number\">4.1</span> → <span class=\"token number\">4</span><span class=\"token punctuation\">,</span> <span class=\"token number\">4.9</span> → <span class=\"token number\">5</span></pre></td></tr></table></figure><blockquote>\n<p>🧠 <strong> <code>floor</code>  不是四舍五入！</strong> 它是 &quot;把小数部分直接删掉&quot;。 <code>floor(4.9) = 4</code> ，这跟  <code>round(4.9) = 5</code>  完全不同。这是最容易答错的一个。</p>\n</blockquote>\n<h3 id=\"382-核心四兄弟increase-rate-irate-delta\"><a class=\"anchor\" href=\"#382-核心四兄弟increase-rate-irate-delta\">#</a> 3.8.2　⭐ 核心四兄弟： <code>increase</code>  /  <code>rate</code>  /  <code>irate</code>  /  <code>delta</code></h3>\n<p>这是全章最需要 &quot;真的理解&quot; 的部分。</p>\n<p>先看它们各自的定义：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">函数</th>\n<th style=\"text-align:left\">输入</th>\n<th style=\"text-align:left\">输出</th>\n<th style=\"text-align:left\">一句话</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>increase(v[d])</code></td>\n<td style=\"text-align:left\">range vector</td>\n<td style=\"text-align:left\"><strong>区间内增长总量</strong></td>\n<td style=\"text-align:left\">&quot;这段时间一共涨了多少&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>rate(v[d])</code></td>\n<td style=\"text-align:left\">range vector</td>\n<td style=\"text-align:left\"><strong>每秒平均增长率</strong></td>\n<td style=\"text-align:left\">&quot;平均下来每秒涨多少&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>irate(v[d])</code></td>\n<td style=\"text-align:left\">range vector</td>\n<td style=\"text-align:left\"><strong>最近两点的瞬时增长率</strong></td>\n<td style=\"text-align:left\">&quot;现在这一刻每秒涨多少&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>delta(v[d])</code></td>\n<td style=\"text-align:left\">range vector</td>\n<td style=\"text-align:left\"><strong>区间首尾差值</strong>（可负）</td>\n<td style=\"text-align:left\">给 Gauge 用，不是给 Counter 用</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>idelta(v[d])</code></td>\n<td style=\"text-align:left\">range vector</td>\n<td style=\"text-align:left\"><strong>最近两点差值</strong></td>\n<td style=\"text-align:left\">给 Gauge 用</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ <strong>先纠正一个常见误解</strong>： <code>increase()</code>  <strong>不是</strong> &quot;最后两个点相减&quot;。<br />\n它等于  <code>rate(v[d]) × 区间秒数</code> ，也就是<strong>基于区间首尾值做外推估算</strong>得到的增长总量。<br />\n（笔记里写 &quot;increase = last 值 − last 前一个值&quot;，那是  <code>idelta</code>  的语义，不是  <code>increase</code> 。）</p>\n</blockquote>\n<h4 id=\"用薪水理解-increase-和-rate讲师原话非常好用\"><a class=\"anchor\" href=\"#用薪水理解-increase-和-rate讲师原话非常好用\">#</a> 用 &quot;薪水&quot; 理解  <code>increase</code>  和  <code>rate</code> （讲师原话，非常好用）</h4>\n<p>假设你的月薪从 <strong>1 万</strong> 涨到了 <strong>2 万</strong>：</p>\n<ul>\n<li><strong> <code>increase</code>  = 1 万</strong>（一共涨了 1 万）</li>\n<li>但这个数字<strong>意义有限</strong> —— 因为你还得知道 &quot;用了多久&quot;：\n<ul>\n<li>一年涨 1 万 → 变化率 = 1 万 / 年</li>\n<li>十年涨 1 万 → 变化率 = 1000 / 年</li>\n</ul>\n</li>\n</ul>\n<blockquote>\n<p><strong>结论：光看 &quot;涨了多少&quot; 意义不大，&quot;单位时间涨了多少&quot; 才有意义。这就是  <code>rate</code> 。</strong></p>\n</blockquote>\n<p><span class=\"katex-display\"><span class=\"katex\"><span class=\"katex-mathml\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><semantics><mrow><mtext>rate</mtext><mo>=</mo><mfrac><mrow><mtext>区间末值</mtext><mo>−</mo><mtext>区间首值</mtext></mrow><mtext>区间秒数</mtext></mfrac></mrow><annotation encoding=\"application/x-tex\">\\text{rate} = \\frac{\\text{区间末值} - \\text{区间首值}}{\\text{区间秒数}}\n</annotation></semantics></math></span><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.61508em;vertical-align:0em;\"></span><span class=\"mord text\"><span class=\"mord\">rate</span></span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span><span class=\"mrel\">=</span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:2.04633em;vertical-align:-0.686em;\"></span><span class=\"mord\"><span class=\"mopen nulldelimiter\"></span><span class=\"mfrac\"><span class=\"vlist-t vlist-t2\"><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:1.36033em;\"><span style=\"top:-2.314em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord text\"><span class=\"mord cjk_fallback\">区间秒数</span></span></span></span><span style=\"top:-3.23em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"frac-line\" style=\"border-bottom-width:0.04em;\"></span></span><span style=\"top:-3.677em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord\"><span class=\"mord text\"><span class=\"mord cjk_fallback\">区间末值</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">−</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">区间首值</span></span></span></span></span><span class=\"vlist-s\">​</span></span><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:0.686em;\"><span></span></span></span></span></span><span class=\"mclose nulldelimiter\"></span></span></span></span></span></span></p>\n<h4 id=\"rate-的计算方式与被平均问题\"><a class=\"anchor\" href=\"#rate-的计算方式与被平均问题\">#</a>  <code>rate</code>  的计算方式与 &quot;被平均&quot; 问题</h4>\n<p>假设采集间隔 10s，取  <code>[1m]</code> ，区间内有 6 个采样点：</p>\n<pre><code>t=0s    t=10s   t=20s   t=30s   t=40s   t=50s   t=60s\n 100     110     120     130     140     150     160\n  ↑                                              ↑\n首值                                           末值\n\nrate   = (160 - 100) / 60 = 1.0   ← 只用首尾两个点，中间 4 个点被&quot;忽略&quot;\n</code></pre>\n<p><strong>问题</strong>：如果中间发生了剧烈波动（比如  <code>t=50s</code>  时突然涨到 500 又回落）， <code>rate</code>  <strong>完全看不出来</strong> —— 因为它已经把这段变化 &quot;平均&quot; 掉了。</p>\n<h4 id=\"irate-的计算方式只看最后两步\"><a class=\"anchor\" href=\"#irate-的计算方式只看最后两步\">#</a>  <code>irate</code>  的计算方式：只看最后两步</h4>\n<pre><code>irate = (末值 - 末值前一个点) / 这两点的时间差\n      = (160 - 150) / 10 = 1.0    ← 只看最后两个点\n</code></pre>\n<p><strong>优势</strong>：能反映<strong>最近一瞬间</strong>的变化，尖峰不会被抹平。</p>\n<h4 id=\"一张图对比\"><a class=\"anchor\" href=\"#一张图对比\">#</a> 一张图对比</h4>\n<pre><code>场景：前 50 秒请求量平稳（0~10），最后 10 秒暴增到 100+\n\n         rate（平均）              irate（瞬时）\n         ┌────────────────┐        ┌────────────────┐\n   数值  │      ╱         │        │              ╱ │\n        │    ╱           │        │            ╱   │\n        │  ╱             │        │          ╱     │\n        └────────────────┘        └────────────────┘\n          平缓、削平了峰值            尖锐、捕捉到尖峰\n\n   适合：SLO 统计、容量规划        适合：突发流量、异常检测\n</code></pre>\n<blockquote>\n<p>📌 <strong>官方建议</strong>：</p>\n<ul>\n<li><strong> <code>irate</code>  适合快速变化的计数器</strong>（如高 QPS 的接口）；</li>\n<li><strong> <code>rate</code>  适合缓慢变化的计数器</strong>（如磁盘 IO、网卡流量）。</li>\n<li>对快速变化的计数器用  <code>rate</code> ，会<strong>削平峰值</strong>；除非把区间设得很小来减弱这种效应。</li>\n</ul>\n</blockquote>\n<h4 id=\"实战写法\"><a class=\"anchor\" href=\"#实战写法\">#</a> 实战写法</h4>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ① 单块磁盘过去 1 分钟的读取速率</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>node_disk_read_bytes_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">1m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">irate</span><span class=\"token punctuation\">(</span>node_disk_read_bytes_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">1m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ② 网卡出口流量（MB/s）</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>node_network_transmit_bytes_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">device</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"eth0\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">1m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token number\">1024</span> <span class=\"token operator\">/</span> <span class=\"token number\">1024</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># ③ 最近 1 分钟 CPU 空闲时间增量</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token function\">increase</span><span class=\"token punctuation\">(</span>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">cpu</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"0\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"idle\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">1m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token comment\"># ④ ⭐ CPU 使用率（最经典的写法）</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token punctuation\">(</span><span class=\"token number\">1</span> <span class=\"token operator\">-</span> <span class=\"token keyword\">avg</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">(</span><span class=\"token function\">irate</span><span class=\"token punctuation\">(</span>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"idle\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr></table></figure><p><strong>第 ④ 条拆解：</strong></p>\n<ol>\n<li><code>node_cpu_seconds_total&#123;mode=&quot;idle&quot;&#125;[5m]</code>  —— 所有 CPU 所有核的空闲时间（range vector）</li>\n<li><code>irate(...)</code>  —— 每个核的空闲速率（instant vector）</li>\n<li><code>avg by (instance)(...)</code>  —— 把 &quot;多核&quot; 平均掉，得到 &quot;这台机器的平均空闲率&quot;（0~1）</li>\n<li><code>1 - ...</code>  —— 得到使用率（0~1）</li>\n<li><code>* 100</code>  —— 转成百分比</li>\n</ol>\n<blockquote>\n<p>💡 <strong>为什么用  <code>avg by (instance)</code>  而不是  <code>sum</code> ？</strong><br />\n因为每个核的  <code>idle</code>  速率已经是 0~1 的比例，<strong>平均</strong>才对； <code>sum</code>  会得到 &quot;核心数&quot; 倍的值，<strong>完全错</strong>。<br />\n<strong>这是 PromQL 里最容易算错的指标，面试高频。</strong></p>\n</blockquote>\n<h4 id=\"另一个经典qps\"><a class=\"anchor\" href=\"#另一个经典qps\">#</a> 另一个经典：QPS</h4>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 每秒请求数（QPS）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">sum</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">(</span><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 5xx 错误率是否超过总请求的 10%</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">status_code</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"5.*\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token operator\">></span> <span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_requests_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">0.1</span></pre></td></tr></table></figure><h3 id=\"383-time-与运行时长\"><a class=\"anchor\" href=\"#383-time-与运行时长\">#</a> 3.8.3　 <code>time()</code>  与运行时长</h3>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 每台主机已运行多少小时</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">(</span><span class=\"token function\">time</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> node_boot_time_seconds<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token number\">3600</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 所有主机运行时间总和</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span><span class=\"token function\">time</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> node_boot_time_seconds<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token number\">3600</span></pre></td></tr></table></figure><blockquote>\n<p>💡  <code>time()</code>  返回 &quot;当前时间戳&quot;， <code>node_boot_time_seconds</code>  返回 &quot;开机时间戳&quot;，相减就是 uptime——<strong> 这是一个非常经典的 &quot;两个指标相减&quot; 的用法</strong>。</p>\n</blockquote>\n<h3 id=\"384-histogram_quantile算分位数\"><a class=\"anchor\" href=\"#384-histogram_quantile算分位数\">#</a> 3.8.4　 <code>histogram_quantile</code> ：算分位数</h3>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 过去 10 分钟 HTTP 请求耗时的 P90</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">histogram_quantile</span><span class=\"token punctuation\">(</span><span class=\"token number\">0.9</span><span class=\"token punctuation\">,</span> <span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>prometheus_http_request_duration_seconds_bucket<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">10m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><p><strong>三个使用要点：</strong></p>\n<ol>\n<li><strong>必须配合  <code>rate()</code> </strong>（ <code>_bucket</code>  是 Counter，累加值不能直接算分位）；</li>\n<li><strong>必须用  <code>_bucket</code>  序列</strong>，不是  <code>_sum</code>  /  <code>_count</code> ；</li>\n<li>结果只是<strong>估算值</strong>，精度取决于桶的划分。桶太少、太粗，误差会很大。</li>\n</ol>\n<p><strong>按维度分组算：</strong></p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">histogram_quantile</span><span class=\"token punctuation\">(</span><span class=\"token number\">0.9</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token keyword\">sum</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">le</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">(</span><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>http_request_duration_seconds_bucket<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>注意  <code>sum by (le, handler)</code>  里必须保留  <code>le</code> ！</strong> 丢了  <code>le</code> ，函数就不知道桶边界，直接报错。这是新手最常见的  <code>histogram_quantile</code>  错误。</p>\n</blockquote>\n<h3 id=\"385-absent专门为告警设计\"><a class=\"anchor\" href=\"#385-absent专门为告警设计\">#</a> 3.8.5　 <code>absent</code> ：专门为告警设计</h3>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">absent</span><span class=\"token punctuation\">(</span>node_memory_SwapTotal_bytes<span class=\"token punctuation\">)</span></pre></td></tr></table></figure><table>\n<thead>\n<tr>\n<th style=\"text-align:left\">情况</th>\n<th style=\"text-align:left\">返回值</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">有数据</td>\n<td style=\"text-align:left\"><strong>空</strong>（无结果）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">没数据</td>\n<td style=\"text-align:left\"><strong>1</strong></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>💡 <strong>用途</strong>：<strong>&quot;指标消失了&quot; 本身就是要告警的事件。</strong> 比如某个 Exporter 挂了， <code>node_memory_*</code>  全没了 —— 这时候正常表达式会返回空，告警不会触发，你就 &quot;什么都不知道&quot;。用  <code>absent()</code>  才抓得住这种 &quot;彻底失联&quot;。</p>\n<p>这条是<strong>告警规则设计的必备技巧</strong>，第 5 章会反复用到。</p>\n</blockquote>\n<h3 id=\"386-标签处理函数\"><a class=\"anchor\" href=\"#386-标签处理函数\">#</a> 3.8.6　标签处理函数</h3>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># label_replace：用正则重命名 / 改写标签</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">label_replace</span><span class=\"token punctuation\">(</span>up<span class=\"token punctuation\">,</span> \"host\"<span class=\"token punctuation\">,</span> \"$<span class=\"token number\">1</span>\"<span class=\"token punctuation\">,</span> \"instance\"<span class=\"token punctuation\">,</span> \"<span class=\"token punctuation\">(</span><span class=\"token punctuation\">.</span><span class=\"token operator\">*</span><span class=\"token punctuation\">)</span>:<span class=\"token punctuation\">.</span><span class=\"token operator\">*</span>\"<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># label_join：把多个标签拼成一个</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">label_join</span><span class=\"token punctuation\">(</span>up<span class=\"token punctuation\">,</span> \"endpoint\"<span class=\"token punctuation\">,</span> \"<span class=\"token operator\">/</span>\"<span class=\"token punctuation\">,</span> \"instance\"<span class=\"token punctuation\">,</span> \"job\"<span class=\"token punctuation\">)</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>重要提醒</strong>： <code>label_replace</code>  /  <code>label_join</code>  是<strong>查询时</strong>的临时改写，<strong>不会改变存储中的序列</strong>。真正的 &quot;标签管理&quot; 要用第 4 章的  <code>relabel_configs</code>  /  <code>metric_relabel_configs</code> ——<strong> 那是落盘的、永久的</strong>。</p>\n</blockquote>\n<hr />\n<h2 id=\"39-本章小结\"><a class=\"anchor\" href=\"#39-本章小结\">#</a> 3.9　本章小结</h2>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>mindmap</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  root<span class=\"token text string\">((\"第3章&lt;br/>PromQL\"))</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    类型系统</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>      instant vector 可画图</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>      range vector 只能进函数</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      scalar</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>      string</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    选择器</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>      指标名</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>      四种匹配器</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      正则全锚定</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>      范围 m h d w y</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>      offset 移基点</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    指标类型</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>      Counter 配 rate</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>      Gauge 可直画</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>      Histogram 服务端算分位</pre></td></tr><tr><td data-num=\"18\"></td><td><pre>      Summary 客户端算分位</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    二元运算</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>      算术 单位换算</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>      比较 bool 不过滤</pre></td></tr><tr><td data-num=\"22\"></td><td><pre>      逻辑 and or unless</pre></td></tr><tr><td data-num=\"23\"></td><td><pre>      向量匹配 ignoring group</pre></td></tr><tr><td data-num=\"24\"></td><td><pre>    聚合</pre></td></tr><tr><td data-num=\"25\"></td><td><pre>      sum avg min max count</pre></td></tr><tr><td data-num=\"26\"></td><td><pre>      topk bottomk</pre></td></tr><tr><td data-num=\"27\"></td><td><pre>      count_values</pre></td></tr><tr><td data-num=\"28\"></td><td><pre>      by without</pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    函数</pre></td></tr><tr><td data-num=\"30\"></td><td><pre>      rate 平均</pre></td></tr><tr><td data-num=\"31\"></td><td><pre>      irate 瞬时</pre></td></tr><tr><td data-num=\"32\"></td><td><pre>      increase 增量</pre></td></tr><tr><td data-num=\"33\"></td><td><pre>      delta Gauge 差值</pre></td></tr><tr><td data-num=\"34\"></td><td><pre>      histogram_quantile</pre></td></tr><tr><td data-num=\"35\"></td><td><pre>      predict_linear</pre></td></tr><tr><td data-num=\"36\"></td><td><pre>      absent</pre></td></tr></table></figure><p><strong>七条必须带走的知识</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">#</th>\n<th style=\"text-align:left\">知识</th>\n<th style=\"text-align:left\">为什么重要</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1</td>\n<td style=\"text-align:left\"><strong>范围向量不能直接画图</strong></td>\n<td style=\"text-align:left\">必须先降维（ <code>rate</code> / <code>avg_over_time</code> ）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">2</td>\n<td style=\"text-align:left\"><strong> <code>=~</code>  是整值匹配</strong></td>\n<td style=\"text-align:left\">不写  <code>.*</code>  就匹配不到</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">3</td>\n<td style=\"text-align:left\"><strong>Counter 的总数没意义</strong></td>\n<td style=\"text-align:left\">必须配  <code>rate</code> / <code>irate</code> / <code>increase</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">4</td>\n<td style=\"text-align:left\"><strong> <code>&gt; 80</code>  过滤、 <code>&gt; bool 80</code>  转换</strong></td>\n<td style=\"text-align:left\">决定结果里 &quot;有没有这条序列&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">5</td>\n<td style=\"text-align:left\"><strong> <code>rate</code>  被平均、 <code>irate</code>  抓瞬时</strong></td>\n<td style=\"text-align:left\">选错就看不到尖峰</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">6</td>\n<td style=\"text-align:left\"><strong>算占比分子分母必须同粒度</strong></td>\n<td style=\"text-align:left\">否则空结果或 labelset 报错</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">7</td>\n<td style=\"text-align:left\"><strong>CPU 使用率用  <code>avg by(instance)</code> ，不是  <code>sum</code> </strong></td>\n<td style=\"text-align:left\"><code>sum</code>  结果会乘上核心数</td>\n</tr>\n</tbody>\n</table>\n<hr />\n<h2 id=\"310-面试高频问答\"><a class=\"anchor\" href=\"#310-面试高频问答\">#</a> 3.10　面试高频问答</h2>\n<p><strong>Q1： <code>rate</code>  和  <code>irate</code>  有什么区别？分别什么时候用？</strong></p>\n<blockquote>\n<p><code>rate</code>  用区间<strong>首尾两个值</strong>相减再除以区间秒数，得到<strong>平均</strong>增长率，会把中间的波动抹平； <code>irate</code>  用<strong>最后两个采样点</strong>相减除以它们的时间差，得到<strong>瞬时</strong>增长率，能反映尖峰。<br />\n快速变化的计数器（高 QPS 接口、突发流量）用  <code>irate</code> ；缓慢变化的计数器（磁盘 IO、网络流量、SLO 统计）用  <code>rate</code> 。</p>\n</blockquote>\n<p><strong>Q2：为什么不能直接画  <code>node_cpu_seconds_total</code> ？</strong></p>\n<blockquote>\n<p>因为它是 Counter，值是 &quot;开机至今的累计秒数&quot;，单调递增，画出来就是一条斜线，毫无意义。必须用  <code>rate</code>  /  <code>irate</code>  转成 &quot;每秒的增长率&quot; 才有观察价值。</p>\n</blockquote>\n<p><strong>Q3： <code>by</code>  和  <code>without</code>  有什么区别？</strong></p>\n<blockquote>\n<p><code>by(labels)</code>  是<strong>白名单</strong>：只按这些标签分组，结果只保留这些标签，等价于 SQL 的  <code>GROUP BY</code> 。<br />\n <code>without(labels)</code>  是<strong>黑名单</strong>：排除这些标签，用其余全部标签分组，结果保留除它们外的所有标签。</p>\n</blockquote>\n<p><strong>Q4：Histogram 和 Summary 怎么选？</strong></p>\n<blockquote>\n<p>优先 Histogram。因为 Histogram 的分位数由服务端用  <code>histogram_quantile</code>  计算，<strong>桶可以跨实例相加</strong>，所以能算全局分位数，也能事后换分位数；Summary 的分位数在客户端算好，<strong>不可聚合</strong>（10 个实例的 P99 不能相加得到整体 P99），只能用预定义的分位点。<br />\nSummary 只适合分位数固定、实例少、不需要聚合的场景。代价是 Histogram 受桶划分影响，结果是估算值。</p>\n</blockquote>\n<p><strong>Q5： <code>absent()</code>  有什么用？</strong></p>\n<blockquote>\n<p>检测 &quot;指标完全消失&quot; 的情况。有数据返回空，无数据返回 1。因为普通表达式在指标消失时返回空结果，告警不会触发，而 &quot;Exporter 挂了&quot; 恰恰是最需要告警的场景。</p>\n</blockquote>\n<p><strong>Q6： <code>&gt; 80</code>  和  <code>&gt; bool 80</code>  有什么区别？</strong></p>\n<blockquote>\n<p><code>&gt; 80</code>  是<strong>过滤</strong>：只保留满足条件的序列，不满足的直接从结果中消失。<br />\n <code>&gt; bool 80</code>  是<strong>转换</strong>：保留所有序列，满足的返回 1，不满足的返回 0，从而形成一条新的 0/1 时间序列。适合画状态图和做计数。</p>\n</blockquote>\n<p><strong>Q7：算占比时经常没结果，怎么排查？</strong></p>\n<blockquote>\n<p>九成是<strong>分子分母聚合粒度不一致</strong>：一边带多个标签、一边被  <code>sum()</code>  清空，导致两边标签集对不上、无法匹配。解决方法是两边都用相同维度聚合（如都  <code>sum()</code> ），或者用  <code>ignoring(...)</code>  /  <code>group_left</code>  明确匹配规则。</p>\n</blockquote>\n<hr />\n<h2 id=\"311-动手实验\"><a class=\"anchor\" href=\"#311-动手实验\">#</a> 3.11　动手实验</h2>\n<h3 id=\"实验一-类型识别训练\"><a class=\"anchor\" href=\"#实验一-类型识别训练\">#</a> 实验一　类型识别训练</h3>\n<p>打开  <code>http://&lt;node&gt;:9100/metrics</code> ，找出下面这些指标，判断类型并写出正确的查询写法：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">指标</th>\n<th style=\"text-align:left\">类型</th>\n<th style=\"text-align:left\">正确写法</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>node_cpu_seconds_total</code></td>\n<td style=\"text-align:left\">?</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_memory_MemAvailable_bytes</code></td>\n<td style=\"text-align:left\">?</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_filesystem_size_bytes</code></td>\n<td style=\"text-align:left\">?</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_load1</code></td>\n<td style=\"text-align:left\">?</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_boot_time_seconds</code></td>\n<td style=\"text-align:left\">?</td>\n<td style=\"text-align:left\">?</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>参考答案要点： <code>cpu_seconds_total</code>  是 Counter → 配  <code>rate</code> ； <code>MemAvailable</code>  是 Gauge → 直接算比例； <code>filesystem_size</code>  是 Gauge → 算使用率； <code>load1</code>  是 Gauge → 直接画或  <code>avg_over_time</code> ； <code>boot_time</code>  是 Gauge（但语义是时间戳）→ 配  <code>time()</code>  相减。</p>\n</blockquote>\n<h3 id=\"实验二-写出五个业务指标\"><a class=\"anchor\" href=\"#实验二-写出五个业务指标\">#</a> 实验二　写出五个业务指标</h3>\n<p>在 Graph 页面依次跑通，并解释每一步：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 单位换算：可用内存（MB）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>node_memory_MemAvailable_bytes <span class=\"token operator\">/</span> <span class=\"token number\">1024</span> <span class=\"token operator\">/</span> <span class=\"token number\">1024</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2. 可用内存百分比</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>node_memory_MemAvailable_bytes <span class=\"token operator\">/</span> node_memory_MemTotal_bytes <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 3. 内存使用率 > 70% 的主机（过滤）</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token punctuation\">(</span><span class=\"token number\">1</span> <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes <span class=\"token operator\">/</span> node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span> <span class=\"token operator\">></span> <span class=\"token number\">70</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 4. 同上，但输出 0/1（转换）</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token punctuation\">(</span><span class=\"token number\">1</span> <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes <span class=\"token operator\">/</span> node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span> <span class=\"token operator\">></span> bool <span class=\"token number\">70</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token comment\"># 5. 根分区使用率</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token punctuation\">(</span>node_filesystem_size_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mountpoint</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/\"</span><span class=\"token punctuation\">&#125;</span></span> <span class=\"token operator\">-</span> node_filesystem_free_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mountpoint</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token operator\">/</span> node_filesystem_size_bytes<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mountpoint</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/\"</span><span class=\"token punctuation\">&#125;</span></span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr></table></figure><p><strong>思考题</strong>：第 3 条和第 4 条的结果有什么不同？分别在什么场景下用？</p>\n<h3 id=\"实验三-rate-vs-irate-的肉眼对比\"><a class=\"anchor\" href=\"#实验三-rate-vs-irate-的肉眼对比\">#</a> 实验三　 <code>rate</code>  vs  <code>irate</code>  的肉眼对比</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 制造流量尖峰：平稳访问 → 突然猛刷</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">while</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">do</span> <span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://<span class=\"token operator\">&lt;</span>your-app<span class=\"token operator\">></span>:8001/metrics <span class=\"token operator\">></span> /dev/null<span class=\"token punctuation\">;</span> <span class=\"token function\">sleep</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">done</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 另一个终端执行 \"暴刷\"</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token keyword\">while</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">do</span> <span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://<span class=\"token operator\">&lt;</span>your-app<span class=\"token operator\">></span>:8001/metrics <span class=\"token operator\">></span> /dev/null<span class=\"token punctuation\">;</span> <span class=\"token keyword\">done</span></pre></td></tr></table></figure><p>在 Grafana 同一个面板上画两条曲线：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">rate</span><span class=\"token punctuation\">(</span>request_count_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">1m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">irate</span><span class=\"token punctuation\">(</span>request_count_total<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">1m</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><p><strong>观察</strong>：哪条曲线更早反映出暴刷？哪条更平滑？<strong>把这幅图记在脑子里，以后选函数就不会错。</strong></p>\n<h3 id=\"实验四-聚合练习\"><a class=\"anchor\" href=\"#实验四-聚合练习\">#</a> 实验四　聚合练习</h3>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 数主机数</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">count</span><span class=\"token punctuation\">(</span>node_os_version<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2. 按系统版本分组统计</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token keyword\">count_values</span><span class=\"token punctuation\">(</span>\"os_version\"<span class=\"token punctuation\">,</span> node_os_version<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 3. 每台主机的内存总量</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 4. 全部主机内存总和</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>node_memory_MemTotal_bytes<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token comment\"># 5. 每台主机的 CPU 核心数</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token keyword\">count</span><span class=\"token punctuation\">(</span>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"system\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">by</span> <span class=\"token vector-match\"><span class=\"token punctuation\">(</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">)</span></span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token comment\"># 6. 内存占用最多的前 3 台</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token keyword\">topk</span><span class=\"token punctuation\">(</span><span class=\"token number\">3</span><span class=\"token punctuation\">,</span> node_memory_MemTotal_bytes <span class=\"token operator\">-</span> node_memory_MemAvailable_bytes<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token comment\"># 7. /metrics 接口占总请求的百分比</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre><span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/metrics\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">100</span></pre></td></tr></table></figure><h3 id=\"实验五-故意犯错很重要\"><a class=\"anchor\" href=\"#实验五-故意犯错很重要\">#</a> 实验五　故意犯错（很重要）</h3>\n<p>依次执行下面的错误写法，<strong>把报错信息抄下来</strong>：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ① 范围向量直接画图</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>node_load1<span class=\"token context-range\"><span class=\"token punctuation\">[</span><span class=\"token range-duration number\">5m</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># ② 正则没写 .*</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>node_cpu_seconds_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">mode</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\"idle\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># ③ 全空标签（应被拒绝）</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=~</span><span class=\"token label-value attr-value\">\".*\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># ④ 占比分子分母粒度不同</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">code</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"200\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/-/reload\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token operator\">/</span> <span class=\"token keyword\">sum</span><span class=\"token punctuation\">(</span>prometheus_http_requests_total<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">handler</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"/-/ready\"</span><span class=\"token punctuation\">,</span> <span class=\"token label-key attr-name\">instance</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"localhost:9090\"</span><span class=\"token punctuation\">&#125;</span></span><span class=\"token punctuation\">)</span></pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>认得报错，比背对语法更有价值。</strong> 真实故障现场，你看到的一定是报错信息。</p>\n</blockquote>\n<hr />\n<h2 id=\"312-下章预告\"><a class=\"anchor\" href=\"#312-下章预告\">#</a> 3.12　下章预告</h2>\n<p>PromQL 会写了，但还有两个 &quot;咽不下去&quot; 的问题：</p>\n<ol>\n<li><strong>业务指标从哪来？</strong> 公司自研的 Java / Python 程序，既没有  <code>/metrics</code> ，也没有现成 Exporter——<strong> 只能自己写一个</strong>。</li>\n<li><strong>标签为什么会错？</strong> 明明采集到了，Grafana 面板却是空的；想删掉没用的指标却不知道从哪下手。</li>\n</ol>\n<p>下一章解决：</p>\n<ul>\n<li><strong>用 Python / Go 亲手写一个 Exporter</strong>（40 行代码，看得懂就能改）</li>\n<li><strong>Grafana 面板自己动手做</strong>（不再依赖别人的模板）</li>\n<li><strong>标签的完整生命周期</strong>： <code>__address__</code> 、 <code>__meta_*</code>  是怎么一路变成  <code>instance</code>  的</li>\n<li><strong> <code>relabel_configs</code>  与  <code>metric_relabel_configs</code> </strong>：抓取前 vs 抓取后，差别到底在哪</li>\n<li><strong>七个标签改写实战案例</strong>（含讲师在课堂上改四遍的那个经典例子）</li>\n<li><strong>记录规则</strong>：给长表达式起个别名，还能顺便提速</li>\n</ul>\n<p><strong>本章作业</strong>：把 &quot;七条必须带走的知识&quot; 背下来，并且能<strong>不看笔记</strong>写出 CPU 使用率和内存使用率两条表达式。这两条是运维面试的 &quot;入场券&quot;。</p>\n",
            "tags": [
                "Prometheus"
            ]
        },
        {
            "id": "http://blog.jaxxwang.cn/posts/3486386405.html",
            "url": "http://blog.jaxxwang.cn/posts/3486386405.html",
            "title": "02 部署与点亮：让 Prometheus 真正跑起来",
            "date_published": "2026-10-23T16:00:00.000Z",
            "content_html": "<h1 id=\"第-2-章-部署与点亮让-prometheus-真正跑起来\"><a class=\"anchor\" href=\"#第-2-章-部署与点亮让-prometheus-真正跑起来\">#</a> 第 2 章　部署与点亮：让 Prometheus 真正跑起来</h1>\n<blockquote>\n<p><strong>本章导读</strong></p>\n<p>第 1 章我们讲了架构，但架构是 &quot;纸上的图&quot;。本章开始动手，把图上的每一个方框都变成一台机器上的一个进程。</p>\n<p>这一章信息密度很高，涉及五个软件的安装、一份配置文件的逐行讲解、以及<strong>六个真实踩过的坑</strong>。请务必不要跳过 &quot;故障现场&quot; 这类小节 ——<strong> 面试官不问你装成功过什么，只问你出过错之后怎么定位的。</strong></p>\n<p>一句话总结本章目标：<strong>把 9090（Prometheus）、9100（Node Exporter）、3000（Grafana）、9091（Pushgateway）这四个端口全部点亮，并且能在 Grafana 上看到四台主机的 CPU 曲线。</strong></p>\n</blockquote>\n<p><strong>学习目标</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">序号</th>\n<th style=\"text-align:left\">学完本章，你应当能够</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1</td>\n<td style=\"text-align:left\">独立完成 Prometheus Server 的二进制安装，并写出规范的 systemd 服务单元</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">2</td>\n<td style=\"text-align:left\">解释  <code>--web.enable-lifecycle</code>  的作用与<strong>安全风险</strong>，说明生产环境为何要禁用</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">3</td>\n<td style=\"text-align:left\">逐行读懂  <code>prometheus.yml</code>  的四段式结构，独立新增一个采集 job</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">4</td>\n<td style=\"text-align:left\">用  <code>promtool</code>  做配置语法检查，并说清 &quot;不重启生效&quot; 的三种方式</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">5</td>\n<td style=\"text-align:left\">用 Docker / Docker Compose 跑起 Prometheus，并正确处理配置与数据两个持久化问题</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">6</td>\n<td style=\"text-align:left\">在任意节点上部署 Node Exporter，并让 Prometheus 采集到它</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">7</td>\n<td style=\"text-align:left\">用 &quot;五步法&quot; 排查 &quot;目标抓不到数据&quot; 的故障</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">8</td>\n<td style=\"text-align:left\">完成 Grafana 的数据源配置与社区 Dashboard 导入，并解释 &quot;监控 Grafana 自己为什么绕一圈&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">9</td>\n<td style=\"text-align:left\">说清 Pushgateway 的适用场景、工作原理与四个固有缺陷</td>\n</tr>\n</tbody>\n</table>\n<hr />\n<h2 id=\"21-开工之前先把拼图摆好\"><a class=\"anchor\" href=\"#21-开工之前先把拼图摆好\">#</a> 2.1　开工之前：先把拼图摆好</h2>\n<h3 id=\"211-五个软件各管一段\"><a class=\"anchor\" href=\"#211-五个软件各管一段\">#</a> 2.1.1　五个软件，各管一段</h3>\n<p>第 1 章我们列过组件职责表，现在把它落成 &quot;要装什么&quot;：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">软件</th>\n<th style=\"text-align:left\">默认端口</th>\n<th style=\"text-align:left\">一句话职责</th>\n<th style=\"text-align:left\">类比 Zabbix</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Prometheus Server</strong></td>\n<td style=\"text-align:left\">9090</td>\n<td style=\"text-align:left\">拉取指标 + 内置 TSDB 存储 + 规则计算</td>\n<td style=\"text-align:left\"><code>zabbix-server</code>  + 数据库</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Node Exporter</strong></td>\n<td style=\"text-align:left\">9100</td>\n<td style=\"text-align:left\">把本机的 CPU / 内存 / 磁盘 / 网络指标用 HTTP 暴露出来</td>\n<td style=\"text-align:left\"><strong> <code>zabbix-agent</code> </strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Grafana</strong></td>\n<td style=\"text-align:left\">3000</td>\n<td style=\"text-align:left\">把数据画成漂亮的图</td>\n<td style=\"text-align:left\"><code>zabbix-web</code> （但强太多）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Alertmanager</strong></td>\n<td style=\"text-align:left\">9093</td>\n<td style=\"text-align:left\">接收告警、去重、分组、路由、发送</td>\n<td style=\"text-align:left\">内置告警动作（本章不展开）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Pushgateway</strong></td>\n<td style=\"text-align:left\">9091</td>\n<td style=\"text-align:left\">给 &quot;抓不到&quot; 的瞬时指标当<strong>中转代理</strong></td>\n<td style=\"text-align:left\"><strong> <code>zabbix-proxy</code> </strong>（角色相近）</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>📌 <strong>一个重要认知</strong>：Prometheus Server <strong>只做两件事</strong> —— 采集、存储。它自带的那个 Web 界面（9090）<strong>只用于调试查询</strong>，从来没打算让你拿它当监控大屏。所以 &quot;要装 Grafana&quot; 不是可选项，而是必选项。</p>\n</blockquote>\n<h3 id=\"212-部署拓扑谁装在哪\"><a class=\"anchor\" href=\"#212-部署拓扑谁装在哪\">#</a> 2.1.2　部署拓扑：谁装在哪</h3>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">flowchart</span> TB</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token keyword\">subgraph</span> MON<span class=\"token text string\">[\"监控服务器（可合设，也可分离部署）\"]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>        <span class=\"token keyword\">direction</span> LR</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>        P<span class=\"token text string\">[\"Prometheus Server&lt;br/>:9090\"]</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>        G<span class=\"token text string\">[\"Grafana&lt;br/>:3000\"]</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>        PG<span class=\"token text string\">[\"Pushgateway&lt;br/>:9091\"]</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>        P <span class=\"token arrow operator\">&lt;--></span><span class=\"token label property\">|PromQL 查询|</span> G</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>        PG <span class=\"token arrow operator\">--></span><span class=\"token label property\">|被 Pull|</span> P</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token keyword\">end</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token keyword\">subgraph</span> NODES<span class=\"token text string\">[\"被监控节点\"]</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>        <span class=\"token keyword\">direction</span> LR</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>        N1<span class=\"token text string\">[\"node101&lt;br/>Node Exporter :9100\"]</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>        N2<span class=\"token text string\">[\"node102&lt;br/>Node Exporter :9100\"]</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>        N3<span class=\"token text string\">[\"node103&lt;br/>Node Exporter :9100\"]</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>        N4<span class=\"token text string\">[\"监控服务器自己&lt;br/>Node Exporter :9100\"]</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    <span class=\"token keyword\">end</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    N1 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull /metrics|</span> P</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    N2 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull /metrics|</span> P</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    N3 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull /metrics|</span> P</pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    N4 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|Pull /metrics|</span> P</pre></td></tr></table></figure><p><strong>三条部署原则</strong>（经验，不是规定）：</p>\n<ol>\n<li><strong>Prometheus / Grafana / Pushgateway 可以装在同一台</strong>（实验环境、小规模环境），也可以分开装。分开装的好处是<strong>性能互不干扰</strong>、故障不连带。</li>\n<li><strong>Node Exporter 必须装在被监控的每一台机器上</strong>，一台不能少 —— 包括 Prometheus 自己那台，因为<strong>监控系统本身也需要被监控</strong>。</li>\n<li>生产环境请把  <code>--storage.tsdb.path</code> （数据目录）<strong>独立挂一个分区</strong>，避免数据把根分区写满导致整机不可用。</li>\n</ol>\n<h3 id=\"213-版本怎么选先看兼容性\"><a class=\"anchor\" href=\"#213-版本怎么选先看兼容性\">#</a> 2.1.3　版本怎么选：先看兼容性</h3>\n<p>监控栈是 &quot;多组件协同&quot;，版本乱配最容易出问题。下面是一套经过验证、兼容性良好的企业级组合：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">组件</th>\n<th style=\"text-align:left\">推荐版本</th>\n<th style=\"text-align:left\">示例文件</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">Prometheus</td>\n<td style=\"text-align:left\"><strong>2.53.x</strong></td>\n<td style=\"text-align:left\"><code>prometheus-2.53.2.linux-amd64.tar.gz</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">Alertmanager</td>\n<td style=\"text-align:left\">0.27.x</td>\n<td style=\"text-align:left\"><code>alertmanager-0.27.0.linux-amd64.tar.gz</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">Node Exporter</td>\n<td style=\"text-align:left\">1.8.x</td>\n<td style=\"text-align:left\"><code>node_exporter-1.8.2.linux-amd64.tar.gz</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">Grafana</td>\n<td style=\"text-align:left\"><strong>11.x</strong></td>\n<td style=\"text-align:left\"><code>grafana-enterprise_11.2.0_amd64.deb</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">Pushgateway</td>\n<td style=\"text-align:left\">1.10.x</td>\n<td style=\"text-align:left\"><code>pushgateway-1.10.0.linux-amd64.tar.gz</code></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ <strong>关于 2.x 还是 3.x</strong></p>\n<p>Prometheus 已经发布了 3.x，并且提供了 <strong>LTS（长期支持）</strong> 版本。课程的演示环境用的是 <strong>3.5.0 LTS</strong>，功能上比 2.x 多了些改进。<br />\n但要注意：<strong>大量企业存量环境仍然是 2.53.x</strong>，生态里的部分 Exporter、Dashboard、规则文件是按 2.x 写的。所以：</p>\n<ul>\n<li><strong>新环境可以上 3.x LTS</strong>；</li>\n<li><strong>接手老环境时不要手贱升级主版本</strong>；</li>\n<li><strong>预发布版（rc /beta/ 带 -rc 后缀）一律不要装到生产</strong>，它不是给生产用的。</li>\n</ul>\n</blockquote>\n<h3 id=\"214-六种部署方式\"><a class=\"anchor\" href=\"#214-六种部署方式\">#</a> 2.1.4　六种部署方式</h3>\n<p>官方文档：<a href=\"https://prometheus.io/docs/prometheus/latest/installation/\">https://prometheus.io/docs/prometheus/latest/installation/</a></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">方式</th>\n<th style=\"text-align:left\">适用场景</th>\n<th style=\"text-align:left\">一句评价</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>包安装</strong>（apt /yum）</td>\n<td style=\"text-align:left\">快速验证、小规模</td>\n<td style=\"text-align:left\">最省事，但版本由仓库决定，往往偏旧</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>二进制安装</strong></td>\n<td style=\"text-align:left\"><strong>生产主力</strong>（学完再看第 4 行）</td>\n<td style=\"text-align:left\">版本可控、零依赖，<strong>必须掌握</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Ansible</strong></td>\n<td style=\"text-align:left\">批量部署几十上百台</td>\n<td style=\"text-align:left\">有现成 Role，改改变量就行</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Docker</strong></td>\n<td style=\"text-align:left\">快速起、CI 环境</td>\n<td style=\"text-align:left\">一条命令，注意挂载</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Docker Compose</strong></td>\n<td style=\"text-align:left\">一键起整套监控栈</td>\n<td style=\"text-align:left\">适合实验与中小规模</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Kubernetes</strong></td>\n<td style=\"text-align:left\">云原生环境</td>\n<td style=\"text-align:left\">用 kube-prometheus / Operator / Helm</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>💡 <strong>学习路径建议</strong>：<strong>先二进制，再容器。</strong><br />\n你只有先在裸机上手动装过一遍，才知道容器里那个  <code>-v</code>  到底在挂什么、那个  <code>--config.file</code>  到底指向哪。反过来学，你会永远停留在 &quot;复制粘贴能跑，坏了不会修&quot; 的层次。</p>\n</blockquote>\n<hr />\n<h2 id=\"22-方式一包安装5-分钟上手\"><a class=\"anchor\" href=\"#22-方式一包安装5-分钟上手\">#</a> 2.2　方式一：包安装（5 分钟上手）</h2>\n<h3 id=\"221-ubuntu-debian\"><a class=\"anchor\" href=\"#221-ubuntu-debian\">#</a> 2.2.1　Ubuntu / Debian</h3>\n<p>Ubuntu 的官方仓库里<strong>直接带 Prometheus 包</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 先看看仓库里有哪个版本</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">apt</span> list prometheus</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># ubuntu 22.04</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># prometheus/jammy 2.31.2+ds1-1ubuntu1 amd64</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># ubuntu 24.04</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># prometheus/noble-security 2.45.3+ds-2ubuntu0.2 amd64</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token function\">apt</span> <span class=\"token parameter variable\">-y</span> <span class=\"token function\">install</span> prometheus</pre></td></tr></table></figure><p>装完<strong>服务自动启动</strong>，并且 —— 这是很多人不知道的一点 ——<strong> 包里自带了一个 Node Exporter</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl status prometheus</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl status prometheus-node-exporter.service</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>ss <span class=\"token parameter variable\">-ntlp</span> <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> prometheus</pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># LISTEN 0 4096 *:9090 users:((\"prometheus\",pid=2969,fd=4))</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># LISTEN 0 4096 *:9100 users:((\"prometheus-node\",pid=2195,fd=3))</span></pre></td></tr></table></figure><p>所以你会看到 <strong>9090 和 9100 同时被监听</strong>，进程名分别是  <code>/usr/bin/prometheus</code>  和  <code>/usr/bin/prometheus-node-exporter</code> 。</p>\n<blockquote>\n<p>💡 <strong>包安装的价值</strong>：适合 &quot;我今天就想看一眼 Prometheus 长啥样&quot;。它的配置文件在  <code>/etc/prometheus/prometheus.yml</code> ，数据目录在  <code>/var/lib/prometheus</code> ，都由打包者安排好了，你不用操心。</p>\n</blockquote>\n<h3 id=\"222-rhel-rocky-centos\"><a class=\"anchor\" href=\"#222-rhel-rocky-centos\">#</a> 2.2.2　RHEL / Rocky / CentOS</h3>\n<p>RHEL 系<strong>默认没有</strong> Prometheus 仓库，需要自己配  <code>yum</code>  repo（packagecloud 提供）：</p>\n<figure class=\"highlight ini\"><figcaption data-lang=\"ini\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">prometheus</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key attr-name\">name</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">prometheus</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key attr-name\">baseurl</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">https://packagecloud.io/prometheus-rpm/release/el/$releasever/$basearch</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token key attr-name\">repo_gpgcheck</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">1</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token key attr-name\">enabled</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">1</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key attr-name\">gpgkey</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">https://packagecloud.io/prometheus-rpm/release/gpgkey</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>       https://raw.githubusercontent.com/lest/prometheus-rpm/master/RPM-GPG-KEY-prometheus-rpm</pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token key attr-name\">gpgcheck</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">1</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token key attr-name\">metadata_expire</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">300</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>包安装的两大局限</strong>（也正是生产偏爱二进制的原因）：</p>\n<ol>\n<li><strong>版本被仓库锁死</strong>，仓库里是什么版本你就用什么版本，通常落后官方好几个小版本，甚至大版本；</li>\n<li><strong>目录布局固定</strong>，想自定义数据目录、想和别的实例并存，就很别扭。</li>\n</ol>\n</blockquote>\n<hr />\n<h2 id=\"23-方式二二进制安装生产标准做法\"><a class=\"anchor\" href=\"#23-方式二二进制安装生产标准做法\">#</a> 2.3　方式二：二进制安装（生产标准做法）</h2>\n<h3 id=\"231-为什么-go-程序装起来这么简单\"><a class=\"anchor\" href=\"#231-为什么-go-程序装起来这么简单\">#</a> 2.3.1　为什么 Go 程序装起来这么简单</h3>\n<p>Prometheus 全套组件都是 <strong>Go</strong> 写的，编译产物是<strong>静态链接的单一二进制文件</strong>。这意味着：</p>\n<ul>\n<li><strong>零运行时依赖</strong> —— 不需要 Python、不需要 JDK、不需要 libc 的某个版本；</li>\n<li><strong>拷到任何 Linux 上都能跑</strong> ——Ubuntu、Rocky、Alpine 都一样；</li>\n<li><strong>镜像可以做得很小</strong> —— 甚至可以  <code>FROM scratch</code> 。</li>\n</ul>\n<p>验证一下就明白了：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>ldd prometheus promtool</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># prometheus:</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\">#     不是动态可执行文件</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># promtool:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\">#     不是动态可执行文件</span></pre></td></tr></table></figure><p>&quot;不是动态可执行文件&quot;，就是<strong>静态编译</strong>的意思。</p>\n<h3 id=\"232-下载与解压\"><a class=\"anchor\" href=\"#232-下载与解压\">#</a> 2.3.2　下载与解压</h3>\n<p>官方下载：<a href=\"https://prometheus.io/download/\">https://prometheus.io/download/</a><br />\n 历史版本：<a href=\"https://github.com/prometheus/prometheus/releases\">https://github.com/prometheus/prometheus/releases</a></p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token builtin class-name\">cd</span> /usr/local</pre></td></tr><tr><td data-num=\"2\"></td><td><pre></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">wget</span> https://github.com/prometheus/prometheus/releases/download/v2.53.2/prometheus-2.53.2.linux-amd64.tar.gz</pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token function\">tar</span> xf prometheus-2.53.2.linux-amd64.tar.gz</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 建软链接，去掉版本号，将来升级只改软链</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token function\">ln</span> <span class=\"token parameter variable\">-s</span> prometheus-2.53.2.linux-amd64 prometheus</pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>软链接的价值</strong>：以后从 2.53.2 升级到 2.53.3，只需要解压新目录、把软链指过去、重启服务。所有配置和 systemd 单元里的路径<strong>一个字都不用改</strong>。这是运维的标准习惯。</p>\n</blockquote>\n<blockquote>\n<p>⚠️ <strong>国内下载慢的老问题</strong>：GitHub 直连经常断。稳妥做法是<strong>一次性把安装包下载好，随安装脚本一起分发，做离线安装</strong> —— 生产环境装东西，永远不要指望 &quot;现场 wget 能成功&quot;。</p>\n</blockquote>\n<p>解压后目录内容：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>/usr/local/prometheus/</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>├── console_libraries/      # 内置控制台模板的库</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>├── consoles/               # 内置控制台模板</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>├── LICENSE                 # 可以删</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>├── NOTICE                  # 可以删</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>├── prometheus              # ★ 主程序</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>├── prometheus.yml          # ★ 默认配置</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>└── promtool                # ★ 运维神器（语法检查/查询调试/TSDB 工具）</pre></td></tr></table></figure><h3 id=\"233-目录规划与权限\"><a class=\"anchor\" href=\"#233-目录规划与权限\">#</a> 2.3.3　目录规划与权限</h3>\n<p>原始包里的文件平铺在一起，不够规整。按 &quot;程序 / 配置 / 数据&quot; 分离：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token builtin class-name\">cd</span> /usr/local/prometheus</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">mkdir</span> bin conf data</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token function\">mv</span> prometheus promtool bin/</pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">mv</span> prometheus.yml conf/</pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 创建专用的服务账号：不要用 root，也不要让它能登录 shell</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token function\">useradd</span> <span class=\"token parameter variable\">-r</span> <span class=\"token parameter variable\">-s</span> /sbin/nologin prometheus</pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 统一属主属组</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token function\">chown</span> <span class=\"token parameter variable\">-R</span> prometheus:prometheus /usr/local/prometheus/</pre></td></tr></table></figure><p>最终结构：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>/usr/local/prometheus/</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>├── bin/       prometheus, promtool</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>├── conf/      prometheus.yml</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>└── data/      ← TSDB 数据（不建也行，首次启动会自动创建）</pre></td></tr></table></figure><blockquote>\n<p>📌  <code>-r</code>  表示<strong>系统账号</strong>（UID 较小、默认不建家目录）， <code>-s /sbin/nologin</code>  表示<strong>禁止交互登录</strong>。服务账号就该是这种 &quot;只存在、不登录&quot; 的形态，安全上更干净。</p>\n</blockquote>\n<p>再把  <code>bin</code>  加到 PATH，省得每次写全路径：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">cat</span> <span class=\"token operator\">></span> /etc/profile.d/prometheus.sh <span class=\"token operator\">&lt;&lt;</span><span class=\"token string\">'EOF'</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>export PROMETHEUS_HOME=/usr/local/prometheus</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>export PATH=$&#123;PROMETHEUS_HOME&#125;/bin:$PATH</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>EOF</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token builtin class-name\">source</span> /etc/profile</pre></td></tr></table></figure><h3 id=\"234-第一次启动先让它裸跑一下\"><a class=\"anchor\" href=\"#234-第一次启动先让它裸跑一下\">#</a> 2.3.4　第一次启动：先让它 &quot;裸跑&quot; 一下</h3>\n<p>主程序参数很多，但初始化阶段只需要关心两个：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>prometheus <span class=\"token parameter variable\">--help</span> <span class=\"token operator\">|</span> <span class=\"token function\">head</span> <span class=\"token parameter variable\">-20</span></pre></td></tr></table></figure><table>\n<thead>\n<tr>\n<th style=\"text-align:left\">参数</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">默认值</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>--config.file</code></td>\n<td style=\"text-align:left\">配置文件路径</td>\n<td style=\"text-align:left\"><code>prometheus.yml</code> （<strong>相对于当前工作目录</strong>）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--web.listen-address</code></td>\n<td style=\"text-align:left\">UI / API 监听地址</td>\n<td style=\"text-align:left\"><code>0.0.0.0:9090</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--storage.tsdb.path</code></td>\n<td style=\"text-align:left\">TSDB 数据目录</td>\n<td style=\"text-align:left\"><code>data/</code></td>\n</tr>\n</tbody>\n</table>\n<p><strong>先什么都不带，直接跑一次</strong>，你会看到报错：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token builtin class-name\">cd</span> /usr/local/prometheus/bin</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>./prometheus</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># level=error msg=\"Error loading config\" err=\"open prometheus.yml: no such file or directory\"</span></pre></td></tr></table></figure><blockquote>\n<p>🧠 <strong>为什么？</strong> 因为默认配置文件名是<strong>相对路径</strong>  <code>prometheus.yml</code> ，它在<strong>当前工作目录</strong>下找。而我们刚把配置文件挪到了  <code>conf/</code> 。</p>\n</blockquote>\n<p>那就在上层的<strong>工作目录</strong>里启动，把配置路径指过去：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token builtin class-name\">cd</span> /usr/local/prometheus</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>./bin/prometheus <span class=\"token parameter variable\">--config.file</span><span class=\"token operator\">=</span>conf/prometheus.yml</pre></td></tr></table></figure><p>起来了。此时浏览器访问  <code>http://&lt;IP&gt;:9090</code>  就能看到那个 &quot;简陋但够用&quot; 的 Web 界面。</p>\n<h3 id=\"235-故障现场一以-root-启动过一次之后再也起不来\"><a class=\"anchor\" href=\"#235-故障现场一以-root-启动过一次之后再也起不来\">#</a> 2.3.5　⭐ 故障现场一：以 root 启动过一次，之后再也起不来</h3>\n<p>这是<strong>初学者 90% 会踩、且完全不知道原因</strong>的坑。完整重现一遍：</p>\n<p><strong>现象</strong>：手动用  <code>root</code>  跑通了，然后删掉进程、改成 systemd 以  <code>prometheus</code>  用户启动，服务起不来。</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl start prometheus</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl status prometheus</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 一直 failed</span></pre></td></tr></table></figure><p><strong>排查过程</strong>（这才是重点）：</p>\n<ol>\n<li><strong>先看端口有没有起来</strong> —— <code>ss -ntlp | grep 9090</code> ，没有。</li>\n<li><strong>再看服务状态</strong> —— <code>systemctl status prometheus</code> ，只有一行 &quot;启动失败&quot;，信息不够。</li>\n<li><strong>看日志</strong> —— <code>journalctl -u prometheus -n 50 --no-pager</code> （或看  <code>/usr/local/prometheus/data</code>  同级目录下有没有生成日志文件），发现关键的一句：</li>\n</ol>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>msg=\"Error opening storage\" err=\"open /usr/local/prometheus/data/queries.active: permission denied\"</pre></td></tr></table></figure><ol start=\"4\">\n<li><strong>验证猜想</strong> —— <code>ls -l /usr/local/prometheus/data/</code> ，发现里面的文件属主是  <code>root:root</code> 。</li>\n</ol>\n<p><strong>根因</strong>：</p>\n<blockquote>\n<p>我第一次是<strong>用 root 身份手动启动</strong>的，Prometheus 在  <code>data/</code>  目录下自动创建了  <code>queries.active</code> 、 <code>lock</code> 、 <code>wal/</code>  等文件，<strong>属主全部是 root</strong>。<br />\n现在 systemd 以  <code>prometheus</code>  普通用户启动，去写这些 root 拥有的文件 ——<strong> 权限不足</strong>。</p>\n</blockquote>\n<p><strong>解决</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">chown</span> <span class=\"token parameter variable\">-R</span> prometheus:prometheus /usr/local/prometheus/</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># 特别是 data 目录，重新设一遍</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">chown</span> <span class=\"token parameter variable\">-R</span> prometheus:prometheus /usr/local/prometheus/data</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>systemctl restart prometheus</pre></td></tr></table></figure><blockquote>\n<p>⭐ <strong>这条经验请写进笔记</strong>：<br />\n<strong>调试阶段用哪个身份启动，生产就用哪个身份。</strong><br />\n不要图省事用 root 试跑 —— 它会污染数据目录、日志文件、以及你自己都没意识到的 PID 文件。<strong>&quot;先 root 试跑，再改普通用户&quot; 是典型的错误顺序。</strong></p>\n</blockquote>\n<h3 id=\"236-写-systemd-服务单元\"><a class=\"anchor\" href=\"#236-写-systemd-服务单元\">#</a> 2.3.6　写 systemd 服务单元</h3>\n<p>标准单元文件（Ubuntu 在  <code>/lib/systemd/system/</code> ，Rocky 在  <code>/usr/lib/systemd/system/</code> ，两者都兼容  <code>/etc/systemd/system/</code> ）：</p>\n<figure class=\"highlight ini\"><figcaption data-lang=\"ini\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Unit</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key attr-name\">Description</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">Prometheus Server</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key attr-name\">Documentation</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">https://prometheus.io/docs/introduction/overview/</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token key attr-name\">After</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">network.target</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Service</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key attr-name\">Restart</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">on-failure</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token key attr-name\">User</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">prometheus</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token key attr-name\">Group</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">prometheus</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token key attr-name\">WorkingDirectory</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/usr/local/prometheus/</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key attr-name\">ExecStart</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/usr/local/prometheus/bin/prometheus \\</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>          <span class=\"token key attr-name\">--config.file</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/usr/local/prometheus/conf/prometheus.yml</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token key attr-name\">ExecReload</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/bin/kill -HUP $MAINPID</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token key attr-name\">LimitNOFILE</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">65535</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Install</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token key attr-name\">WantedBy</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">multi-user.target</span></pre></td></tr></table></figure><p><strong>逐行解释，这几行每一行都有用：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">配置</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">为什么必须有</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>After=network.target</code></td>\n<td style=\"text-align:left\">在网络就绪后再启动</td>\n<td style=\"text-align:left\">否则开机可能先于网络起来，抓取全部失败</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>User</code>  /  <code>Group</code></td>\n<td style=\"text-align:left\">以专用账号运行</td>\n<td style=\"text-align:left\">最小权限原则，避免被拿下后拿整机</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>WorkingDirectory</code></td>\n<td style=\"text-align:left\">工作目录</td>\n<td style=\"text-align:left\"><strong>关键</strong>：决定了相对路径（ <code>data/</code> ）解析到哪里</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>ExecStart</code>  ...  <code>--config.file</code></td>\n<td style=\"text-align:left\">启动命令与配置路径</td>\n<td style=\"text-align:left\">用<strong>绝对路径</strong>，不依赖 PATH</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>ExecReload=/bin/kill -HUP $MAINPID</code></td>\n<td style=\"text-align:left\"><code>systemctl reload</code>  发 SIGHUP</td>\n<td style=\"text-align:left\">让<strong>不重启进程</strong>重载配置成为可能</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>LimitNOFILE=65535</code></td>\n<td style=\"text-align:left\">打开文件数上限</td>\n<td style=\"text-align:left\">TSDB 会打开大量 chunk 文件，默认 1024 不够。<strong>这是性能优化项</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>Restart=on-failure</code></td>\n<td style=\"text-align:left\">异常退出自动拉起</td>\n<td style=\"text-align:left\">提高可用性</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>WantedBy=multi-user.target</code></td>\n<td style=\"text-align:left\">允许开机自启</td>\n<td style=\"text-align:left\"><code>systemctl enable</code>  才有意义</td>\n</tr>\n</tbody>\n</table>\n<p>启用：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl daemon-reload</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl <span class=\"token builtin class-name\">enable</span> <span class=\"token parameter variable\">--now</span> prometheus.service</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>systemctl is-active prometheus</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>ss <span class=\"token parameter variable\">-ntlp</span> <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token number\">9090</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong> <code>LimitNOFILE</code>  到底影响什么？</strong><br />\n它的效果你<strong>能亲眼看到</strong> —— 访问  <code>http://&lt;IP&gt;:9090/metrics</code> ，搜索  <code>process_max_fds</code> ：</p>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>process_max_fds 6.5535e+04</pre></td></tr></table></figure><p>改一下 service 文件里的值（比如改成 66666），重启服务后再看，这个指标就跟着变了。<strong>&quot;配置文件的每一个数字，都会在某个指标里体现&quot;</strong>—— 这是理解监控系统的一个非常好的思维方式。</p>\n</blockquote>\n<h3 id=\"237-验证web-ui-的三个菜单\"><a class=\"anchor\" href=\"#237-验证web-ui-的三个菜单\">#</a> 2.3.7　验证：Web UI 的三个菜单</h3>\n<p>浏览器访问  <code>http://&lt;prometheus-ip&gt;:9090/</code> ，顶部菜单四项：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">菜单</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">你需要知道的</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Alerts</strong></td>\n<td style=\"text-align:left\">当前处于活动状态的告警</td>\n<td style=\"text-align:left\">显示由规则计算出的 pending /firing 告警</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Graph</strong></td>\n<td style=\"text-align:left\">查询与画图界面</td>\n<td style=\"text-align:left\"><strong>默认落地页</strong>，PromQL 就在这里写</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Status</strong></td>\n<td style=\"text-align:left\">各种运行状态</td>\n<td style=\"text-align:left\">排障时最常用，见下</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>Help</strong></td>\n<td style=\"text-align:left\">帮助与文档链接</td>\n<td style=\"text-align:left\">很少用</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Status 下的子菜单（排障必去）</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">子菜单</th>\n<th style=\"text-align:left\">内容</th>\n<th style=\"text-align:left\">典型用途</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>Runtime &amp; Build Information</code></td>\n<td style=\"text-align:left\">版本、启动时间、构建信息、内存等</td>\n<td style=\"text-align:left\">确认版本、确认服务是否刚重启</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>Command-Line Flags</code></td>\n<td style=\"text-align:left\">实际生效的启动参数</td>\n<td style=\"text-align:left\"><strong>确认 service 文件里写的参数真的生效了</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>Configuration</code></td>\n<td style=\"text-align:left\">当前生效的配置（YAML 原文）</td>\n<td style=\"text-align:left\"><strong>确认 reload 之后配置真的变了</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>Rules</code></td>\n<td style=\"text-align:left\">规则文件的加载与计算情况</td>\n<td style=\"text-align:left\">告警不触发时第一个该看的地方</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>Targets</code></td>\n<td style=\"text-align:left\">所有采集目标的健康状态</td>\n<td style=\"text-align:left\">⭐ <strong>抓不到数据时第一个该看的地方</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>Service Discovery</code></td>\n<td style=\"text-align:left\">服务发现得到的动态目标列表</td>\n<td style=\"text-align:left\">排查 K8s /file_sd 不生效</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ <strong>两个 &quot;只存在于内存&quot; 的认知</strong>：</p>\n<ol>\n<li><strong>Graph 页面里写的表达式，刷新就没了。</strong> 这就是为什么必须要有 Grafana—— 它负责把表达式 &quot;存下来&quot; 变成面板。</li>\n<li><strong>Targets 页面上的  <code>Last Scrape</code>  时间和  <code>State</code>  颜色</strong>，是你判断 &quot;数据到底有没有进来&quot; 最快的方式。绿色 UP = 抓到了；红色 DOWN = 抓不到。</li>\n</ol>\n</blockquote>\n<hr />\n<h2 id=\"24-管理-api-与-webenable-lifecycle-的安全陷阱\"><a class=\"anchor\" href=\"#24-管理-api-与-webenable-lifecycle-的安全陷阱\">#</a> 2.4　管理 API 与  <code>--web.enable-lifecycle</code>  的安全陷阱</h2>\n<h3 id=\"241-四个-api-端点\"><a class=\"anchor\" href=\"#241-四个-api-端点\">#</a> 2.4.1　四个 API 端点</h3>\n<p>Prometheus 提供了一组管理 API 用于自动化运维：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">端点</th>\n<th style=\"text-align:left\">方法</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">是否需要  <code>--web.enable-lifecycle</code></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>/-/healthy</code></td>\n<td style=\"text-align:left\">GET</td>\n<td style=\"text-align:left\">健康检查，通常恒返回 200</td>\n<td style=\"text-align:left\">❌ 不需要</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>/-/ready</code></td>\n<td style=\"text-align:left\">GET</td>\n<td style=\"text-align:left\">就绪检查，能响应查询后返回 200</td>\n<td style=\"text-align:left\">❌ 不需要</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>/-/reload</code></td>\n<td style=\"text-align:left\">POST / PUT</td>\n<td style=\"text-align:left\"><strong>重载配置文件</strong></td>\n<td style=\"text-align:left\">✅ <strong>需要</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>/-/quit</code></td>\n<td style=\"text-align:left\">POST / PUT</td>\n<td style=\"text-align:left\"><strong>关闭 Prometheus 进程</strong></td>\n<td style=\"text-align:left\">✅ <strong>需要</strong></td>\n</tr>\n</tbody>\n</table>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 健康 / 就绪：永远可用</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">curl</span> http://prom.example.com:9090/-/healthy</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># Prometheus Server is Healthy.</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">curl</span> http://prom.example.com:9090/-/ready</pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># Prometheus Server is Ready.</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># 重载 / 关闭：需要开启 lifecycle</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-X</span> POST http://prom.example.com:9090/-/reload</pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-X</span> POST http://prom.example.com:9090/-/quit</pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token comment\"># Requesting termination... Goodbye!</span></pre></td></tr></table></figure><p>未开启该选项时：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-X</span> POST http://prom.example.com:9090/-/quit</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># Lifecycle API is not enabled.</span></pre></td></tr></table></figure><h3 id=\"242-故障现场二我在另一台机器上一行命令关掉了你的监控\"><a class=\"anchor\" href=\"#242-故障现场二我在另一台机器上一行命令关掉了你的监控\">#</a> 2.4.2　⭐ 故障现场二：我在另一台机器上，一行命令关掉了你的监控</h3>\n<p>开  <code>--web.enable-lifecycle</code>  之后，会发生这样的事：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 注意：这是在【另一台无关的远程主机】上执行</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-X</span> POST http://10.0.0.100:9090/-/quit</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 服务直接退出</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>ss <span class=\"token parameter variable\">-ntlp</span> <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token number\">9090</span>        <span class=\"token comment\"># 端口没了</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>systemctl is-active prometheus  <span class=\"token comment\"># inactive</span></pre></td></tr></table></figure><p><strong>不需要任何认证，不需要登录服务器，只要能访问 9090 端口。</strong> 整个监控系统被一行 curl 干掉了。</p>\n<blockquote>\n<p>🚨 <strong>结论必须记住</strong>：<br />\n<strong> <code>--web.enable-lifecycle</code>  生产环境不要开。</strong></p>\n<p>它的收益是什么？—— 能通过 API 触发 reload。<br />\n但问题是：<strong>我们本来就有  <code>systemctl reload prometheus</code> </strong>（靠  <code>ExecReload</code>  发 SIGHUP），效果完全一样，还不需要暴露任何危险接口。</p>\n<p>我在很多人的 service 文件里见过这一行，他们<strong>大多不知道这行意味着 &quot;谁都能远程关掉你的监控&quot;</strong>。别做那个人。</p>\n</blockquote>\n<h3 id=\"243-重载配置的四种方式对比\"><a class=\"anchor\" href=\"#243-重载配置的四种方式对比\">#</a> 2.4.3　重载配置的四种方式对比</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">方式</th>\n<th style=\"text-align:left\">命令</th>\n<th style=\"text-align:left\">是否重启进程</th>\n<th style=\"text-align:left\">前提</th>\n<th style=\"text-align:left\">建议</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>systemd reload</strong></td>\n<td style=\"text-align:left\"><code>systemctl reload prometheus</code></td>\n<td style=\"text-align:left\">❌ 不重启</td>\n<td style=\"text-align:left\"><code>ExecReload</code>  配了  <code>kill -HUP</code></td>\n<td style=\"text-align:left\">⭐ <strong>生产首选</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">信号</td>\n<td style=\"text-align:left\"><code>kill -HUP &lt;pid&gt;</code></td>\n<td style=\"text-align:left\">❌ 不重启</td>\n<td style=\"text-align:left\">无</td>\n<td style=\"text-align:left\">手工排障可用</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">API reload</td>\n<td style=\"text-align:left\"><code>curl -X POST :9090/-/reload</code></td>\n<td style=\"text-align:left\">❌ 不重启</td>\n<td style=\"text-align:left\">必须开 lifecycle（<strong>不建议</strong>）</td>\n<td style=\"text-align:left\">不推荐</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">重启服务</td>\n<td style=\"text-align:left\"><code>systemctl restart prometheus</code></td>\n<td style=\"text-align:left\">✅ 重启</td>\n<td style=\"text-align:left\">无</td>\n<td style=\"text-align:left\">改了<strong>启动参数</strong>时才需要</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>📌 <strong>分清两类配置</strong>：</p>\n<ul>\n<li><strong>配置文件（ <code>prometheus.yml</code> ）</strong> 里的东西 → <strong>可以热加载</strong>；</li>\n<li><strong>命令行启动参数</strong>（如  <code>--storage.tsdb.path</code> 、 <code>--web.listen-address</code> ）→ <strong>必须重启</strong>才能生效。</li>\n</ul>\n<p>改了什么，就用对应的方式生效，不要图省事一律 restart。</p>\n</blockquote>\n<h3 id=\"244-顺带一提谁来监控-prometheus-自己\"><a class=\"anchor\" href=\"#244-顺带一提谁来监控-prometheus-自己\">#</a> 2.4.4　顺带一提：谁来监控 Prometheus 自己</h3>\n<p><code>/-/healthy</code>  和  <code>/-/ready</code>  的价值在于：<strong>它们让外部系统可以监控 Prometheus 本身</strong>。</p>\n<pre><code>Prometheus 监控万物  ——  但 Prometheus 挂了，谁来发现？\n</code></pre>\n<p>三种常见做法：</p>\n<ol>\n<li><strong>双机互监控</strong>：A 的 Prometheus 抓 B 的指标，B 的抓 A 的，任一方挂了另一方告警；</li>\n<li><strong>外部探活</strong>：另一个系统（Zabbix / 云监控 / 负载均衡健康检查）定时 curl  <code>/-/healthy</code> ；</li>\n<li><strong> <code>up</code>  指标自监控</strong>：用另一个 Prometheus 实例抓本实例的  <code>/metrics</code> ，看  <code>up&#123;job=&quot;prometheus&quot;&#125;</code> 。</li>\n</ol>\n<blockquote>\n<p>💡 回到第 1 章的比喻：<strong>警察管普通人，那谁管警察？</strong>—— 这既是技术问题，也是一个非常好的面试发散点。</p>\n</blockquote>\n<hr />\n<h2 id=\"25-常用启动参数与容量规划\"><a class=\"anchor\" href=\"#25-常用启动参数与容量规划\">#</a> 2.5　常用启动参数与容量规划</h2>\n<p>完整参数表：<a href=\"https://prometheus.io/docs/prometheus/latest/command-line/prometheus/\">https://prometheus.io/docs/prometheus/latest/command-line/prometheus/</a></p>\n<p>不过真正需要你关心的是下面这几个：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">参数</th>\n<th style=\"text-align:left\">默认值</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">调优建议</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>--config.file</code></td>\n<td style=\"text-align:left\"><code>prometheus.yml</code></td>\n<td style=\"text-align:left\">配置文件路径</td>\n<td style=\"text-align:left\">用绝对路径</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--web.listen-address</code></td>\n<td style=\"text-align:left\"><code>0.0.0.0:9090</code></td>\n<td style=\"text-align:left\">监听地址</td>\n<td style=\"text-align:left\">对外暴露时建议配合反向代理 + 认证</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--web.read-timeout</code></td>\n<td style=\"text-align:left\"><code>5m</code></td>\n<td style=\"text-align:left\">请求读超时，关闭空闲连接</td>\n<td style=\"text-align:left\">防止空闲连接堆满</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--web.max-connections</code></td>\n<td style=\"text-align:left\"><code>512</code></td>\n<td style=\"text-align:left\">最大并发连接数</td>\n<td style=\"text-align:left\">大屏轮询多时适当调大</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--storage.tsdb.path</code></td>\n<td style=\"text-align:left\"><code>data/</code></td>\n<td style=\"text-align:left\"><strong>TSDB 数据目录</strong></td>\n<td style=\"text-align:left\">⭐ <strong>独立分区</strong>，别和根分区放一起</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--storage.tsdb.retention.time</code></td>\n<td style=\"text-align:left\"><code>15d</code></td>\n<td style=\"text-align:left\">样本保留时长</td>\n<td style=\"text-align:left\">企业通常 <strong>15d</strong>；太长吃磁盘和内存，太短查不到历史</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--query.timeout</code></td>\n<td style=\"text-align:left\"><code>2m</code></td>\n<td style=\"text-align:left\">单次查询最长执行时间</td>\n<td style=\"text-align:left\">复杂 PromQL 多时可调大</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--query.max-concurrency</code></td>\n<td style=\"text-align:left\"><code>20</code></td>\n<td style=\"text-align:left\">最大并发查询数</td>\n<td style=\"text-align:left\">与 Grafana 面板数量相关</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--web.enable-lifecycle</code></td>\n<td style=\"text-align:left\"><code>false</code></td>\n<td style=\"text-align:left\">允许 API reload/quit</td>\n<td style=\"text-align:left\">🚨 <strong>生产保持 false</strong></td>\n</tr>\n</tbody>\n</table>\n<p><strong>保留期的取舍</strong>（面试常问）：</p>\n<p><span class=\"katex-display\"><span class=\"katex\"><span class=\"katex-mathml\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><semantics><mrow><mtext>磁盘占用</mtext><mo>≈</mo><mtext>活跃序列数</mtext><mo>×</mo><mtext>采样频率</mtext><mo>×</mo><mtext>保留时长</mtext><mo>×</mo><mtext>单点字节数</mtext></mrow><annotation encoding=\"application/x-tex\">\\text{磁盘占用} \\approx \\text{活跃序列数} \\times \\text{采样频率} \\times \\text{保留时长} \\times \\text{单点字节数}\n</annotation></semantics></math></span><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.68333em;vertical-align:0em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">磁盘占用</span></span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span><span class=\"mrel\">≈</span><span class=\"mspace\" style=\"margin-right:0.2777777777777778em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.76666em;vertical-align:-0.08333em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">活跃序列数</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">×</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.76666em;vertical-align:-0.08333em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">采样频率</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">×</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.76666em;vertical-align:-0.08333em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">保留时长</span></span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span><span class=\"mbin\">×</span><span class=\"mspace\" style=\"margin-right:0.2222222222222222em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.68333em;vertical-align:0em;\"></span><span class=\"mord text\"><span class=\"mord cjk_fallback\">单点字节数</span></span></span></span></span></span></p>\n<blockquote>\n<p GB=\"\">举例：10 万条活跃序列、每 15 秒采一次、保留 15 天、压缩后按 1.5 字节 / 点估算：<br />\n100000 \\times \\frac{86400}{15} \\times 15 \\times 1.5 \\approx 1.3\\ \\text</p>\n<p>注意：<strong>这个公式只用于量级估算</strong>。真实占用还要看标签基数、chunk 对齐、索引大小等。但把 &quot;序列数&quot; 和 &quot;采样频率&quot; 作为两个乘法因子放在分子上，这个直觉是对的 ——<strong> 序列爆炸和采集频率过高，是磁盘被打满的两大主因</strong>。</p>\n</blockquote>\n<hr />\n<h2 id=\"26-prometheusyml逐行读懂配置文件\"><a class=\"anchor\" href=\"#26-prometheusyml逐行读懂配置文件\">#</a> 2.6　 <code>prometheus.yml</code> ：逐行读懂配置文件</h2>\n<p>官方参考：<a href=\"https://prometheus.io/docs/prometheus/latest/configuration/configuration/\">https://prometheus.io/docs/prometheus/latest/configuration/configuration/</a></p>\n<h3 id=\"261-两类配置的分工\"><a class=\"anchor\" href=\"#261-两类配置的分工\">#</a> 2.6.1　两类配置的分工</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">配置方式</th>\n<th style=\"text-align:left\">存什么</th>\n<th style=\"text-align:left\">例子</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>命令行参数</strong></td>\n<td style=\"text-align:left\">不可变的系统级参数</td>\n<td style=\"text-align:left\">数据目录、保留期、监听地址</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>配置文件（YAML）</strong></td>\n<td style=\"text-align:left\">与 &quot;数据动态获取&quot; 相关的配置</td>\n<td style=\"text-align:left\">抓谁、怎么抓、告警规则、告警发往哪</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"262-默认配置的四段式结构\"><a class=\"anchor\" href=\"#262-默认配置的四段式结构\">#</a> 2.6.2　默认配置的四段式结构</h3>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">global</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token key atrule\">scrape_interval</span><span class=\"token punctuation\">:</span> 15s        <span class=\"token comment\"># 抓取间隔，默认 1m</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">evaluation_interval</span><span class=\"token punctuation\">:</span> 15s    <span class=\"token comment\"># 规则计算间隔，默认 1m</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token comment\"># scrape_timeout 默认取 global 默认值 10s，且不应超过 scrape_interval</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">alerting</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token key atrule\">alertmanagers</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span>                <span class=\"token comment\"># 这里留空，等第 6 章再填</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key atrule\">rule_files</span><span class=\"token punctuation\">:</span>                   <span class=\"token comment\"># 告警规则文件列表，先空着</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token comment\"># - \"rules/*.yml\"</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token key atrule\">scrape_configs</span><span class=\"token punctuation\">:</span>               <span class=\"token comment\"># ★ 最核心：监控谁</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"prometheus\"</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"localhost:9090\"</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure><p><strong>四大段各自的作用：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">段</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">本章是否要改</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>global</code></td>\n<td style=\"text-align:left\">全局默认值，被各 job 继承</td>\n<td style=\"text-align:left\">可能微调  <code>scrape_interval</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>alerting</code></td>\n<td style=\"text-align:left\">告警发给哪个 Alertmanager</td>\n<td style=\"text-align:left\">留空</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>rule_files</code></td>\n<td style=\"text-align:left\">外置规则文件（告警规则 / 记录规则）</td>\n<td style=\"text-align:left\">留空</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>scrape_configs</code></td>\n<td style=\"text-align:left\"><strong>采集目标列表</strong>（一组 job）</td>\n<td style=\"text-align:left\">⭐ <strong>本章重点</strong></td>\n</tr>\n</tbody>\n</table>\n<p>除此之外，还有<strong>扩展配置 8 项</strong>（ <code>tls_config</code> 、 <code>relabel_config</code> 、 <code>metric_relabel_configs</code> 、 <code>remote_write</code> 、 <code>remote_read</code> …）和<strong>平台集成配置 12 项</strong>（ <code>file_sd_config</code> 、 <code>dns_sd_config</code> 、 <code>consul_sd_config</code> 、 <code>kubernetes_sd_config</code> …），后面章节逐个展开。</p>\n<h3 id=\"263-scrape_configs-的结构\"><a class=\"anchor\" href=\"#263-scrape_configs-的结构\">#</a> 2.6.3　 <code>scrape_configs</code>  的结构</h3>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">scrape_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"&lt;job_name>\"</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">metrics_path</span><span class=\"token punctuation\">:</span> /metrics      <span class=\"token comment\"># 默认值，可省略</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token key atrule\">scheme</span><span class=\"token punctuation\">:</span> http                <span class=\"token comment\"># 默认值，可省略</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span> <span class=\"token string\">\"&lt;host_ip>:&lt;host_port>\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">...</span> <span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>      <span class=\"token key atrule\">labels</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">&lt;labelname></span><span class=\"token punctuation\">:</span> &lt;labelvalue<span class=\"token punctuation\">></span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">...</span> <span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><p><strong>三个概念对应第 1 章的知识点：</strong></p>\n<ul>\n<li>一个  <code>scrape_configs</code>  下可以有<strong>多个 job</strong>，<strong>job 就是分类</strong>（同一类指标的机器放一个 job）；</li>\n<li>一个 job 下的  <code>static_configs.targets</code>  里每一项，就是一个 <strong>instance（实例）</strong>，格式  <code>ip:port</code> ；</li>\n<li><code>labels</code>  是给这个 job 下所有目标<strong>附加的标签</strong>，可用于后续 PromQL 过滤。</li>\n</ul>\n<blockquote>\n<p>💡 <strong>给 job 命名的建议</strong>：起一个 &quot;<strong> 能看出这是什么东西</strong> &quot; 的名字，比如  <code>node_exporter</code> 、 <code>mysql</code> 、 <code>redis</code> 、 <code>nginx</code> 。这个名字会原封不动地出现在  <code>up&#123;job=&quot;...&quot;&#125;</code> 、Grafana 的变量下拉框、以及告警模板里。名字起得烂，后面到处难受。</p>\n</blockquote>\n<h3 id=\"264-故障现场三缩进错了targets-永远不生效\"><a class=\"anchor\" href=\"#264-故障现场三缩进错了targets-永远不生效\">#</a> 2.6.4　⭐ 故障现场三：缩进错了，targets 永远不生效</h3>\n<p>YAML 是<strong>缩进敏感</strong>的语言，而  <code>scrape_configs</code>  的结构是 &quot;列表套列表套字典&quot;，嵌套很深。典型错误：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ❌ 错误：targets 和 static_configs 不对齐</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'node_exporter'</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'10.0.0.101:9100'</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure><p>或者：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ❌ 错误：把 targets 写成了 static_configs 的兄弟</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'node_exporter'</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'10.0.0.101:9100'</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'10.0.0.102:9100'</span><span class=\"token punctuation\">]</span>     <span class=\"token comment\"># ← 这一行变成了一个新的 job（且没有 job_name）</span></pre></td></tr></table></figure><p><strong>后果</strong>： <code>promtool check config</code>  可能报错；也可能<strong>不报错但语义完全变了</strong> ——targets 变成了另一个匿名 job，或者根本没被解析。</p>\n<blockquote>\n<p>⭐ <strong>所以：改完配置，先检查语法，再 reload。</strong></p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>promtool check config /usr/local/prometheus/conf/prometheus.yml</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># Checking /usr/local/prometheus/conf/prometheus.yml</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\">#  SUCCESS: ... is valid prometheus config file syntax</span></pre></td></tr></table></figure><p>故意少写一个冒号试试，它会准确告诉你<strong>第几行</strong>出错 —— 这个反馈比 &quot;reload 之后没数据，然后你猜了半天&quot; 高效一百倍。</p>\n</blockquote>\n<h3 id=\"265-promtool被严重低估的运维工具\"><a class=\"anchor\" href=\"#265-promtool被严重低估的运维工具\">#</a> 2.6.5　 <code>promtool</code> ：被严重低估的运维工具</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>promtool <span class=\"token parameter variable\">--help</span></pre></td></tr></table></figure><table>\n<thead>\n<tr>\n<th style=\"text-align:left\">子命令</th>\n<th style=\"text-align:left\">用途</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>promtool check config &lt;file&gt;</code></td>\n<td style=\"text-align:left\">⭐ 检查配置语法与语义</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>promtool check rules &lt;file&gt;</code></td>\n<td style=\"text-align:left\">检查告警 / 记录规则文件</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>promtool query instant &lt;url&gt; &lt;expr&gt;</code></td>\n<td style=\"text-align:left\">命令行直接跑 PromQL，便于脚本化</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>promtool tsdb ...</code></td>\n<td style=\"text-align:left\">TSDB 分析（如  <code>analyze</code>  看块与序列统计）</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>💡 <strong>养成习惯</strong>：<strong>任何配置变更 → 先  <code>check config</code>  → 再 reload → 再去看 Targets 页面。</strong> 三步走，能省掉 80% 的 &quot;改完没生效&quot; 的困惑。</p>\n</blockquote>\n<hr />\n<h2 id=\"27-方式三容器化部署\"><a class=\"anchor\" href=\"#27-方式三容器化部署\">#</a> 2.7　方式三：容器化部署</h2>\n<h3 id=\"271-官方-dockerfile-全解读\"><a class=\"anchor\" href=\"#271-官方-dockerfile-全解读\">#</a> 2.7.1　官方 Dockerfile 全解读</h3>\n<p>官方镜像： <code>prom/prometheus</code> （注意是 <strong> <code>prom</code> </strong> 组织，不是  <code>prometheus</code> ，直接搜全名经常搜不到）</p>\n<p>来源：<a href=\"https://github.com/prometheus/prometheus/blob/main/Dockerfile\">https://github.com/prometheus/prometheus/blob/main/Dockerfile</a></p>\n<figure class=\"highlight dockerfile\"><figcaption data-lang=\"Docker\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">ARG</span> ARCH=<span class=\"token string\">\"amd64\"</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">ARG</span> OS=<span class=\"token string\">\"linux\"</span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">FROM</span> quay.io/prometheus/busybox-<span class=\"token variable\">$&#123;OS&#125;</span>-<span class=\"token variable\">$&#123;ARCH&#125;</span>:latest</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">COPY</span> .build/<span class=\"token variable\">$&#123;OS&#125;</span>-<span class=\"token variable\">$&#123;ARCH&#125;</span>/prometheus /bin/prometheus</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">COPY</span> .build/<span class=\"token variable\">$&#123;OS&#125;</span>-<span class=\"token variable\">$&#123;ARCH&#125;</span>/promtool   /bin/promtool</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">COPY</span> documentation/examples/prometheus.yml /etc/prometheus/prometheus.yml</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">WORKDIR</span> /prometheus</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">RUN</span> chown -R nobody:nobody /etc/prometheus /prometheus &amp;&amp; chmod g+w /prometheus</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">USER</span> nobody</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">EXPOSE</span> 9090</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">VOLUME</span> [ <span class=\"token string\">\"/prometheus\"</span> ]</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">ENTRYPOINT</span> [ <span class=\"token string\">\"/bin/prometheus\"</span> ]</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token instruction\"><span class=\"token keyword\">CMD</span> [ <span class=\"token string\">\"--config.file=/etc/prometheus/prometheus.yml\"</span>, <span class=\"token string\">\"--storage.tsdb.path=/prometheus\"</span> ]</span></pre></td></tr></table></figure><p><strong>看懂了这 10 行，你就看懂了所有 Go 程序的官方镜像：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">行</th>\n<th style=\"text-align:left\">含义</th>\n<th style=\"text-align:left\">对我们的启示</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>FROM busybox</code></td>\n<td style=\"text-align:left\">基础镜像只是提供 shell 和根证书</td>\n<td style=\"text-align:left\">镜像可以做到很小（甚至  <code>scratch</code> ）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>COPY prometheus /bin/</code></td>\n<td style=\"text-align:left\"><strong>就是把我们手动装的那个二进制拷进去</strong></td>\n<td style=\"text-align:left\">二进制会了，镜像就是 &quot;打包&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">配置文件在  <code>/etc/prometheus/</code></td>\n<td style=\"text-align:left\">默认配置路径</td>\n<td style=\"text-align:left\">修改配置 = 覆盖这个文件</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>USER nobody</code></td>\n<td style=\"text-align:left\">以 nobody 运行</td>\n<td style=\"text-align:left\">非 root，安全</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>VOLUME [&quot;/prometheus&quot;]</code></td>\n<td style=\"text-align:left\">数据目录</td>\n<td style=\"text-align:left\">不挂载就<strong>随容器删掉而丢失</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>CMD [...]</code></td>\n<td style=\"text-align:left\">默认启动参数</td>\n<td style=\"text-align:left\">传入自己的参数会<strong>完全覆盖</strong> CMD</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>💡 <strong>这就是为什么 &quot;二进制学扎实&quot; 如此重要</strong>：容器里跑的就是那个二进制，参数一模一样，只是配置文件位置和数据目录换成了镜像里约定的路径。<strong>没有任何魔法。</strong></p>\n</blockquote>\n<h3 id=\"272-三种启动姿势\"><a class=\"anchor\" href=\"#272-三种启动姿势\">#</a> 2.7.2　三种启动姿势</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ① 最简：默认配置 + 默认数据目录（不持久化）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">docker</span> run <span class=\"token parameter variable\">-d</span> <span class=\"token parameter variable\">--name</span> prometheus <span class=\"token parameter variable\">-p</span> <span class=\"token number\">9090</span>:9090 prom/prometheus</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># ② 生产可用：挂载配置 + 数据卷</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">docker</span> run <span class=\"token parameter variable\">-d</span> <span class=\"token parameter variable\">--name</span> prometheus <span class=\"token parameter variable\">-p</span> <span class=\"token number\">9090</span>:9090 <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token parameter variable\">-v</span> <span class=\"token environment constant\">$PWD</span>/prometheus.yml:/etc/prometheus/prometheus.yml <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token parameter variable\">-v</span> prometheus_data:/prometheus <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  prom/prometheus:v2.53.0</pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># ③ 自定义配置路径（不覆盖镜像内文件，而是改变启动参数）</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token function\">docker</span> run <span class=\"token parameter variable\">-d</span> <span class=\"token parameter variable\">--name</span> prometheus <span class=\"token parameter variable\">-p</span> <span class=\"token number\">9090</span>:9090 <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token parameter variable\">-v</span> <span class=\"token environment constant\">$PWD</span>/prometheus.yml:/prometheus-config/prometheus.yml <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  prom/prometheus <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token parameter variable\">--config.file</span><span class=\"token operator\">=</span>/prometheus-config/prometheus.yml</pre></td></tr></table></figure><blockquote>\n<p>⚠️ <strong>注意第 ③ 种</strong>：一旦你在镜像名后面跟了参数，<strong>镜像里的  <code>CMD</code>  会被整体替换</strong>。所以必须把  <code>--storage.tsdb.path</code>  之类的必要参数一起写全，否则会回落到默认值（ <code>data/</code> ，相对于容器内工作目录）。</p>\n</blockquote>\n<h3 id=\"273-故障现场四容器里的配置文件改不动\"><a class=\"anchor\" href=\"#273-故障现场四容器里的配置文件改不动\">#</a> 2.7.3　⭐ 故障现场四：容器里的配置文件改不动</h3>\n<p>用  <code>docker run</code>  起完之后，你会发现一个尴尬事：</p>\n<blockquote>\n<p><strong>配置文件在镜像里。想改？得  <code>docker exec</code>  进去用  <code>vi</code>  改 —— 而大多数精简镜像里根本没有  <code>vi</code> 。</strong></p>\n</blockquote>\n<p><strong>正确做法（三步）</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 把镜像内的默认配置拷出来</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">docker</span> <span class=\"token function\">cp</span> prometheus:/etc/prometheus/prometheus.yml ./prometheus.yml</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2. 在宿主机上修改它（想改采集间隔就改）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">vi</span> ./prometheus.yml</pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 3. 删掉旧容器，用 -v 挂载覆盖镜像内的配置</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token function\">docker</span> <span class=\"token function\">rm</span> <span class=\"token parameter variable\">-f</span> prometheus</pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token function\">docker</span> run <span class=\"token parameter variable\">-d</span> <span class=\"token parameter variable\">--name</span> prometheus <span class=\"token parameter variable\">-p</span> <span class=\"token number\">9090</span>:9090 <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token parameter variable\">-v</span> <span class=\"token environment constant\">$PWD</span>/prometheus.yml:/etc/prometheus/prometheus.yml <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token parameter variable\">-v</span> prometheus_data:/prometheus <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  prom/prometheus</pre></td></tr></table></figure><p><strong>验证是否生效</strong>：访问 9090 → Status → Configuration，看里面的  <code>scrape_interval</code>  是不是你改的值。</p>\n<blockquote>\n<p>📌 <strong>容器化不是 &quot;更好的方式&quot;，而是 &quot;另一种打包方式&quot;。</strong><br />\n它把 &quot;改配置文件&quot; 这件简单的事，变成了 &quot;覆盖镜像内文件&quot; 这件事。<br />\n所以：<strong>实验环境用容器图快，生产环境很多人仍然用二进制 + systemd</strong>—— 改配置、看日志、排障都更直接。两种方式都要会，别只会一种。</p>\n</blockquote>\n<h3 id=\"274-docker-compose一键起整套监控栈\"><a class=\"anchor\" href=\"#274-docker-compose一键起整套监控栈\">#</a> 2.7.4　Docker Compose：一键起整套监控栈</h3>\n<p>中小规模环境可以直接用 Compose 拉起完整栈：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">version</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'3.6'</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key atrule\">volumes</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">prometheus_data</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token key atrule\">grafana_data</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key atrule\">networks</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">monitoring</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token key atrule\">driver</span><span class=\"token punctuation\">:</span> bridge</pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key atrule\">services</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token key atrule\">prometheus</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>    <span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> prom/prometheus<span class=\"token punctuation\">:</span>v2.53.0</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    <span class=\"token key atrule\">volumes</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>      <span class=\"token punctuation\">-</span> ./prometheus/<span class=\"token punctuation\">:</span>/etc/prometheus/</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>      <span class=\"token punctuation\">-</span> prometheus_data<span class=\"token punctuation\">:</span>/prometheus</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    <span class=\"token key atrule\">command</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--config.file=/etc/prometheus/prometheus.yml'</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--storage.tsdb.path=/prometheus'</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--storage.tsdb.retention.time=15d'</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">\"9090:9090\"</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>    <span class=\"token key atrule\">networks</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>monitoring<span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>    <span class=\"token key atrule\">restart</span><span class=\"token punctuation\">:</span> unless<span class=\"token punctuation\">-</span>stopped</pre></td></tr><tr><td data-num=\"25\"></td><td><pre></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>  <span class=\"token key atrule\">alertmanager</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>    <span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> prom/alertmanager<span class=\"token punctuation\">:</span>v0.27.0</pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token key atrule\">command</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--config.file=/etc/alertmanager/config.yml'</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--storage.path=/alertmanager'</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre>    <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">\"9093:9093\"</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre>    <span class=\"token key atrule\">networks</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>monitoring<span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre>    <span class=\"token key atrule\">restart</span><span class=\"token punctuation\">:</span> unless<span class=\"token punctuation\">-</span>stopped</pre></td></tr><tr><td data-num=\"35\"></td><td><pre></pre></td></tr><tr><td data-num=\"36\"></td><td><pre>  <span class=\"token key atrule\">node-exporter</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre>    <span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> prom/node<span class=\"token punctuation\">-</span>exporter<span class=\"token punctuation\">:</span>v1.8.2</pre></td></tr><tr><td data-num=\"38\"></td><td><pre>    <span class=\"token key atrule\">volumes</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"39\"></td><td><pre>      <span class=\"token punctuation\">-</span> /proc<span class=\"token punctuation\">:</span>/host/proc<span class=\"token punctuation\">:</span>ro</pre></td></tr><tr><td data-num=\"40\"></td><td><pre>      <span class=\"token punctuation\">-</span> /sys<span class=\"token punctuation\">:</span>/host/sys<span class=\"token punctuation\">:</span>ro</pre></td></tr><tr><td data-num=\"41\"></td><td><pre>      <span class=\"token punctuation\">-</span> /<span class=\"token punctuation\">:</span>/rootfs<span class=\"token punctuation\">:</span>ro</pre></td></tr><tr><td data-num=\"42\"></td><td><pre>    <span class=\"token key atrule\">command</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"43\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--path.procfs=/host/proc'</span></pre></td></tr><tr><td data-num=\"44\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--path.sysfs=/host/sys'</span></pre></td></tr><tr><td data-num=\"45\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--path.rootfs=/rootfs'</span></pre></td></tr><tr><td data-num=\"46\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'</span></pre></td></tr><tr><td data-num=\"47\"></td><td><pre>    <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"48\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">\"9100:9100\"</span></pre></td></tr><tr><td data-num=\"49\"></td><td><pre>    <span class=\"token key atrule\">networks</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>monitoring<span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"50\"></td><td><pre>    <span class=\"token key atrule\">restart</span><span class=\"token punctuation\">:</span> unless<span class=\"token punctuation\">-</span>stopped</pre></td></tr><tr><td data-num=\"51\"></td><td><pre></pre></td></tr><tr><td data-num=\"52\"></td><td><pre>  <span class=\"token key atrule\">pushgateway</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"53\"></td><td><pre>    <span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> prom/pushgateway<span class=\"token punctuation\">:</span>v1.10.0</pre></td></tr><tr><td data-num=\"54\"></td><td><pre>    <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"55\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">\"9091:9091\"</span></pre></td></tr><tr><td data-num=\"56\"></td><td><pre>    <span class=\"token key atrule\">networks</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>monitoring<span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"57\"></td><td><pre>    <span class=\"token key atrule\">restart</span><span class=\"token punctuation\">:</span> unless<span class=\"token punctuation\">-</span>stopped</pre></td></tr><tr><td data-num=\"58\"></td><td><pre></pre></td></tr><tr><td data-num=\"59\"></td><td><pre>  <span class=\"token key atrule\">grafana</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"60\"></td><td><pre>    <span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> grafana/grafana<span class=\"token punctuation\">:</span>11.2.0</pre></td></tr><tr><td data-num=\"61\"></td><td><pre>    <span class=\"token key atrule\">volumes</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"62\"></td><td><pre>      <span class=\"token punctuation\">-</span> grafana_data<span class=\"token punctuation\">:</span>/var/lib/grafana</pre></td></tr><tr><td data-num=\"63\"></td><td><pre>    <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"64\"></td><td><pre>      <span class=\"token punctuation\">-</span> GF_SECURITY_ADMIN_PASSWORD=admin</pre></td></tr><tr><td data-num=\"65\"></td><td><pre>      <span class=\"token punctuation\">-</span> GF_USERS_ALLOW_SIGN_UP=false</pre></td></tr><tr><td data-num=\"66\"></td><td><pre>    <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"67\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">\"3000:3000\"</span></pre></td></tr><tr><td data-num=\"68\"></td><td><pre>    <span class=\"token key atrule\">networks</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>monitoring<span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"69\"></td><td><pre>    <span class=\"token key atrule\">restart</span><span class=\"token punctuation\">:</span> unless<span class=\"token punctuation\">-</span>stopped</pre></td></tr></table></figure><p>有两点必须提醒：</p>\n<ol>\n<li><strong> <code>node-exporter</code>  的三个挂载不是可选项</strong> —— 它要读宿主机的  <code>/proc</code> 、 <code>/sys</code>  和根文件系统，否则采集到的是容器自己的（几乎为空的）指标。下一节会详细解释。</li>\n<li><strong>容器内的  <code>prometheus</code>  抓容器内的  <code>node-exporter</code>  时，target 要写  <code>node-exporter:9100</code> </strong>（服务名），而不是  <code>localhost:9100</code> 。这是 Compose 网络里的 DNS 解析规则，也是新手最常见的 &quot;抓不到&quot; 原因之一。</li>\n</ol>\n<hr />\n<h2 id=\"28-node-exporter把主机指标出口出去\"><a class=\"anchor\" href=\"#28-node-exporter把主机指标出口出去\">#</a> 2.8　Node Exporter：把主机指标 &quot;出口&quot; 出去</h2>\n<h3 id=\"281-为什么必须有它\"><a class=\"anchor\" href=\"#281-为什么必须有它\">#</a> 2.8.1　为什么必须有它</h3>\n<p>回到第 1 章的结论：<strong>Prometheus 的所有指标都必须以 HTTP 形式暴露。</strong></p>\n<p>而 Linux 操作系统<strong>本身不提供 HTTP 指标端点</strong>。你不可能让内核主动开个端口给你读  <code>/proc/stat</code> 。</p>\n<p>所以中间必须有个 &quot;转换器&quot;：</p>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">flowchart</span> LR</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    K<span class=\"token text string\">[\"Linux 内核&lt;br/>/proc /sys\"]</span> <span class=\"token arrow operator\">--></span><span class=\"token label property\">|读取|</span> NE<span class=\"token text string\">[\"Node Exporter&lt;br/>:9100\"]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    NE <span class=\"token arrow operator\">--></span><span class=\"token label property\">|\"HTTP GET /metrics&lt;br/>纯文本格式\"|</span> P<span class=\"token text string\">[\"Prometheus Server\"]</span></pre></td></tr></table></figure><p><strong>Node Exporter 干的事：</strong></p>\n<ol>\n<li>读取本机的  <code>/proc</code> 、 <code>/sys</code> 、系统调用，拿到 CPU、内存、磁盘、网络、文件系统等原始数据；</li>\n<li>转换成 <strong>Prometheus 文本格式</strong>（ <code># HELP</code>  /  <code># TYPE</code>  /  <code>指标 值</code> ）；</li>\n<li>在本机 <strong>9100</strong> 端口起一个 HTTP 服务，把结果暴露在  <code>/metrics</code> 。</li>\n</ol>\n<blockquote>\n<p>🧠 <strong>名字的由来</strong>：它把本节点的指标 &quot;<strong> 出口（export）</strong>&quot;出去，让 Prometheus 来&quot; 进货 &quot;。你不&quot; 出口 &quot;，人家就采不到 —— 这个命名非常形象。</p>\n<p><strong>和 Zabbix 的对照</strong>：</p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\"></th>\n<th style=\"text-align:left\">Zabbix</th>\n<th style=\"text-align:left\">Prometheus</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">采集代理</td>\n<td style=\"text-align:left\"><code>zabbix-agent</code></td>\n<td style=\"text-align:left\"><code>node_exporter</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">通信协议</td>\n<td style=\"text-align:left\"><strong>Zabbix 专有协议</strong></td>\n<td style=\"text-align:left\"><strong>HTTP/HTTPS</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">数据方向</td>\n<td style=\"text-align:left\">Server 拉（被动）或 Agent 推（主动）</td>\n<td style=\"text-align:left\"><strong>只有 Server 拉</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">谁的客户端 / 服务端</td>\n<td style=\"text-align:left\">Server 是服务端，Agent 是客户端</td>\n<td style=\"text-align:left\">⭐ <strong>反过来了</strong>：Prometheus 是 HTTP <strong>客户端</strong>，Node Exporter 是 HTTP <strong>服务端</strong></td>\n</tr>\n</tbody>\n</table>\n<p>最后一行请特别注意：<strong>角色是反的</strong>。Prometheus 主动发起 HTTP 请求（像浏览器），Node Exporter 被动响应（像 Web 服务器）。</p>\n<h3 id=\"282-安装与-prometheus-二进制安装几乎同构\"><a class=\"anchor\" href=\"#282-安装与-prometheus-二进制安装几乎同构\">#</a> 2.8.2　安装（与 Prometheus 二进制安装几乎同构）</h3>\n<p>官方下载：<a href=\"https://prometheus.io/download/\">https://prometheus.io/download/</a><br />\nGitHub：<a href=\"https://github.com/prometheus/node_exporter\">https://github.com/prometheus/node_exporter</a></p>\n<p><strong>在每一台需要监控的节点上执行</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token builtin class-name\">cd</span> /usr/local</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">wget</span> https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">tar</span> xf node_exporter-1.8.2.linux-amd64.tar.gz</pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token function\">ln</span> <span class=\"token parameter variable\">-s</span> node_exporter-1.8.2.linux-amd64 node_exporter</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token builtin class-name\">cd</span> node_exporter</pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token function\">mkdir</span> bin</pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token function\">mv</span> node_exporter bin/</pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token function\">useradd</span> <span class=\"token parameter variable\">-r</span> <span class=\"token parameter variable\">-s</span> /sbin/nologin prometheus</pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token function\">chown</span> <span class=\"token parameter variable\">-R</span> prometheus:prometheus /usr/local/node_exporter/</pre></td></tr></table></figure><blockquote>\n<p>💡 看出来了吗？<strong>解压 → 软链 → 分目录 → 建账号 → 改属主</strong>，和装 Prometheus 的步骤一模一样。这就是 Go 生态的统一 &quot;手感&quot;。<strong>学会一个，就会一串。</strong></p>\n</blockquote>\n<h3 id=\"283-service-文件含两个坑\"><a class=\"anchor\" href=\"#283-service-文件含两个坑\">#</a> 2.8.3　service 文件（含两个坑）</h3>\n<figure class=\"highlight ini\"><figcaption data-lang=\"ini\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Unit</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key attr-name\">Description</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">Prometheus Node Exporter</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key attr-name\">After</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">network.target</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Service</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key attr-name\">Type</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">simple</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key attr-name\">ExecStart</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/usr/local/node_exporter/bin/node_exporter --collector.cgroups</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token key attr-name\">ExecReload</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/bin/kill -HUP $MAINPID</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token key attr-name\">Restart</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">on-failure</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token key attr-name\">User</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">prometheus</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key attr-name\">Group</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">prometheus</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Install</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token key attr-name\">WantedBy</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">multi-user.target</span></pre></td></tr></table></figure><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl daemon-reload</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl <span class=\"token builtin class-name\">enable</span> <span class=\"token parameter variable\">--now</span> node_exporter.service</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>systemctl is-active node_exporter</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>ss <span class=\"token parameter variable\">-ntlp</span> <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token number\">9100</span></pre></td></tr></table></figure><p><strong>两个参数坑，来自实战：</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">参数</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">坑</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>--collector.cgroups</code></td>\n<td style=\"text-align:left\">额外启用 cgroups 采集器</td>\n<td style=\"text-align:left\">想采容器资源占用时需要</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--no-collector.uname</code></td>\n<td style=\"text-align:left\"><strong>禁用</strong> uname 采集器</td>\n<td style=\"text-align:left\">❌ <strong>千万别加！</strong> 禁用后 Grafana 里的 Dashboard <strong>拿不到主机名和内核版本</strong>，面板上会显示  <code>N/A</code></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ 第二个坑非常隐蔽：有人为了 &quot;减少指标数量&quot; 加了  <code>--no-collector.uname</code> ，结果所有社区 Dashboard 的主机信息栏全是空的，还以为是模板不兼容。<strong>优化指标量请用 relabel 丢弃，不要随手关采集器。</strong></p>\n</blockquote>\n<h3 id=\"284-验证暴露结果\"><a class=\"anchor\" href=\"#284-验证暴露结果\">#</a> 2.8.4　验证暴露结果</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">curl</span> http://localhost:9100/metrics <span class=\"token operator\">|</span> <span class=\"token function\">head</span> <span class=\"token parameter variable\">-40</span></pre></td></tr></table></figure><p>浏览器访问  <code>http://&lt;node-ip&gt;:9100/</code> ，会看到一个只有一个  <code>metrics</code>  链接的极简页面 —— 点进去就是全部指标。</p>\n<blockquote>\n<p>💡 <strong>这个页面本身就是最好的学习材料</strong>。随便挑几个指标，对照  <code># HELP</code>  的说明，你就能明白它代表什么。比看文档快得多。</p>\n</blockquote>\n<h3 id=\"285-常见指标速查背诵级\"><a class=\"anchor\" href=\"#285-常见指标速查背诵级\">#</a> 2.8.5　常见指标速查（背诵级）</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">前缀 / 指标</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>node_cpu_seconds_total</code></td>\n<td style=\"text-align:left\">各 CPU、各模式（user/system/idle/iowait/softirq…）的累计秒数（<strong>Counter</strong>）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_memory_*</code></td>\n<td style=\"text-align:left\">内存： <code>MemTotal</code> 、 <code>MemFree</code> 、 <code>MemAvailable</code> 、 <code>Buffers</code> 、 <code>Cached</code> 、 <code>Swap*</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_filesystem_*</code></td>\n<td style=\"text-align:left\">文件系统的容量与可用空间（按挂载点、设备、fstype 分标签）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_disk_*</code></td>\n<td style=\"text-align:left\">磁盘 IO：读写字节、IOPS、耗时、队列长度</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_network_*</code></td>\n<td style=\"text-align:left\">网卡收发字节、包数、错误数、丢包（按  <code>device</code>  分标签）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_load1</code>  /  <code>5</code>  /  <code>15</code></td>\n<td style=\"text-align:left\">1/5/15 分钟平均负载（<strong>Gauge</strong>）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_boot_time_seconds</code></td>\n<td style=\"text-align:left\">系统启动时间（1970 起的秒数）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_time_seconds</code></td>\n<td style=\"text-align:left\">当前系统时间</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>go_*</code></td>\n<td style=\"text-align:left\">Exporter 自身的 Go 运行时指标（GC、goroutine、堆）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>process_*</code></td>\n<td style=\"text-align:left\">Exporter 自身进程指标（ <code>process_max_fds</code>  就属于这类）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>node_uname_info</code></td>\n<td style=\"text-align:left\">主机名、内核版本、架构等信息</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>🔗 <strong>回忆第 1 章</strong>： <code>top</code>  里的 user /system/nice /idle/iowait /irq/softirq /steal，在  <code>node_cpu_seconds_total</code>  里就是  <code>mode=&quot;user&quot;|&quot;system&quot;|&quot;nice&quot;|&quot;idle&quot;|&quot;iowait&quot;|&quot;irq&quot;|&quot;softirq&quot;|&quot;steal&quot;</code>  这几个标签值。<strong>命令行的每一列，在 Prometheus 里都是一个标签维度。</strong></p>\n</blockquote>\n<h3 id=\"286-为什么容器里的-node-exporter-必须三件套\"><a class=\"anchor\" href=\"#286-为什么容器里的-node-exporter-必须三件套\">#</a> 2.8.6　为什么容器里的 Node Exporter 必须 &quot;三件套&quot;</h3>\n<p>这是本章最值得深入理解的一处。官方推荐命令：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">docker</span> run <span class=\"token parameter variable\">-d</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token parameter variable\">--net</span><span class=\"token operator\">=</span><span class=\"token string\">\"host\"</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token parameter variable\">--pid</span><span class=\"token operator\">=</span><span class=\"token string\">\"host\"</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token parameter variable\">-v</span> <span class=\"token string\">\"/:/host:ro,rslave\"</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  quay.io/prometheus/node-exporter:latest <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token parameter variable\">--path.rootfs</span><span class=\"token operator\">=</span>/host</pre></td></tr></table></figure><p>三个参数，各有其不可替代的原因：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">参数</th>\n<th style=\"text-align:left\">作用</th>\n<th style=\"text-align:left\">不加会怎样</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>--net=&quot;host&quot;</code></td>\n<td style=\"text-align:left\">与宿主机共享网络命名空间</td>\n<td style=\"text-align:left\">采集到的网卡（ <code>node_network_*</code> ）是容器虚拟网卡的，<strong>看不到 eth0 /bond/ 物理网卡</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>--pid=&quot;host&quot;</code></td>\n<td style=\"text-align:left\">与宿主机共享 PID 命名空间</td>\n<td style=\"text-align:left\">进程类指标（进程数、 <code>node_processes_*</code> ）只看到容器内的 1 号进程</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>-v &quot;/:/host:ro,rslave&quot;</code></td>\n<td style=\"text-align:left\">把宿主机根挂进来 +  <code>--path.rootfs=/host</code></td>\n<td style=\"text-align:left\"><strong>文件系统指标全是容器 overlay 的</strong>，磁盘使用率完全失真； <code>/proc</code> 、 <code>/sys</code>  读到的也是容器自己的</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⭐ <strong>一句话记忆</strong>：<br />\n<strong>Node Exporter 不是来监控 &quot;自己&quot; 的，是来监控 &quot;宿主机&quot; 的 —— 所以它必须能看见宿主机。</strong><br />\n同理，K8s 里部署 node-exporter 一定要用 <strong>DaemonSet +  <code>hostNetwork: true</code>  +  <code>hostPID: true</code>  +  <code>hostPath</code>  挂载  <code>/proc</code>   <code>/sys</code>   <code>/</code> </strong>。</p>\n</blockquote>\n<h3 id=\"287-批量部署脚本-ansible-daemonset\"><a class=\"anchor\" href=\"#287-批量部署脚本-ansible-daemonset\">#</a> 2.8.7　批量部署：脚本 → Ansible → DaemonSet</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">规模</th>\n<th style=\"text-align:left\">方案</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1～5 台</td>\n<td style=\"text-align:left\">手工 / Shell 脚本</td>\n<td style=\"text-align:left\">课程提供的  <code>install_node_exporter.sh</code>  支持在线与离线安装</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">10～100 台</td>\n<td style=\"text-align:left\"><strong>Ansible</strong></td>\n<td style=\"text-align:left\">官方 Role：<a href=\"https://github.com/prometheus-community/ansible/tree/main/roles/node_exporter\">https://github.com/prometheus-community/ansible/tree/main/roles/node_exporter</a>，改改变量即可</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">K8s 集群</td>\n<td style=\"text-align:left\"><strong>DaemonSet</strong></td>\n<td style=\"text-align:left\">保证每个节点恰好一个 Pod</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Shell 脚本的核心结构</strong>（值得学习它的工程化写法）：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token assign-left variable\">NODE_EXPORTER_VERSION</span><span class=\"token operator\">=</span><span class=\"token number\">1.8</span>.2</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token assign-left variable\">NODE_EXPORTER_FILE</span><span class=\"token operator\">=</span><span class=\"token string\">\"node_exporter-<span class=\"token variable\">$&#123;NODE_EXPORTER_VERSION&#125;</span>.linux-amd64.tar.gz\"</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token assign-left variable\">GITHUB_PROXY</span><span class=\"token operator\">=</span>https://mirror.ghproxy.com/     <span class=\"token comment\"># 加速代理，会失效，注意维护</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function-name function\">install_node_exporter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-f</span> <span class=\"token string\">\"<span class=\"token variable\">$&#123;NODE_EXPORTER_FILE&#125;</span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token function\">wget</span> <span class=\"token string\">\"<span class=\"token variable\">$&#123;GITHUB_PROXY&#125;</span><span class=\"token variable\">$&#123;NODE_EXPORTER_URL&#125;</span>\"</span> <span class=\"token operator\">||</span> <span class=\"token punctuation\">&#123;</span> color <span class=\"token string\">\"下载失败!\"</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span> <span class=\"token builtin class-name\">exit</span><span class=\"token punctuation\">;</span> <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    <span class=\"token function\">tar</span> xf <span class=\"token string\">\"<span class=\"token variable\">$&#123;NODE_EXPORTER_FILE&#125;</span>\"</span> <span class=\"token parameter variable\">-C</span> <span class=\"token string\">\"<span class=\"token variable\">$&#123;INSTALL_DIR&#125;</span>\"</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    <span class=\"token function\">ln</span> <span class=\"token parameter variable\">-s</span> node_exporter-<span class=\"token variable\">$&#123;NODE_EXPORTER_VERSION&#125;</span>.linux-amd64 node_exporter</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token function\">mkdir</span> <span class=\"token parameter variable\">-p</span> node_exporter/bin <span class=\"token operator\">&amp;&amp;</span> <span class=\"token function\">mv</span> node_exporter bin/</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token function\">id</span> prometheus <span class=\"token operator\">&amp;></span>/dev/null <span class=\"token operator\">||</span> <span class=\"token function\">useradd</span> <span class=\"token parameter variable\">-r</span> <span class=\"token parameter variable\">-s</span> /sbin/nologin prometheus</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token function\">chown</span> <span class=\"token parameter variable\">-R</span> prometheus:prometheus node_exporter/</pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token function-name function\">node_exporter_service</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token punctuation\">..</span>.  写 <span class=\"token function\">service</span> 文件、daemon-reload、enable <span class=\"token parameter variable\">--now</span> <span class=\"token punctuation\">..</span>. <span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>脚本里的三个好习惯</strong>：</p>\n<ol>\n<li><strong>版本号抽成变量</strong> —— 升级只改一行；</li>\n<li><strong>先判断本地包是否存在</strong> —— 存在就不下载，天然支持<strong>离线安装</strong>；</li>\n<li><strong>幂等</strong> —— <code>id prometheus &amp;&gt;/dev/null || useradd</code> ，重复执行不报错。</li>\n</ol>\n</blockquote>\n<p><strong>Ansible（官方已现成）</strong>：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">hosts</span><span class=\"token punctuation\">:</span> all</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token key atrule\">become</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">roles</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token punctuation\">-</span> prometheus.prometheus.node_exporter</pre></td></tr></table></figure><p><strong>K8s DaemonSet（关键字段）</strong>：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">apiVersion</span><span class=\"token punctuation\">:</span> apps/v1</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key atrule\">kind</span><span class=\"token punctuation\">:</span> DaemonSet</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key atrule\">metadata</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> prometheus<span class=\"token punctuation\">-</span>node<span class=\"token punctuation\">-</span>exporter</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token key atrule\">namespace</span><span class=\"token punctuation\">:</span> prom</pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">spec</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token key atrule\">selector</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    <span class=\"token key atrule\">matchLabels</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">app</span><span class=\"token punctuation\">:</span> prometheus<span class=\"token punctuation\">,</span> <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> node<span class=\"token punctuation\">-</span>exporter <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token key atrule\">template</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token key atrule\">metadata</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      <span class=\"token key atrule\">labels</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">app</span><span class=\"token punctuation\">:</span> prometheus<span class=\"token punctuation\">,</span> <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> node<span class=\"token punctuation\">-</span>exporter <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token key atrule\">spec</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>      <span class=\"token key atrule\">tolerations</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">effect</span><span class=\"token punctuation\">:</span> NoSchedule</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>        <span class=\"token key atrule\">key</span><span class=\"token punctuation\">:</span> node<span class=\"token punctuation\">-</span>role.kubernetes.io/master      <span class=\"token comment\"># 主节点也要装，需要容忍污点</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>      <span class=\"token key atrule\">containers</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> prom/node<span class=\"token punctuation\">-</span>exporter<span class=\"token punctuation\">:</span>v1.8.2</pre></td></tr><tr><td data-num=\"18\"></td><td><pre>        <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> prometheus<span class=\"token punctuation\">-</span>node<span class=\"token punctuation\">-</span>exporter</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>        <span class=\"token key atrule\">args</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">-</span><span class=\"token punctuation\">-</span>path.procfs=/host/proc</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">-</span><span class=\"token punctuation\">-</span>path.sysfs=/host/sys</pre></td></tr><tr><td data-num=\"22\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">-</span><span class=\"token punctuation\">-</span>path.rootfs=/host</pre></td></tr><tr><td data-num=\"23\"></td><td><pre>        <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">containerPort</span><span class=\"token punctuation\">:</span> <span class=\"token number\">9100</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>          <span class=\"token key atrule\">hostPort</span><span class=\"token punctuation\">:</span> <span class=\"token number\">9100</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>        <span class=\"token key atrule\">volumeMounts</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> proc<span class=\"token punctuation\">,</span>   <span class=\"token key atrule\">mountPath</span><span class=\"token punctuation\">:</span> /host/proc <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> sys<span class=\"token punctuation\">,</span>    <span class=\"token key atrule\">mountPath</span><span class=\"token punctuation\">:</span> /host/sys  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>        <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> rootfs<span class=\"token punctuation\">,</span> <span class=\"token key atrule\">mountPath</span><span class=\"token punctuation\">:</span> /host      <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>      <span class=\"token key atrule\">hostNetwork</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>     <span class=\"token comment\"># ⭐ 与宿主机共享网络</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre>      <span class=\"token key atrule\">hostPID</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>         <span class=\"token comment\"># ⭐ 与宿主机共享 PID</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre>      <span class=\"token key atrule\">volumes</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> proc<span class=\"token punctuation\">,</span>   <span class=\"token key atrule\">hostPath</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">path</span><span class=\"token punctuation\">:</span> /proc <span class=\"token punctuation\">&#125;</span> <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> sys<span class=\"token punctuation\">,</span>    <span class=\"token key atrule\">hostPath</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">path</span><span class=\"token punctuation\">:</span> /sys  <span class=\"token punctuation\">&#125;</span> <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> rootfs<span class=\"token punctuation\">,</span> <span class=\"token key atrule\">hostPath</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">&#123;</span> <span class=\"token key atrule\">path</span><span class=\"token punctuation\">:</span> /     <span class=\"token punctuation\">&#125;</span> <span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><blockquote>\n<p>📌  <code>DaemonSet</code>  = &quot;每个节点跑一个&quot;。这正是 Node Exporter 需要的语义 ——<strong> 它不是 &quot;一个服务&quot;，而是 &quot;每台机器上的一个探针&quot;</strong>。</p>\n</blockquote>\n<hr />\n<h2 id=\"29-让-prometheus-采集-node-exporter\"><a class=\"anchor\" href=\"#29-让-prometheus-采集-node-exporter\">#</a> 2.9　让 Prometheus 采集 Node Exporter</h2>\n<p>到这里，Node Exporter 已经在 9100 上 &quot;出口&quot; 了指标，但 <strong>Prometheus 还不知道它的存在</strong> —— 所以你在 Prometheus 里搜  <code>node_memory_*</code>  会一无所获。</p>\n<p><strong>这是新手最常见的困惑</strong>：&quot;我明明在浏览器里能看到指标，为什么 Prometheus 里查不到？&quot;</p>\n<blockquote>\n<p>记住这句话：<strong>&quot;暴露&quot; 是 Node Exporter 的事，&quot;采集&quot; 是 Prometheus 的事。两件事必须都做。</strong></p>\n</blockquote>\n<h3 id=\"291-修改配置\"><a class=\"anchor\" href=\"#291-修改配置\">#</a> 2.9.1　修改配置</h3>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">global</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token key atrule\">scrape_interval</span><span class=\"token punctuation\">:</span> 15s</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">evaluation_interval</span><span class=\"token punctuation\">:</span> 15s</pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token key atrule\">alerting</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token key atrule\">alertmanagers</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token key atrule\">rule_files</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token key atrule\">scrape_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"prometheus\"</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"localhost:9090\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token comment\"># ★ 新增：采集 Node Exporter</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'node_exporter'</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token key atrule\">metrics_path</span><span class=\"token punctuation\">:</span> /metrics        <span class=\"token comment\"># 默认值，可省略</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    <span class=\"token key atrule\">scheme</span><span class=\"token punctuation\">:</span> http                  <span class=\"token comment\"># 默认值，可省略</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'10.0.0.101:9100'</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'10.0.0.102:9100'</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'10.0.0.103:9100'</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'10.0.0.100:9100'</span>         <span class=\"token comment\"># 别忘了 Prometheus 自己这台</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>      <span class=\"token key atrule\">labels</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>        <span class=\"token key atrule\">env</span><span class=\"token punctuation\">:</span> prod</pre></td></tr><tr><td data-num=\"29\"></td><td><pre>        <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> bj</pre></td></tr></table></figure><p><strong>targets 的两种写法（都合法，选顺眼的）</strong>：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 写法 A：写在一行（机器少时更紧凑）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'10.0.0.101:9100'</span><span class=\"token punctuation\">,</span><span class=\"token string\">'10.0.0.102:9100'</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 写法 B：一行一个（机器多时更清晰，推荐）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'10.0.0.101:9100'</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token string\">'10.0.0.102:9100'</span></pre></td></tr></table></figure><blockquote>\n<p>⚠️ 无论哪种写法， <code>targets</code>  都是<strong>列表</strong>，列表项以  <code>-</code>  开头。<strong>这是 YAML 缩进错误最高发的位置。</strong></p>\n</blockquote>\n<h3 id=\"292-检查-生效-验证\"><a class=\"anchor\" href=\"#292-检查-生效-验证\">#</a> 2.9.2　检查 → 生效 → 验证</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 语法检查</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>promtool check config /usr/local/prometheus/conf/prometheus.yml</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2. 热加载（不重启）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>systemctl reload prometheus</pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 3. 验证：三种方式</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://localhost:9090/-/ready</pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\"># 浏览器 → Status → Targets：应看到 node_exporter 这个 job，状态 UP</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token comment\"># 4. 用 PromQL 确认</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>up<span class=\"token punctuation\">&#123;</span>job<span class=\"token operator\">=</span><span class=\"token string\">\"node_exporter\"</span><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><p><code>up</code>  指标的返回值：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">值</th>\n<th style=\"text-align:left\">含义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>1</code></td>\n<td style=\"text-align:left\">上一次抓取成功</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>0</code></td>\n<td style=\"text-align:left\">上一次抓取失败（连不上、超时、非 2xx）</td>\n</tr>\n</tbody>\n</table>\n<p>四个 target 全部  <code>1</code> ，说明采集链路通了。此时再查  <code>node_memory_MemTotal_bytes</code> ，四台机器的数据就都出来了。</p>\n<h3 id=\"293-故障现场五端口写错一个字符排查半小时\"><a class=\"anchor\" href=\"#293-故障现场五端口写错一个字符排查半小时\">#</a> 2.9.3　⭐ 故障现场五：端口写错，一个字符排查半小时</h3>\n<p>真实过程，值得完整复盘：</p>\n<ol>\n<li>配好了 job， <code>reload</code>  之后浏览器刷新 Graph 页面，搜  <code>memory</code>  —— <strong>什么都没有</strong>。</li>\n<li>第一反应：&quot;是不是要等一会？&quot;——<strong> 对，采集是周期性的</strong>。当前  <code>scrape_interval</code>  是 20s，那就等 20s 再看。</li>\n<li>等了 20s，还是没数据。</li>\n<li>第二反应：&quot;是不是配置没生效？&quot;—— 去 <strong>Status → Configuration</strong> 确认新 job 在不在。在。</li>\n<li>第三反应：&quot;那到底抓没抓到？&quot;—— 去 <strong>Status → Targets</strong>，看到  <code>node_exporter</code>  这个 job 是<strong>红色 DOWN</strong>，报错类似：</li>\n</ol>\n<figure class=\"highlight text\"><figcaption data-lang=\"text\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>Get \"http://10.0.0.101:9010/metrics\": dial tcp 10.0.0.101:9010: connect: connection refused</pre></td></tr></table></figure><ol start=\"6\">\n<li><strong>一眼看出问题</strong>： <code>9010</code> ，不是  <code>9100</code> 。<strong>打错了一个数字。</strong></li>\n</ol>\n<p>改完 reload，颜色变绿，数据立刻就有了。</p>\n<blockquote>\n<p>⭐ <strong>这就是 &quot;看 Targets 页面&quot; 的价值</strong>：它把 &quot;为什么没数据&quot; 这个问题，直接翻译成了<strong>一个具体的 URL 和一个具体的错误</strong>。<br />\n不要一上来就怀疑 Prometheus 有 bug、怀疑版本不兼容、怀疑网络 ——<strong> 先看 Targets。</strong></p>\n</blockquote>\n<h3 id=\"294-抓不到数据五步排查法\"><a class=\"anchor\" href=\"#294-抓不到数据五步排查法\">#</a> 2.9.4　&quot;抓不到数据&quot; 五步排查法</h3>\n<p>把上面的经验固化成流程，以后照着走：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">步骤</th>\n<th style=\"text-align:left\">动作</th>\n<th style=\"text-align:left\">判断依据</th>\n<th style=\"text-align:left\">结论</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>① 目标端自测</strong></td>\n<td style=\"text-align:left\">在目标机上  <code>curl -s localhost:9100/metrics \\| head</code></td>\n<td style=\"text-align:left\">有输出？</td>\n<td style=\"text-align:left\">无 → exporter 没起 / 端口不对</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>② 跨机自测</strong></td>\n<td style=\"text-align:left\">在 Prometheus 机上  <code>curl -s &lt;target&gt;:9100/metrics</code></td>\n<td style=\"text-align:left\">通了？</td>\n<td style=\"text-align:left\">不通 → <strong>防火墙 / 监听地址是 127.0.0.1 / 网络不通</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>③ 看 Targets</strong></td>\n<td style=\"text-align:left\">Web UI → Status → Targets</td>\n<td style=\"text-align:left\">UP / DOWN + 错误信息</td>\n<td style=\"text-align:left\">DOWN → 错误信息直接指出原因</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>④ 看配置</strong></td>\n<td style=\"text-align:left\">Status → Configuration</td>\n<td style=\"text-align:left\">新 job 在不在、targets 对不对</td>\n<td style=\"text-align:left\">不在 → reload 没成功 / 配置语法被拒</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>⑤ 看日志</strong></td>\n<td style=\"text-align:left\"><code>journalctl -u prometheus -n 50</code></td>\n<td style=\"text-align:left\">有无  <code>Error reloading config</code></td>\n<td style=\"text-align:left\">有 → 配置有问题</td>\n</tr>\n</tbody>\n</table>\n<p><strong>四个高频根因</strong>（按出现频率排序）：</p>\n<ol>\n<li><strong>端口写错</strong>（ <code>9100</code>  →  <code>9010</code>  /  <code>9091</code>  /  <code>910</code> ）；</li>\n<li><strong>服务监听在  <code>127.0.0.1</code>  而不是  <code>0.0.0.0</code> </strong>—— 本机 curl 通、跨机不通，这是最迷惑人的一种；</li>\n<li><strong>防火墙 / 安全组没放行</strong>（ <code>firewalld</code> 、 <code>ufw</code> 、云安全组）；</li>\n<li><strong>改完没 reload /reload 失败但没人看日志</strong>。</li>\n</ol>\n<blockquote>\n<p>💡 还有一个 &quot;假故障&quot;：<strong>指标有延迟</strong>。刚配好就查，必然查不到 —— 必须等至少一个  <code>scrape_interval</code> 。学习时把间隔调成  <code>10s</code> ，能少等很多；但<strong>生产不要低于 10s</strong>，否则序列数与磁盘写入会成倍增长。</p>\n</blockquote>\n<hr />\n<h2 id=\"210-grafana让数据变成图\"><a class=\"anchor\" href=\"#210-grafana让数据变成图\">#</a> 2.10　Grafana：让数据变成图</h2>\n<h3 id=\"2101-它是什么\"><a class=\"anchor\" href=\"#2101-它是什么\">#</a> 2.10.1　它是什么</h3>\n<p><strong>Grafana</strong> 是一个开源的度量分析与可视化套件，同样用 <strong>Go</strong> 开发。</p>\n<p>核心能力：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">能力</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>多数据源</strong></td>\n<td style=\"text-align:left\">Prometheus、Zabbix、Graphite、InfluxDB、Elasticsearch、MySQL… 一个界面对接所有</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>统一查询编辑器</strong></td>\n<td style=\"text-align:left\">每种数据源有自己的查询语言，Grafana 统一包装并保留各自特性</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>同屏混合展示</strong></td>\n<td style=\"text-align:left\">同一个 Dashboard 上可以混用多个数据源</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>海量现成模板</strong></td>\n<td style=\"text-align:left\"><a href=\"https://grafana.com/grafana/dashboards/\">https://grafana.com/grafana/dashboards/</a> 上有几万个社区面板</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>告警</strong></td>\n<td style=\"text-align:left\">内置 Grafana Alerting（本章不展开）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>默认端口</strong></td>\n<td style=\"text-align:left\"><strong>3000</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>自带  <code>/metrics</code> </strong></td>\n<td style=\"text-align:left\">能暴露自身运行指标给 Prometheus 采集</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>💡 <strong>和 Zabbix 的关键差异</strong>：Zabbix 内置的数据源能力有限（要装插件才支持某些源），而 <strong>Grafana 天生一等公民支持 Prometheus</strong>—— 数据源列表里 Prometheus 排第一。这也是 &quot;Prometheus + Grafana&quot; 成为事实标准组合的原因。</p>\n</blockquote>\n<h3 id=\"2102-安装deb-包\"><a class=\"anchor\" href=\"#2102-安装deb-包\">#</a> 2.10.2　安装（deb 包）</h3>\n<p>官方下载：<a href=\"https://grafana.com/grafana/download\">https://grafana.com/grafana/download</a></p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 官方源（慢）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">wget</span> https://dl.grafana.com/enterprise/release/grafana-enterprise_11.2.0_amd64.deb</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 或清华镜像（快）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">wget</span> https://mirrors.tuna.tsinghua.edu.cn/grafana/apt/pool/main/g/grafana-enterprise/grafana-enterprise_11.2.0_amd64.deb</pre></td></tr></table></figure><p><strong>三种安装方式，强烈推荐第 2 种</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ① dpkg 装：依赖需要手工解决</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>dpkg <span class=\"token parameter variable\">-i</span> grafana-enterprise_11.2.0_amd64.deb</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">apt</span> <span class=\"token parameter variable\">-y</span> --fix-broken <span class=\"token function\">install</span>          <span class=\"token comment\"># 缺依赖时补救</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ② apt 装本地 deb 文件：依赖自动解决  ⭐ 推荐</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token function\">apt</span> <span class=\"token parameter variable\">-y</span> <span class=\"token function\">install</span> ./grafana-enterprise_11.2.0_amd64.deb</pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># ③ 先装依赖再 dpkg（等价于 ①，但更可控）</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token function\">apt-get</span> <span class=\"token function\">install</span> <span class=\"token parameter variable\">-y</span> adduser libfontconfig1 musl</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>dpkg <span class=\"token parameter variable\">-i</span> grafana-enterprise_11.2.0_amd64.deb</pre></td></tr></table></figure><blockquote>\n<p>📌 <strong>为什么  <code>apt install ./xxx.deb</code>  比  <code>dpkg -i</code>  好？</strong><br />\n <code>dpkg</code>  只管解包，<strong>不解决依赖</strong>； <code>apt</code>  会自动把缺的包（如  <code>musl</code> 、 <code>libfontconfig1</code> ）一并装上。<strong>&quot;先装依赖还是先装包&quot; 这种顺序问题，用 apt 直接消失。</strong></p>\n</blockquote>\n<p>启动与验证：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl daemon-reload</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl <span class=\"token builtin class-name\">enable</span> <span class=\"token parameter variable\">--now</span> grafana-server.service</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>systemctl status grafana-server</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>ss <span class=\"token parameter variable\">-ntulp</span> <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token number\">3000</span></pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>关于 &quot;企业版&quot;</strong>： <code>grafana-enterprise</code>  <strong>并不是收费版</strong>，核心功能完全免费开源（Apache 2.0 部分 + AGPLv3 部分）。企业版只是额外包含了一些企业级特性（如 SSO、报表）。<strong>个人和中小团队放心用。</strong></p>\n</blockquote>\n<h3 id=\"2103-首次登录与添加数据源\"><a class=\"anchor\" href=\"#2103-首次登录与添加数据源\">#</a> 2.10.3　首次登录与添加数据源</h3>\n<pre><code>浏览器访问：http://&lt;grafana-ip&gt;:3000/\n默认账号密码：admin / admin\n</code></pre>\n<p>首次登录会要求改密码（可以跳过，生产环境请务必改）。</p>\n<p><strong>添加数据源</strong>（这是 Grafana 的 &quot;第一课&quot;，Zabbix 课程里也练过）：</p>\n<ol>\n<li>左侧菜单 → <strong>Connections → Data sources</strong>（或首页 &quot;Add your first data source&quot;）；</li>\n<li>选择 <strong>Prometheus</strong>（列表里排第一）；</li>\n<li><strong>Connection URL</strong> 填  <code>http://&lt;prometheus-ip&gt;:9090</code>\n<ul>\n<li>同一台机器上可以填  <code>http://localhost:9090</code> ；</li>\n</ul>\n</li>\n<li><strong>认证</strong>：Prometheus 默认无认证，留空；</li>\n<li>拉到最下面点 <strong>Save &amp; Test</strong>，看到绿色提示 <strong>&quot;Data source is working&quot;</strong> 即成功。</li>\n</ol>\n<blockquote>\n<p>⚠️ <strong>Grafana 服务端为你 &quot;代发请求&quot;</strong>：Grafana 后端会去访问那个 URL。所以填  <code>localhost:9090</code>  只在 <strong>Grafana 和 Prometheus 同机</strong>时才有效。分机部署时必须填 Prometheus 的真实 IP。</p>\n</blockquote>\n<h3 id=\"2104-认知难点内置-dashboard-为什么部分没数据\"><a class=\"anchor\" href=\"#2104-认知难点内置-dashboard-为什么部分没数据\">#</a> 2.10.4　⭐ 认知难点：内置 Dashboard 为什么 &quot;部分没数据&quot;</h3>\n<p>添加完 Prometheus 数据源后，Grafana 会自动提示导入三个内置面板：</p>\n<ul>\n<li><code>Prometheus Stats</code></li>\n<li><code>Prometheus 2.0 Stats</code></li>\n<li><code>Grafana metrics</code></li>\n</ul>\n<p>导入后你会发现：<strong>有的能显示，有的全是  <code>No data</code> 。</strong></p>\n<p>原因有两个，<strong>性质完全不同</strong>：</p>\n<p><strong>原因一：指标名变了（版本兼容问题）</strong></p>\n<p>内置模板是几年前写的，里面用的 PromQL 表达式引用的指标，在新版本 Prometheus 里可能已经改名或移除。</p>\n<p><strong>验证方法</strong>（非常值得掌握）：</p>\n<ol>\n<li>打开出问题面板 → 点 <strong>Edit</strong>（或 &quot;Panel options&quot;）；</li>\n<li>看下面的 <strong>Query</strong> 里的表达式，例如  <code>prometheus_tsdb_...</code> ；</li>\n<li>把这段表达式复制出来，粘到 <strong>Prometheus 的 Graph 页面</strong>执行；</li>\n<li>如果 Prometheus 里也查不到 → <strong>不是 Grafana 的问题，是这个指标在当前版本里不存在</strong>；</li>\n<li>反过来，在 Graph 页输入  <code>prometheus_</code>  前缀，看下拉提示里有哪些指标 —— 就能找到 &quot;改名后的那个&quot;。</li>\n</ol>\n<blockquote>\n<p>💡 <strong>这个排查手法适用于所有 &quot;面板没数据&quot; 的场景</strong>：<strong>永远先在 Prometheus 里验证表达式，再去怀疑 Grafana。</strong></p>\n</blockquote>\n<p><strong>原因二：数据源根本没被采集（逻辑问题）</strong></p>\n<p><code>Grafana metrics</code>  这个面板展示的是 <strong>Grafana 自身的指标</strong>。但你现在还<strong>没有让 Prometheus 去采集 Grafana</strong>—— 所以 Prometheus 里压根没有这些数据。详见 2.11 节，那里会完整解释这条 &quot;绕一圈&quot; 的链路。</p>\n<h3 id=\"2105-导入社区-dashboard-展示-node-exporter-数据\"><a class=\"anchor\" href=\"#2105-导入社区-dashboard-展示-node-exporter-数据\">#</a> 2.10.5　导入社区 Dashboard 展示 Node Exporter 数据</h3>\n<p>内置模板不适合看主机指标，得用社区模板。</p>\n<p><strong>第 1 步：找模板</strong></p>\n<p>访问 <a href=\"https://grafana.com/grafana/dashboards/\">https://grafana.com/grafana/dashboards/</a>，搜索  <code>node exporter</code> 。</p>\n<p><strong>第 2 步：筛选（关键）</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">筛选条件</th>\n<th style=\"text-align:left\">为什么</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>Data source = Prometheus</strong></td>\n<td style=\"text-align:left\">数据源必须匹配</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>按下载量 / 评分排序</strong></td>\n<td style=\"text-align:left\">经过大量用户验证，踩坑少</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>看更新时间</strong></td>\n<td style=\"text-align:left\">⭐ <strong>太老的模板别用</strong> —— 指标名可能已经变了，会重演 2.10.4 的 &quot;没数据&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>看是否中文</strong></td>\n<td style=\"text-align:left\">英文面板不是不能用，但中文面板日常更顺手</td>\n</tr>\n</tbody>\n</table>\n<p><strong>几个常用 ID</strong>（注意：ID 会随社区更新变化，请以官网当前状态为准）：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">ID</th>\n<th style=\"text-align:left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>1860</strong></td>\n<td style=\"text-align:left\">Node Exporter Full，英文 / 日文，更新较新，指标最全</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>8919</strong></td>\n<td style=\"text-align:left\">Node Exporter 中文版，日常查看更友好</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>16098</strong></td>\n<td style=\"text-align:left\">Node Exporter 中文版（另一套风格）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>10465</strong></td>\n<td style=\"text-align:left\">Zookeeper 监控（2.12 节会用到）</td>\n</tr>\n</tbody>\n</table>\n<p><strong>第 3 步：导入</strong></p>\n<pre><code>Grafana → Dashboards → New → Import\n→ 输入 Dashboard ID（如 1860）→ Load\n→ 选择数据源 Prometheus → Import\n</code></pre>\n<blockquote>\n<p>💡 <strong>两个实用技巧</strong>：</p>\n<ol>\n<li><strong>导入失败（网络拿不到 JSON）时</strong>，可以在官网页面直接下载 JSON 文件，再走 &quot;Upload JSON file&quot; 离线导入；</li>\n<li><strong>给面板改名时带上 ID</strong>，例如  <code>Node Exporter Full (1860)</code> —— 半年后你还能知道它是从哪来的。</li>\n</ol>\n</blockquote>\n<p><strong>第 4 步：看不到数据的四个检查点</strong></p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">检查点</th>\n<th style=\"text-align:left\">现象</th>\n<th style=\"text-align:left\">处理</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">节点上没装 Node Exporter</td>\n<td style=\"text-align:left\">面板全空</td>\n<td style=\"text-align:left\">装</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">Prometheus 没采集该节点</td>\n<td style=\"text-align:left\">部分主机空</td>\n<td style=\"text-align:left\">加 target + reload</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>浏览器时间与服务器时间差 &gt; 3 秒</strong></td>\n<td style=\"text-align:left\">数据 &quot;看起来是空的&quot;</td>\n<td style=\"text-align:left\">⭐ <strong>校时（NTP）</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">选了错误的数据源 / Cluster 变量</td>\n<td style=\"text-align:left\">全空或只有部分</td>\n<td style=\"text-align:left\">检查 Dashboard 顶部的变量下拉框</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ <strong>时间误差 &gt; 3 秒会导致查不到数据</strong>，这一条很多人不知道，遇到 &quot;明明有数据但图是空的&quot; 时，先  <code>date</code>  对比一下。</p>\n</blockquote>\n<h3 id=\"2106-时间显示utc-还是本地时间\"><a class=\"anchor\" href=\"#2106-时间显示utc-还是本地时间\">#</a> 2.10.6　时间显示：UTC 还是本地时间</h3>\n<p>Prometheus 内部<strong>统一使用 UTC</strong> 时间戳。Grafana 面板默认可能按 UTC 显示，导致 &quot;我明明下午 4 点起的服务，图上显示 8 点&quot;。</p>\n<p><strong>解决</strong>：Dashboard 右上角时间选择器 → 切到 <strong>Browser Time / Local</strong>。</p>\n<blockquote>\n<p>💡 这不是 bug，是时区约定。<strong>记住：Prometheus 存 UTC，展示时再转本地时区。</strong> 排查告警时间对不上时，先确认时区。</p>\n</blockquote>\n<hr />\n<h2 id=\"211-递归之美监控-grafana-自己\"><a class=\"anchor\" href=\"#211-递归之美监控-grafana-自己\">#</a> 2.11　递归之美：监控 Grafana 自己</h2>\n<h3 id=\"2111-那条绕一圈的链路\"><a class=\"anchor\" href=\"#2111-那条绕一圈的链路\">#</a> 2.11.1　那条 &quot;绕一圈&quot; 的链路</h3>\n<p>这是本章最反直觉、也最值得理解的一个知识点。</p>\n<p><strong>问题</strong>：我想在 Grafana 上看到 Grafana 自己的指标，怎么办？</p>\n<p><strong>直觉答案</strong>：Grafana 自己展示自己就行了嘛。</p>\n<p><strong>正确答案</strong>：不行。<strong>必须绕一圈。</strong></p>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">flowchart</span> LR</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    G1<span class=\"token text string\">[\"Grafana&lt;br/>:3000/metrics&lt;br/>（自带暴露能力）\"]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    P<span class=\"token text string\">[\"Prometheus Server&lt;br/>:9090\"]</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    G2<span class=\"token text string\">[\"Grafana&lt;br/>Dashboard&lt;br/>（数据源指向 Prometheus）\"]</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    G1 <span class=\"token arrow operator\">--></span><span class=\"token label property\">|\"① Prometheus Pull 采集\"|</span> P</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    P <span class=\"token arrow operator\">--></span><span class=\"token label property\">|\"② Grafana 用 PromQL 查询\"|</span> G2</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    G2 <span class=\"token arrow operator\">-.-></span><span class=\"token label property\">|\"③ 画出来的就是 Grafana 自己的指标\"|</span> G1</pre></td></tr></table></figure><p><strong>为什么必须这样？</strong></p>\n<blockquote>\n<p><strong>Grafana 是 &quot;展示层&quot;，不是 &quot;数据源&quot;。它只能从数据源读数据，而它自己不是数据源。</strong></p>\n</blockquote>\n<p>即使要展示 Grafana 自己的指标，也必须：</p>\n<ol>\n<li>Grafana 把自身指标暴露在  <code>:3000/metrics</code> ；</li>\n<li><strong>Prometheus 去采集它</strong>（在  <code>prometheus.yml</code>  里加一个 job）；</li>\n<li>Grafana 通过 Prometheus 数据源把这些指标查出来画图。</li>\n</ol>\n<p><strong>同理可推</strong>：Prometheus 自己的指标也是这么来的 ——Prometheus 默认就采集自己（ <code>localhost:9090</code> ），所以  <code>Prometheus Stats</code>  面板有数据；而  <code>Grafana metrics</code>  面板没数据，因为<strong>没人去采集 Grafana</strong>。</p>\n<h3 id=\"2112-配置\"><a class=\"anchor\" href=\"#2112-配置\">#</a> 2.11.2　配置</h3>\n<p>先验证 Grafana 确实暴露了指标：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://localhost:3000/metrics <span class=\"token operator\">|</span> <span class=\"token function\">head</span> <span class=\"token parameter variable\">-20</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># HELP go_gc_duration_seconds ...</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># HELP grafana_api_response_status_total ...</span></pre></td></tr></table></figure><p>然后在  <code>prometheus.yml</code>  里加一个 job：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'grafana'</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'10.0.0.100:3000'</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>promtool check config /usr/local/prometheus/conf/prometheus.yml</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl reload prometheus</pre></td></tr></table></figure><p>验证：</p>\n<figure class=\"highlight promql\"><figcaption data-lang=\"promql\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>up<span class=\"token context-labels\"><span class=\"token punctuation\">&#123;</span><span class=\"token label-key attr-name\">job</span><span class=\"token punctuation\">=</span><span class=\"token label-value attr-value\">\"grafana\"</span><span class=\"token punctuation\">&#125;</span></span>          # 应为 <span class=\"token number\">1</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>grafana_http_request_duration_seconds_count   # 应该有数据了</pre></td></tr></table></figure><p>回到 Grafana，刷新  <code>Grafana metrics</code>  面板 ——<strong> 数据出来了</strong>。</p>\n<h3 id=\"2113-由此总结出的一条重要分类\"><a class=\"anchor\" href=\"#2113-由此总结出的一条重要分类\">#</a> 2.11.3　由此总结出的一条重要分类</h3>\n<p>现在我们可以把 &quot;指标从哪来&quot; 分成三类，这是理解 Exporter 生态的钥匙：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">类型</th>\n<th style=\"text-align:left\">特征</th>\n<th style=\"text-align:left\">例子</th>\n<th style=\"text-align:left\">需要额外装 Exporter 吗</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>① 天生自带</strong></td>\n<td style=\"text-align:left\">软件内部主动暴露  <code>/metrics</code></td>\n<td style=\"text-align:left\"><strong>Prometheus 自己</strong>、<strong>Grafana</strong>、Zookeeper、Nacos、Etcd、Traefik</td>\n<td style=\"text-align:left\">❌ <strong>不需要</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>② 需要 Exporter</strong></td>\n<td style=\"text-align:left\">软件本身没有 HTTP 指标端点（尤其老软件）</td>\n<td style=\"text-align:left\"><strong>Linux 系统</strong>（→ node_exporter）、<strong>MySQL</strong>（→ mysqld_exporter）、<strong>Redis</strong>（→ redis_exporter）、Nginx、HAProxy</td>\n<td style=\"text-align:left\">✅ 需要</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>③ 只能推</strong></td>\n<td style=\"text-align:left\">生命周期太短或无法被访问</td>\n<td style=\"text-align:left\">一次性脚本、定时任务、批处理作业</td>\n<td style=\"text-align:left\">✅ 用 Pushgateway</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>🧠 <strong>一句话决策法</strong>：<br />\n<strong>先  <code>curl http://&lt;软件&gt;:&lt;端口&gt;/metrics</code>  试试。</strong><br />\n有 → 直接加 job 采；没有 → 找对应 Exporter；连 &quot;常驻&quot; 都做不到 → 上 Pushgateway。</p>\n</blockquote>\n<hr />\n<h2 id=\"212-pushgateway给抓不到的指标开一扇门\"><a class=\"anchor\" href=\"#212-pushgateway给抓不到的指标开一扇门\">#</a> 2.12　Pushgateway：给 &quot;抓不到&quot; 的指标开一扇门</h2>\n<h3 id=\"2121-为什么会有这个组件\"><a class=\"anchor\" href=\"#2121-为什么会有这个组件\">#</a> 2.12.1　为什么会有这个组件</h3>\n<p>考虑一个真实需求：<strong>统计当前有多少用户登录在这台机器上。</strong></p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">who</span> <span class=\"token operator\">|</span> <span class=\"token function\">wc</span> <span class=\"token parameter variable\">-l</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># 1</span></pre></td></tr></table></figure><p>就一个数字。但问题是：</p>\n<ul>\n<li>它是<strong>由一条命令临时算出来的</strong>，不是某个常驻服务持续提供；</li>\n<li>机器上<strong>没有 HTTP 服务</strong>去暴露这个数字；</li>\n<li>Prometheus 只会  <code>GET /metrics</code> —— 它没法 &quot;执行一条命令&quot;。</li>\n</ul>\n<p><strong>Prometheus 抓不到它。</strong> 这就是 Pushgateway 存在的理由。</p>\n<h3 id=\"2122-工作原理一个代收点\"><a class=\"anchor\" href=\"#2122-工作原理一个代收点\">#</a> 2.12.2　工作原理：一个 &quot;代收点&quot;</h3>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">sequenceDiagram</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token keyword\">participant</span> J as 脚本或定时任务</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token keyword\">participant</span> PG as Pushgateway-9091</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token keyword\">participant</span> P as Prometheus-9090</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    J<span class=\"token arrow operator\">->></span>PG<span class=\"token operator\">:</span> ① HTTP POST 推送指标（主动推）</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    <span class=\"token keyword\">Note over</span> PG<span class=\"token operator\">:</span> ② 暂存指标（不会自动过期！）</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    P<span class=\"token arrow operator\">->></span>PG<span class=\"token operator\">:</span> ③ GET /metrics（Pull 拉取）</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    PG<span class=\"token arrow operator\">-->></span>P<span class=\"token operator\">:</span> 返回暂存的指标</pre></td></tr></table></figure><p><strong>它就是一个 &quot;代理 / 中转站&quot;</strong>：</p>\n<blockquote>\n<p>你没有 HTTP 服务？<strong>我替你有。</strong><br />\n你把数据交给我（POST /metrics），我挂在  <code>/metrics</code>  上等 Prometheus 来拉。</p>\n</blockquote>\n<p><strong>关键结论：Pushgateway 并没有改变 Prometheus&quot;只拉不推&quot; 的本质</strong> —— 它只是给 &quot;无法被拉&quot; 的目标，额外增加了一个 &quot;可以被拉&quot; 的中转点。数据链路的最后一跳，<strong>仍然是 Pull</strong>。</p>\n<h3 id=\"2123-与-exporter-与-zabbix-proxy-的对照\"><a class=\"anchor\" href=\"#2123-与-exporter-与-zabbix-proxy-的对照\">#</a> 2.12.3　与 Exporter、与 Zabbix Proxy 的对照</h3>\n<p>这是最容易混淆的一组概念，用表格彻底分清：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">维度</th>\n<th style=\"text-align:left\"><strong>Exporter</strong></th>\n<th style=\"text-align:left\"><strong>Pushgateway</strong></th>\n<th style=\"text-align:left\"><strong>Zabbix Proxy</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">采集方向</td>\n<td style=\"text-align:left\"><strong>被动</strong>（等 Prometheus 来拉）</td>\n<td style=\"text-align:left\"><strong>主动接收</strong>（应用推过来）</td>\n<td style=\"text-align:left\">主动采集后上报</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">装在哪儿</td>\n<td style=\"text-align:left\">⭐ <strong>每个被监控节点都要装一个</strong></td>\n<td style=\"text-align:left\">⭐ <strong>只装一个</strong>（任何位置都行，不必在被监控端）</td>\n<td style=\"text-align:left\">每个区域 / 网段一个</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">是否需要专属</td>\n<td style=\"text-align:left\">⭐ <strong>每种应用一个专用 Exporter</strong>（MySQL、Redis 各有各的）</td>\n<td style=\"text-align:left\"><strong>一个就够，所有应用都能往它推</strong></td>\n<td style=\"text-align:left\">一个通用的即可</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">类比</td>\n<td style=\"text-align:left\"><strong> <code>zabbix-agent</code> </strong></td>\n<td style=\"text-align:left\"><strong> <code>zabbix-proxy</code> </strong></td>\n<td style=\"text-align:left\"><code>zabbix-proxy</code></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>🧠 <strong>记忆锚点</strong>：</p>\n<ul>\n<li><strong>Exporter 是 &quot;每个应用配一个专用翻译官&quot;</strong>——MySQL 的翻译官不懂 Redis 的话。</li>\n<li><strong>Pushgateway 是 &quot;一个公共收件箱&quot;</strong>—— 谁都能往里投信，它不挑。</li>\n</ul>\n</blockquote>\n<h3 id=\"2124-必须知道的四个固有缺陷\"><a class=\"anchor\" href=\"#2124-必须知道的四个固有缺陷\">#</a> 2.12.4　必须知道的四个固有缺陷</h3>\n<p>Pushgateway 官方文档明确定义了这些局限，<strong>面试常问，生产必知</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">缺陷</th>\n<th style=\"text-align:left\">具体表现</th>\n<th style=\"text-align:left\">后果</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>① 单点瓶颈</strong></td>\n<td style=\"text-align:left\">只有一份 Pushgateway，多个应用同时推送</td>\n<td style=\"text-align:left\">进程挂了 → 全链路数据中断</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>②  <code>up</code>  指标失效</strong></td>\n<td style=\"text-align:left\">Prometheus 只能看到 Pushgateway 是否活着，<strong>看不到真实应用是否活着</strong></td>\n<td style=\"text-align:left\">⭐ <strong>服务挂了，旧数据还在，图表上一片 &quot;正常&quot;—— 假存活！</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>③ 永不清理</strong></td>\n<td style=\"text-align:left\">推上去的数据<strong>永久保留</strong>并持续暴露，除非手动 DELETE</td>\n<td style=\"text-align:left\">已下线任务的指标一直 &quot;诈尸&quot;</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>④ 不做校验</strong></td>\n<td style=\"text-align:left\">脚本算错了、推了脏数据，它<strong>照单全收</strong></td>\n<td style=\"text-align:left\">错误数据进入 TSDB，无法追溯</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>🚨 <strong>② 号缺陷最危险</strong>。举个真实场景：你的备份任务每天推一次 &quot;备份成功 = 1&quot;。某天任务彻底挂了，不再推送 —— 但 Pushgateway 上那条  <code>backup_success 1</code>  <strong>还在</strong>，Prometheus 一直抓到  <code>1</code> ，你的大屏一直显示 &quot;备份正常&quot;。<strong>你会在真正需要备份的那天发现它已经坏了三个月。</strong></p>\n<p><strong>应对</strong>：在<strong>应用侧</strong>实现 &quot;心跳 / 时间戳&quot; 指标，用  <code>time() - backup_last_success_timestamp &gt; 86400</code>  这类表达式告警。<strong>不要指望  <code>up</code> 。</strong></p>\n</blockquote>\n<h3 id=\"2125-安装\"><a class=\"anchor\" href=\"#2125-安装\">#</a> 2.12.5　安装</h3>\n<p>官方下载：<a href=\"https://prometheus.io/download/\">https://prometheus.io/download/</a> 或 <a href=\"https://github.com/prometheus/pushgateway/releases\">https://github.com/prometheus/pushgateway/releases</a></p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token builtin class-name\">cd</span> /usr/local</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">wget</span> https://github.com/prometheus/pushgateway/releases/download/v1.10.0/pushgateway-1.10.0.linux-amd64.tar.gz</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">tar</span> xf pushgateway-1.10.0.linux-amd64.tar.gz <span class=\"token parameter variable\">-C</span> /usr/local/</pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token function\">ln</span> <span class=\"token parameter variable\">-s</span> pushgateway-1.10.0.linux-amd64 pushgateway</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token function\">mkdir</span> <span class=\"token parameter variable\">-p</span> /usr/local/pushgateway/bin</pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token function\">mv</span> /usr/local/pushgateway/pushgateway /usr/local/pushgateway/bin/</pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token function\">useradd</span> <span class=\"token parameter variable\">-r</span> <span class=\"token parameter variable\">-s</span> /sbin/nologin prometheus</pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token function\">chown</span> <span class=\"token parameter variable\">-R</span> prometheus:prometheus /usr/local/pushgateway/</pre></td></tr></table></figure><p>service 文件：</p>\n<figure class=\"highlight ini\"><figcaption data-lang=\"ini\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Unit</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key attr-name\">Description</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">Prometheus Pushgateway</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key attr-name\">After</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">network.target</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Service</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key attr-name\">Type</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">simple</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key attr-name\">ExecStart</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/usr/local/pushgateway/bin/pushgateway</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token key attr-name\">ExecReload</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">/bin/kill -HUP $MAINPID</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token key attr-name\">Restart</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">on-failure</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token key attr-name\">User</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">prometheus</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key attr-name\">Group</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">prometheus</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">Install</span><span class=\"token punctuation\">]</span></span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token key attr-name\">WantedBy</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">multi-user.target</span></pre></td></tr></table></figure><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl daemon-reload</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl <span class=\"token builtin class-name\">enable</span> <span class=\"token parameter variable\">--now</span> pushgateway.service</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>ss <span class=\"token parameter variable\">-ntlp</span> <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token number\">9091</span></pre></td></tr></table></figure><p>浏览器访问  <code>http://&lt;ip&gt;:9091/</code>  —— 界面是<strong>空的</strong>，因为还没人往里推过东西。这正是它的本质：<strong>数据不来自它自己，来自 &quot;推给它的应用&quot;。</strong></p>\n<blockquote>\n<p>💡 <strong>但它自己也需要被监控</strong> —— <code>http://&lt;ip&gt;:9091/metrics</code>  里能看到它自身的指标（请求数、推送成功数等）。所以按 2.11 节的分类，它属于 &quot;<strong>① 天生自带</strong> &quot;，直接加 job 采就行。</p>\n</blockquote>\n<h3 id=\"2126-让-prometheus-采集-pushgateway\"><a class=\"anchor\" href=\"#2126-让-prometheus-采集-pushgateway\">#</a> 2.12.6　让 Prometheus 采集 Pushgateway</h3>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"pushgateway\"</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token key atrule\">honor_labels</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>          <span class=\"token comment\"># ⭐ 关键</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">scrape_interval</span><span class=\"token punctuation\">:</span> 10s</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"10.0.0.100:9091\"</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure><p><strong> <code>honor_labels: true</code>  到底解决什么问题？</strong></p>\n<p>不加它时，Prometheus 会把自己配置里的  <code>job=&quot;pushgateway&quot;</code>  和  <code>instance=&quot;10.0.0.100:9091&quot;</code>  <strong>强加</strong>到所有指标上 —— 于是<strong>所有应用推上来的指标看起来都来自同一台机器</strong>，标签全被覆盖了。</p>\n<p>加上它之后，<strong>Pushgateway 上的  <code>job</code>  /  <code>instance</code>  标签优先保留</strong>，Prometheus 自己的标签会被改名为  <code>exported_job</code>  /  <code>exported_instance</code> 。这样你才能区分 &quot;这条指标是哪个应用推的&quot;。</p>\n<blockquote>\n<p>⚠️ <strong>所以：采集 Pushgateway， <code>honor_labels: true</code>  几乎是必选项。</strong></p>\n</blockquote>\n<p>也支持文件形式自动发现：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> pushgateway</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token key atrule\">honor_labels</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">file_sd_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">files</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>      <span class=\"token punctuation\">-</span> targets/pushgateway/<span class=\"token important\">*.json</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token key atrule\">refresh_interval</span><span class=\"token punctuation\">:</span> 5m</pre></td></tr></table></figure><figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// targets/pushgateway/test.json</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span><span class=\"token punctuation\">&#123;</span><span class=\"token property\">\"targets\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"pushgateway1.example.com:9091\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure><h3 id=\"2127-推送数据url-格式详解\"><a class=\"anchor\" href=\"#2127-推送数据url-格式详解\">#</a> 2.12.7　推送数据：URL 格式详解</h3>\n<pre><code>http://&lt;pg-addr&gt;:&lt;pg-port&gt;/metrics/job/&lt;job_name&gt;/[&lt;label_name&gt;/&lt;label_value&gt;]/...\n</code></pre>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">路径片段</th>\n<th style=\"text-align:left\">作用</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code>/metrics</code></td>\n<td style=\"text-align:left\">固定接收接口</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>/job/&lt;job_name&gt;</code></td>\n<td style=\"text-align:left\">设置  <code>job</code>  标签</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>/instance/&lt;value&gt;</code></td>\n<td style=\"text-align:left\">设置  <code>instance</code>  标签</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">其它  <code>&lt;label&gt;/&lt;value&gt;</code></td>\n<td style=\"text-align:left\">任意附加标签</td>\n</tr>\n</tbody>\n</table>\n<p><strong>最小示例</strong>（推一条： <code>age = 18</code> ）：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"age 18\"</span> <span class=\"token operator\">|</span> <span class=\"token function\">curl</span> --data-binary @- <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  http://pushgateway.example.com:9091/metrics/job/demo/instance/<span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">hostname</span> <span class=\"token parameter variable\">-I</span> <span class=\"token operator\">|</span> <span class=\"token function\">awk</span> <span class=\"token string\">'&#123;print $1&#125;'</span><span class=\"token variable\">)</span></span></pre></td></tr></table></figure><ul>\n<li><code>echo &quot;age 18&quot;</code> ：生成一行 Prometheus 格式的指标；</li>\n<li><code>|</code> ：管道，把内容交给 curl 的 stdin；</li>\n<li><code>--data-binary @-</code> ：从标准输入原样读取并 POST（<strong>注意用  <code>--data-binary</code> ，不要用  <code>-d</code> </strong>，后者会处理换行符）；</li>\n<li><code>/job/demo</code> ：这条指标的  <code>job</code>  标签是  <code>demo</code> ；</li>\n<li><code>/instance/&lt;ip&gt;</code> ： <code>instance</code>  标签是当前主机第一个 IP。</li>\n</ul>\n<p><strong>带类型与帮助的完整示例</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">cat</span> <span class=\"token operator\">&lt;&lt;</span><span class=\"token string\">EOF<span class=\"token bash punctuation\"> <span class=\"token operator\">|</span> <span class=\"token function\">curl</span> --data-binary @- http://pushgateway.example.com:9091/metrics/job/some_job/instance/some_instance</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre># TYPE some_metric counter</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>some_metric&#123;label=\"val1\"&#125; 42</pre></td></tr><tr><td data-num=\"4\"></td><td><pre># TYPE another_metric gauge</pre></td></tr><tr><td data-num=\"5\"></td><td><pre># HELP another_metric Just an example.</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>another_metric 2398.283</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>EOF</span></pre></td></tr></table></figure><p>三者作用（呼应第 1 章）：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">行</th>\n<th style=\"text-align:left\">作用</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><code># TYPE</code></td>\n<td style=\"text-align:left\">声明类型（counter /gauge/histogram /summary/untyped）</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code># HELP</code></td>\n<td style=\"text-align:left\">人类可读的说明，Grafana 面板会显示</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><code>some_metric&#123;...&#125; 42</code></td>\n<td style=\"text-align:left\">真正的样本： <code>指标名&#123;标签&#125; 值</code></td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"2128-删除数据重要别只会推不会删\"><a class=\"anchor\" href=\"#2128-删除数据重要别只会推不会删\">#</a> 2.12.8　删除数据（重要，别只会推不会删）</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 删除某个组下的全部指标</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-X</span> DELETE http://pushgateway.example.com:9091/metrics/job/some_job/instance/some_instance</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 删除某个 job 下的全部指标</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-X</span> DELETE http://pushgateway.example.com:9091/metrics/job/some_job</pre></td></tr></table></figure><p>也可以直接在 Pushgateway 的 Web 界面点删除按钮。</p>\n<blockquote>\n<p>⚠️ <strong>生产纪律</strong>：<strong>任何上线了又下线的任务，必须清理它在 Pushgateway 上的残留</strong>。否则那些 &quot;僵尸指标&quot; 会一直出现在查询结果里，污染图表和告警判断。</p>\n</blockquote>\n<h3 id=\"2129-生产可用脚本\"><a class=\"anchor\" href=\"#2129-生产可用脚本\">#</a> 2.12.9　生产可用脚本</h3>\n<p>一个通用的自定义指标推送脚本，把 &quot;采集命令&quot; 和 &quot;推送&quot; 解耦：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token shebang important\">#!/bin/bash</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token builtin class-name\">set</span> <span class=\"token parameter variable\">-uo</span> pipefail</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># ===== 只改这几行：想监控什么，就换 METRIC_* =====</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token assign-left variable\">METRIC_NAME</span><span class=\"token operator\">=</span><span class=\"token string\">\"login_number\"</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token assign-left variable\">METRIC_VALUE_CMD</span><span class=\"token operator\">=</span><span class=\"token string\">'who | wc -l'</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token assign-left variable\">METRIC_TYPE</span><span class=\"token operator\">=</span><span class=\"token string\">\"gauge\"</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token assign-left variable\">METRIC_HELP</span><span class=\"token operator\">=</span><span class=\"token string\">\"Current login user number\"</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token assign-left variable\">PUSHGATEWAY_HOST</span><span class=\"token operator\">=</span><span class=\"token string\">\"pushgateway.example.com:9091\"</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token assign-left variable\">JOB_NAME</span><span class=\"token operator\">=</span><span class=\"token string\">\"custom_metrics\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token assign-left variable\"><span class=\"token environment constant\">INSTANCE</span></span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">hostname</span> <span class=\"token parameter variable\">-I</span> <span class=\"token operator\">|</span> <span class=\"token function\">awk</span> <span class=\"token string\">'&#123;print $1&#125;'</span><span class=\"token variable\">)</span></span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token assign-left variable\">INTERVAL</span><span class=\"token operator\">=</span><span class=\"token number\">60</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token assign-left variable\">PUSH_URL</span><span class=\"token operator\">=</span><span class=\"token string\">\"http://<span class=\"token variable\">$&#123;PUSHGATEWAY_HOST&#125;</span>/metrics/job/<span class=\"token variable\">$&#123;JOB_NAME&#125;</span>/instance/<span class=\"token variable\">$&#123;<span class=\"token environment constant\">INSTANCE</span>&#125;</span>\"</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token builtin class-name\">trap</span> <span class=\"token string\">'echo \"[$(date \"+%F %T\")] Exit.\"; exit 0'</span> INT <span class=\"token environment constant\">TERM</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token keyword\">while</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">do</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    <span class=\"token assign-left variable\">VALUE</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token builtin class-name\">eval</span> <span class=\"token string\">\"<span class=\"token variable\">$METRIC_VALUE_CMD</span>\"</span><span class=\"token variable\">)</span></span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token function\">cat</span> <span class=\"token operator\">&lt;&lt;</span><span class=\"token string\">EOF<span class=\"token bash punctuation\"> <span class=\"token operator\">|</span> <span class=\"token function\">curl</span> <span class=\"token parameter variable\">--silent</span> --show-error <span class=\"token parameter variable\">--fail</span> --data-binary @- <span class=\"token string\">\"<span class=\"token variable\">$PUSH_URL</span>\"</span> <span class=\"token operator\">></span>/dev/null</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre># HELP <span class=\"token variable\">$&#123;METRIC_NAME&#125;</span> <span class=\"token variable\">$&#123;METRIC_HELP&#125;</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre># TYPE <span class=\"token variable\">$&#123;METRIC_NAME&#125;</span> <span class=\"token variable\">$&#123;METRIC_TYPE&#125;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre><span class=\"token variable\">$&#123;METRIC_NAME&#125;</span> <span class=\"token variable\">$&#123;VALUE&#125;</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>EOF</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">[</span> <span class=\"token variable\">$?</span> <span class=\"token parameter variable\">-eq</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>        <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"[<span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">date</span> <span class=\"token string\">'+%F %T'</span><span class=\"token variable\">)</span></span>] Push OK: <span class=\"token variable\">$&#123;METRIC_NAME&#125;</span>=<span class=\"token variable\">$&#123;VALUE&#125;</span>\"</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>    <span class=\"token keyword\">else</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre>        <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"[<span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">date</span> <span class=\"token string\">'+%F %T'</span><span class=\"token variable\">)</span></span>] Push FAILED!\"</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre>    <span class=\"token keyword\">fi</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre></pre></td></tr><tr><td data-num=\"34\"></td><td><pre>    <span class=\"token function\">sleep</span> <span class=\"token string\">\"<span class=\"token variable\">$&#123;INTERVAL&#125;</span>\"</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre><span class=\"token keyword\">done</span></pre></td></tr></table></figure><p><strong>从 &quot;一次性任务&quot; 推数据</strong>，交给 cron 定时执行。但<strong>不要写超长的单行 cron 命令</strong>（引号嵌套会把你逼疯），正确做法是<strong>先写一个小脚本，cron 只负责调用它</strong>：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 写脚本 /usr/local/bin/push_login_number.sh</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\">#!/bin/bash</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token builtin class-name\">set</span> <span class=\"token parameter variable\">-euo</span> pipefail</pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token assign-left variable\">PG</span><span class=\"token operator\">=</span><span class=\"token string\">\"http://pushgateway.example.com:9091\"</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token assign-left variable\">IP</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">hostname</span> <span class=\"token parameter variable\">-I</span> <span class=\"token operator\">|</span> <span class=\"token function\">awk</span> <span class=\"token string\">'&#123;print $1&#125;'</span><span class=\"token variable\">)</span></span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token assign-left variable\">N</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">who</span> <span class=\"token operator\">|</span> <span class=\"token function\">wc</span> <span class=\"token parameter variable\">-l</span><span class=\"token variable\">)</span></span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token function\">cat</span> <span class=\"token operator\">&lt;&lt;</span><span class=\"token string\">EOF<span class=\"token bash punctuation\"> <span class=\"token operator\">|</span> <span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> <span class=\"token parameter variable\">--fail</span> --data-binary @- <span class=\"token string\">\"<span class=\"token variable\">$&#123;PG&#125;</span>/metrics/job/custom_metrics/instance/<span class=\"token variable\">$&#123;IP&#125;</span>\"</span> <span class=\"token operator\">></span>/dev/null</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre># HELP login_number Current login user number</pre></td></tr><tr><td data-num=\"9\"></td><td><pre># TYPE login_number gauge</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>login_number <span class=\"token variable\">$&#123;N&#125;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>EOF</span></pre></td></tr></table></figure><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 2. 授权</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">chmod</span> +x /usr/local/bin/push_login_number.sh</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 3. cron 只负责调用脚本（/etc/cron.d/push_login_number）</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>*/5 * * * * root /usr/local/bin/push_login_number.sh</pre></td></tr></table></figure><blockquote>\n<p>💡 <strong>脚本里的三个好习惯</strong>：</p>\n<ol>\n<li><strong> <code>--fail</code> </strong>：HTTP 4xx/5xx 时让 curl 返回非 0，从而能判断推送失败；</li>\n<li><strong>输出成功 / 失败日志</strong>：不然任务 &quot;看起来在跑&quot;，其实一直在失败；</li>\n<li><strong> <code>trap</code>  优雅退出</strong>：systemd 停止服务时不会留下僵尸循环。</li>\n</ol>\n</blockquote>\n<h3 id=\"21210-验证\"><a class=\"anchor\" href=\"#21210-验证\">#</a> 2.12.10　验证</h3>\n<ol>\n<li><strong>Pushgateway 页面</strong>： <code>http://&lt;ip&gt;:9091/</code>  能看到你推上去的指标组；</li>\n<li><strong>Prometheus Graph</strong>：查  <code>login_number</code>  或  <code>mem_free</code> ，能看到数据。</li>\n</ol>\n<blockquote>\n<p>⚠️ 这里有个小陷阱：如果  <code>honor_labels: true</code>  没配，你在 Prometheus 里查到的  <code>instance</code>  是 <strong>Pushgateway 的地址</strong>，而不是推送方的地址。查不到特定主机的数据时，先检查这一点。</p>\n</blockquote>\n<hr />\n<h2 id=\"213-一个完整例子监控-zookeeper\"><a class=\"anchor\" href=\"#213-一个完整例子监控-zookeeper\">#</a> 2.13　一个完整例子：监控 Zookeeper</h2>\n<p>前面所有例子里，被监控对象要么 &quot;本来没有指标&quot;（Linux），要么 &quot;指标要中转&quot;（脚本）。Zookeeper 属于第三类：<strong>软件自己就能开指标端口</strong>。</p>\n<h3 id=\"2131-三种指标来源分类\"><a class=\"anchor\" href=\"#2131-三种指标来源分类\">#</a> 2.13.1　三种指标来源分类</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">来源</th>\n<th style=\"text-align:left\">例子</th>\n<th style=\"text-align:left\">要点</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\"><strong>① 软件内置</strong></td>\n<td style=\"text-align:left\">Grafana、Zookeeper、Nacos、Etcd</td>\n<td style=\"text-align:left\">改配置打开即可，<strong>不用装 Exporter</strong></td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>② 第三方 Exporter</strong></td>\n<td style=\"text-align:left\">MySQL、Redis、Nginx</td>\n<td style=\"text-align:left\">需要单独部署 exporter</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>③ Pushgateway</strong></td>\n<td style=\"text-align:left\">一次性脚本、定时任务</td>\n<td style=\"text-align:left\">主动推</td>\n</tr>\n<tr>\n<td style=\"text-align:left\"><strong>④ 自行编程</strong></td>\n<td style=\"text-align:left\">业务指标</td>\n<td style=\"text-align:left\">需要开发能力，用客户端库</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"2132-打开-zookeeper-的内置指标端点\"><a class=\"anchor\" href=\"#2132-打开-zookeeper-的内置指标端点\">#</a> 2.13.2　打开 Zookeeper 的内置指标端点</h3>\n<p>Zookeeper 的  <code>zoo_sample.cfg</code>  里已经<strong>预置</strong>了 Prometheus 相关注释，取消注释即可：</p>\n<figure class=\"highlight properties\"><figcaption data-lang=\".properties\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 在 zoo.cfg 末尾添加（模板里默认就有，只是被注释了）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key attr-name\">metricsProvider.className</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key attr-name\">metricsProvider.httpPort</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">7000</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token key attr-name\">metricsProvider.exportJvmInfo</span><span class=\"token punctuation\">=</span><span class=\"token value attr-value\">true</span></pre></td></tr></table></figure><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl restart zookeeper.service</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">curl</span> http://localhost:7000/metrics <span class=\"token operator\">|</span> <span class=\"token function\">head</span></pre></td></tr></table></figure><blockquote>\n<p>💡 <strong> <code>metricsProvider.httpPort=7000</code> </strong> 就是这个软件给自己开的 &quot;出口&quot;。<strong>凡是能在某个端口  <code>curl</code>  到  <code>/metrics</code>  的软件，都不需要额外装 Exporter。</strong></p>\n</blockquote>\n<h3 id=\"2133-加-job看数据\"><a class=\"anchor\" href=\"#2133-加-job看数据\">#</a> 2.13.3　加 job，看数据</h3>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">job_name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'zookeeper'</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>    <span class=\"token key atrule\">static_configs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">targets</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'10.0.0.101:7000'</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>promtool check config /usr/local/prometheus/conf/prometheus.yml</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>systemctl reload prometheus</pre></td></tr></table></figure><ul>\n<li><strong>Prometheus</strong> → Status → Targets，确认  <code>zookeeper</code>  是 UP；</li>\n<li><strong>Grafana</strong> → 导入社区模板（如 <strong>ID 10465</strong>）→ 注意在面板顶部<strong>选对 Cluster 变量</strong>，否则显示为空。</li>\n</ul>\n<hr />\n<h2 id=\"214-本章小结\"><a class=\"anchor\" href=\"#214-本章小结\">#</a> 2.14　本章小结</h2>\n<figure class=\"highlight mermaid\"><figcaption data-lang=\"mermaid\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>mindmap</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  root<span class=\"token text string\">((\"第2章&lt;br/>部署与点亮\"))</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    五个软件</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>      Prometheus 9090 采集+存储</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>      Node Exporter 9100 系统指标</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      Grafana 3000 展示</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>      Alertmanager 9093 告警</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>      Pushgateway 9091 中转</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    安装方式</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>      包安装 快但版本旧</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      二进制 生产标准</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>      容器 注意挂载</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>      Ansible 批量</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    关键参数</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>      config.file</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>      storage.tsdb.path</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>      storage.tsdb.retention.time</pre></td></tr><tr><td data-num=\"18\"></td><td><pre>      web.enable-lifecycle 危险</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    配置文件</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>      global</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>      alerting</pre></td></tr><tr><td data-num=\"22\"></td><td><pre>      rule_files</pre></td></tr><tr><td data-num=\"23\"></td><td><pre>      scrape_configs</pre></td></tr><tr><td data-num=\"24\"></td><td><pre>    踩过的坑</pre></td></tr><tr><td data-num=\"25\"></td><td><pre>      root启动污染权限</pre></td></tr><tr><td data-num=\"26\"></td><td><pre>      YAML缩进</pre></td></tr><tr><td data-num=\"27\"></td><td><pre>      端口写错</pre></td></tr><tr><td data-num=\"28\"></td><td><pre>      容器内配置文件</pre></td></tr><tr><td data-num=\"29\"></td><td><pre>      指标有延迟</pre></td></tr><tr><td data-num=\"30\"></td><td><pre>      uname采集器</pre></td></tr><tr><td data-num=\"31\"></td><td><pre>    Pushgateway</pre></td></tr><tr><td data-num=\"32\"></td><td><pre>      up指标失效</pre></td></tr><tr><td data-num=\"33\"></td><td><pre>      永不清理</pre></td></tr><tr><td data-num=\"34\"></td><td><pre>      单点</pre></td></tr><tr><td data-num=\"35\"></td><td><pre>      不校验</pre></td></tr></table></figure><p><strong>六条必须记住的运维经验</strong>：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">#</th>\n<th style=\"text-align:left\">经验</th>\n<th style=\"text-align:left\">出处</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">1</td>\n<td style=\"text-align:left\"><strong>调试用哪个身份启动，生产就用哪个身份</strong></td>\n<td style=\"text-align:left\">root 污染 data 目录</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">2</td>\n<td style=\"text-align:left\"><strong> <code>--web.enable-lifecycle</code>  生产禁用</strong></td>\n<td style=\"text-align:left\">一行 curl 就能远程关掉服务</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">3</td>\n<td style=\"text-align:left\"><strong>改配置：先  <code>promtool check config</code> ，再 reload，再查 Targets</strong></td>\n<td style=\"text-align:left\">三步固定流程</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">4</td>\n<td style=\"text-align:left\"><strong>&quot;暴露&quot; 和 &quot;采集&quot; 是两件事</strong></td>\n<td style=\"text-align:left\">Node Exporter 有了还得加 job</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">5</td>\n<td style=\"text-align:left\"><strong>抓不到数据先看 Targets，它会告诉你具体 URL 和错误</strong></td>\n<td style=\"text-align:left\">端口写成 9010 的教训</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">6</td>\n<td style=\"text-align:left\"><strong>容器化 Node Exporter 必须 host 网络 + host PID + 挂载 /</strong></td>\n<td style=\"text-align:left\">否则采的是容器自己</td>\n</tr>\n</tbody>\n</table>\n<hr />\n<h2 id=\"215-面试高频问答\"><a class=\"anchor\" href=\"#215-面试高频问答\">#</a> 2.15　面试高频问答</h2>\n<p><strong>Q1：Prometheus 有几种安装方式？生产推荐哪种，为什么？</strong></p>\n<blockquote>\n<p>包安装、二进制、Ansible、Docker、Docker Compose、K8s 六种。<br />\n生产推荐<strong>二进制 + systemd</strong>：版本可控（不被发行版仓库锁死）、零依赖（Go 静态编译）、目录布局自由（配置 / 数据可分离、数据目录可独立分区）、排障直观（日志、进程、路径都在明处）。大规模机器建议 <strong>Ansible</strong>，云原生环境用 <strong>Operator / Helm</strong>。</p>\n</blockquote>\n<p><strong>Q2： <code>--web.enable-lifecycle</code>  是干什么的？为什么不建议开？</strong></p>\n<blockquote>\n<p>它允许通过 HTTP API 触发  <code>/-/reload</code>  和  <code>/-/quit</code> 。风险在于<strong>无任何认证</strong>：任何能访问 9090 的人都能  <code>POST /-/quit</code>  直接把监控服务关掉。而 reload 这件事用  <code>systemctl reload</code> （配合  <code>ExecReload=/bin/kill -HUP</code> ）完全能实现。所以<strong>生产保持默认 false</strong>。</p>\n</blockquote>\n<p><strong>Q3：改了配置文件怎么让它生效？</strong></p>\n<blockquote>\n<p>三步： <code>promtool check config</code>  校验语法 →  <code>systemctl reload prometheus</code> （SIGHUP 热加载）→ 在 Status → Configuration 确认生效、Status → Targets 确认目标 UP。<br />\n注意：<strong>改启动参数（如  <code>--storage.tsdb.path</code> ）必须 restart</strong>，热加载不了。</p>\n</blockquote>\n<p><strong>Q4：为什么 Node Exporter 装在容器里要  <code>--net=host --pid=host -v /:/host</code> ？</strong></p>\n<blockquote>\n<p>因为它的职责是采集<strong>宿主机</strong>的指标，而不是容器自己的。共享网络命名空间才能看到真实网卡；共享 PID 命名空间才能看到宿主机全部进程；挂载宿主机根目录并指定  <code>--path.rootfs=/host</code>  才能读到真实的  <code>/proc</code> 、 <code>/sys</code>  和文件系统使用率。否则采到的全是容器 overlay 里的数据。</p>\n</blockquote>\n<p><strong>Q5：Pushgateway 有什么缺点？</strong></p>\n<blockquote>\n<p>四个：① 单点故障；② <strong> <code>up</code>  指标失效</strong>（看不到真实目标存活，服务挂了旧数据还在，造成 &quot;假存活&quot;）；③ 数据永不自动清理，必须手动 DELETE；④ 不做数据校验，脏数据照单全收。<br />\n因此它只适合<strong>短周期 / 一次性任务的指标</strong>，长期运行的服务应该用 Exporter。</p>\n</blockquote>\n<p><strong>Q6：如何监控 Grafana 自身？</strong></p>\n<blockquote>\n<p>Grafana 自带  <code>/metrics</code>  端点（:3000），在  <code>prometheus.yml</code>  里加一个 job 采集它，然后在 Grafana 里用 Prometheus 数据源查询展示。<strong>注意它不能自己展示自己 ——Grafana 是展示层不是数据源，必须经 Prometheus 中转。</strong></p>\n</blockquote>\n<p><strong>Q7： <code>honor_labels: true</code>  有什么作用？</strong></p>\n<blockquote>\n<p>采集 Pushgateway 时必须加。否则 Prometheus 会用自己配置的  <code>job</code> / <code>instance</code>  覆盖掉推送方设置的标签，导致所有应用的数据都像是同一个来源。加上之后保留 Pushgateway 上的标签，Prometheus 自己的标签改名为  <code>exported_job</code> / <code>exported_instance</code> 。</p>\n</blockquote>\n<hr />\n<h2 id=\"216-动手实验\"><a class=\"anchor\" href=\"#216-动手实验\">#</a> 2.16　动手实验</h2>\n<h3 id=\"实验一必做-二进制装全套-采集四台主机\"><a class=\"anchor\" href=\"#实验一必做-二进制装全套-采集四台主机\">#</a> 实验一（必做）　二进制装全套 + 采集四台主机</h3>\n<p><strong>目标</strong>： <code>up&#123;job=&quot;node_exporter&quot;&#125;</code>  返回 4 条，值全为 1。</p>\n<pre><code>步骤清单（打勾）\n□ 1. 三台机器规划：100=监控服务器，101/102/103=被监控节点\n□ 2. 100 上二进制安装 Prometheus（2.53.x 或 3.x LTS）\n□ 3. 目录规划 bin/conf/data + 建 prometheus 服务账号 + chown\n□ 4. 先手动启动一次验证（注意：用 prometheus 身份，别用 root！）\n□ 5. 写 systemd 单元（含 LimitNOFILE、ExecReload），enable --now\n□ 6. 访问 9090，看 Status → Runtime 确认版本与启动时间\n□ 7. 四台机器全装 node_exporter，加 service，9100 监听\n□ 8. curl 各自 9100/metrics 确认暴露正常\n□ 9. prometheus.yml 新增 node_exporter job，4 个 target\n□ 10. promtool check config → systemctl reload\n□ 11. Status → Targets 确认 4 个全 UP\n□ 12. Graph 里查 node_memory_MemAvailable_bytes，应有 4 条序列\n</code></pre>\n<p><strong>思考题</strong>（做完实验再回答）：</p>\n<ol>\n<li>为什么  <code>data/</code>  目录第一次启动是空的，第二次启动就有内容了？</li>\n<li><code>process_max_fds</code>  这个指标的值，是从哪里来的？（提示：service 文件）</li>\n<li>如果把  <code>scrape_interval</code>  改成  <code>1s</code> ， <code>up</code>  的变化会更快，但会带来什么代价？</li>\n</ol>\n<h3 id=\"实验二-容器化对照实验\"><a class=\"anchor\" href=\"#实验二-容器化对照实验\">#</a> 实验二　容器化对照实验</h3>\n<p>用 Docker 起 Prometheus 和 Node Exporter，<strong>故意不加  <code>--net=host</code> </strong>，然后：</p>\n<ol>\n<li>在容器里执行  <code>curl localhost:9100/metrics | grep node_network</code>  —— 看有几块网卡？</li>\n<li>加上  <code>--net=host</code>  再执行一次 —— 有几块？</li>\n<li><strong>用两行命令理解 &quot;网络命名空间隔离&quot; 这句话是什么意思。</strong></li>\n</ol>\n<h3 id=\"实验三-grafana-全链路\"><a class=\"anchor\" href=\"#实验三-grafana-全链路\">#</a> 实验三　Grafana 全链路</h3>\n<pre><code>□ 1. 安装 Grafana（apt install ./xxx.deb）\n□ 2. 登 3000，admin/admin，改密码\n□ 3. 加 Prometheus 数据源，Save &amp; Test 成功\n□ 4. 导入内置 Prometheus Stats → 看数据\n□ 5. 导入内置 Grafana metrics → 看到 No data，解释原因\n□ 6. 在 prometheus.yml 加 grafana job，reload\n□ 7. 回 Grafana 刷新 → Grafana metrics 有数据了\n□ 8. 导入 Dashboard 1860 / 8919 → 看到四台主机 CPU 曲线\n</code></pre>\n<p><strong>关键问答</strong>：第 5 步为什么没数据？第 7 步为什么就有了？<strong>用一句话讲清这条链路。</strong></p>\n<h3 id=\"实验四-pushgateway-推一个自定义指标\"><a class=\"anchor\" href=\"#实验四-pushgateway-推一个自定义指标\">#</a> 实验四　Pushgateway 推一个自定义指标</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 装 Pushgateway，9091 监听</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># 2. prometheus.yml 加 job（务必 honor_labels: true），reload</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 3. 推一个登录数</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"login_number <span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">who</span> <span class=\"token operator\">|</span> <span class=\"token function\">wc</span> <span class=\"token parameter variable\">-l</span><span class=\"token variable\">)</span></span>\"</span> <span class=\"token operator\">|</span> <span class=\"token function\">curl</span> --data-binary @- <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  http://<span class=\"token operator\">&lt;</span>pg-ip<span class=\"token operator\">></span>:9091/metrics/job/custom_metrics/instance/<span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">hostname</span> <span class=\"token parameter variable\">-I</span> <span class=\"token operator\">|</span> <span class=\"token function\">awk</span> <span class=\"token string\">'&#123;print $1&#125;'</span><span class=\"token variable\">)</span></span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 4. Pushgateway 页面看到指标组</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># 5. Prometheus 里查 login_number</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\"># 6. 故意停掉脚本，等 5 分钟，再查 login_number —— 数据还在吗？为什么？</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 7. 用 DELETE 清掉，再查 —— 没了吧</span></pre></td></tr></table></figure><p><strong>第 6 步的答案，就是 Pushgateway 最大的坑。</strong> 请务必亲手做一次。</p>\n<hr />\n<h2 id=\"217-下章预告\"><a class=\"anchor\" href=\"#217-下章预告\">#</a> 2.17　下章预告</h2>\n<p>本章我们把 &quot;能跑起来&quot; 这件事做到了：四个端口全亮，四台主机的 CPU 曲线出现在 Grafana 上。</p>\n<p>但你会发现一个尴尬的事实：<strong>图虽然有了，可我看不懂那些指标名，也不知道该怎么算。</strong></p>\n<p><code>node_cpu_seconds_total</code>  为什么是一个<strong>只增不减</strong>的巨大数字？为什么不能直接画它就要先做  <code>rate()</code> ？</p>\n<p>下一章专门解决这个问题：</p>\n<ul>\n<li><strong>四种指标类型的本质区别</strong>：Counter / Gauge / Histogram / Summary</li>\n<li>为什么  <code>node_cpu_seconds_total</code>  必须配  <code>rate()</code> ，而  <code>node_memory_MemAvailable_bytes</code>  可以直接画</li>\n<li><strong>标签基数（cardinality）</strong> 为什么会让 Prometheus 内存爆掉</li>\n<li><code>node_exporter</code>  的常用指标该怎么读</li>\n</ul>\n<p><strong>本章作业</strong>：把 &quot;抓不到数据五步排查法&quot; 抄在笔记本第一页。后面所有实验，你都会用到它。</p>\n",
            "tags": [
                "Prometheus"
            ]
        },
        {
            "id": "http://blog.jaxxwang.cn/posts/3825997150.html",
            "url": "http://blog.jaxxwang.cn/posts/3825997150.html",
            "title": "01 ELK 日志收集系统概述",
            "date_published": "2025-12-09T16:00:00.000Z",
            "content_html": "<h1 id=\"elk-相关技术介绍\"><a class=\"anchor\" href=\"#elk-相关技术介绍\">#</a> ELK 相关技术介绍</h1>\n<h2 id=\"1-elk-诞生的背景\"><a class=\"anchor\" href=\"#1-elk-诞生的背景\">#</a> 1. ELK 诞生的背景</h2>\n<h3 id=\"11-没有-elk-分析日志前\"><a class=\"anchor\" href=\"#11-没有-elk-分析日志前\">#</a> 1.1 没有 ELK 分析日志前</h3>\n<p>没有日志分析工具之前，运维工作存在哪些痛点？</p>\n<ul>\n<li>痛点 1：生产出现故障后，运维需要不停的查看各种不同的日志进行分析？是不是毫无头绪？</li>\n<li>痛点 2：项目上线出现错误，如何快速定位问题？如果后端节点过多、日志分散怎么办？</li>\n<li>痛点 3：开发人员需要实时查看日志但又不想给服务器的登陆权限，怎么办？难道每天帮开发取日志？</li>\n<li>痛点 4：如何在海量的日志中快速的提取我们想要的数据？比如：PV、UV、TOP10 的 URL？如果分析的日志数据量大，那么势必会导致查询速度慢、难度增大，最终则会导致我们无法快速的获取到想要的指标。</li>\n<li>痛点 5：CDN 公司需要不停的分析日志，那分析什么？主要分析命中率，为什么？因为我们给用户承诺的命中率是 90% 以上。如果没有达到 90%，我们就要去分析数据为什么没有被命中、为什么没有被缓存下来。</li>\n</ul>\n<h3 id=\"12-使用-elk-分析日志后\"><a class=\"anchor\" href=\"#12-使用-elk-分析日志后\">#</a> 1.2 使用 ELK 分析日志后</h3>\n<p>如上所有的痛点都可以使用日志分析系统 ELK 解决，通过 ELK，将运维所有的服务器日志，业务系统日志都收集到一个平台下，然后提取想要的内容，比如错误信息，警告信息等，当过滤到这种信息，就马上告警，告警后，运维人员就能马上定位是哪台机器、哪个业务系统出现了问题，出现了什么问题。</p>\n<h2 id=\"2-elk-技术栈是什么\"><a class=\"anchor\" href=\"#2-elk-技术栈是什么\">#</a> 2. ELK 技术栈是什么</h2>\n<h3 id=\"21-什么是-elk\"><a class=\"anchor\" href=\"#21-什么是-elk\">#</a> 2.1 什么是 ELK</h3>\n<p>其实 ELK 不是一个单独的技术，而是一套技术的组合，是由 Elasticsearch、Logstash、Kibana 组合而成的。<br />\nELK 是一套开源免费、功能强大的日志分析管理系统。ELK 可以将我们的系统日志、网站日志、应用系统日志等各种日志进行收集、过滤、清洗，然后进行集中存放并可用于实时检索、分析。</p>\n<ul>\n<li>E：Elasticsearch 数据存储；</li>\n<li>L：Logstash 数据采集、数据清洗、数据过滤；</li>\n<li>K：Kibana 数据分析、数据展示；</li>\n</ul>\n<p><strong>缺点</strong>：</p>\n<ul>\n<li>1、Logstash 基于 Java 开发，内存消耗极高</li>\n<li>2、Logstash 与 ElasticSerach 耦合度过紧，容易打爆 ES，造成数据丢失</li>\n</ul>\n<h3 id=\"22-什么是-efk\"><a class=\"anchor\" href=\"#22-什么是-efk\">#</a> 2.2 什么是 EFK</h3>\n<p>简单来说就是将 Logstash 替换成了 Filebeat，那为什么要进行替换？<br />\n因为 Logstash 是基于 JAVA 开发的，在收集日志时会大量的占用业务系统资源，从而影响正常线上业务。而替换成 filebeat 这种较为轻量的日志收集组件，会让业务系统的运行更加的稳定。</p>\n<p><strong>缺点</strong>：</p>\n<ul>\n<li>1、Filebeat 与 ElasticSearch 耦合度过紧，容易打爆 ES，造成数据丢失；</li>\n<li>2、Filebeat 对日志格式的处理与转换，比较的弱；</li>\n</ul>\n<h3 id=\"23-什么是-elfk\"><a class=\"anchor\" href=\"#23-什么是-elfk\">#</a> 2.3 什么是 ELFK</h3>\n<h3 id=\"24-elk-kafka\"><a class=\"anchor\" href=\"#24-elk-kafka\">#</a> 2.4 ELK + Kafka</h3>\n<p>该解决方案可支持每日 1TB 级别的业务日志处理。若贵公司业务日志量达到每日 10 TB，建议根据业务系统进行横向拆分，部署多套独立 ELK 集群。</p>\n<p>Kafka 消息队列 可以将 Filebeat 与 ElasticSearch 进行解耦，从而可以避免 ES 被打爆的现象；</p>\n<p>Logstash</p>\n<ul>\n<li>1、可以从 Kafka 中获取数据，然后匀速写入 ElasticSearch 中：</li>\n<li>2、能针对那些非结构化的数据，将其转为结构化数据，并可以对无用字段进行清洗；</li>\n</ul>\n<h3 id=\"24-efk-收集哪些日志\"><a class=\"anchor\" href=\"#24-efk-收集哪些日志\">#</a> 2.4 EFK 收集哪些日志</h3>\n<ul>\n<li>代理：Haproxy、Nginx</li>\n<li>Web：Nginx、Tomcat、Httpd、PHP</li>\n<li>DB：mysql、redis、mongo、elasticsearch</li>\n<li>存储：nfs、glusterfs、fastdfs</li>\n<li>系统：message、security</li>\n<li>业务：app</li>\n</ul>\n<h3 id=\"25-elk-软件下载地址\"><a class=\"anchor\" href=\"#25-elk-软件下载地址\">#</a> 2.5 ELK 软件下载地址</h3>\n<h4 id=\"251-redhat-系列\"><a class=\"anchor\" href=\"#251-redhat-系列\">#</a> 2.5.1 RedHat 系列</h4>\n<table>\n<thead>\n<tr>\n<th>软件名称</th>\n<th>版本</th>\n<th>下载地址</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>ElasticSearch</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.18.2-x86_64.rpm\">https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.18.2-x86_64.rpm</a></td>\n</tr>\n<tr>\n<td>Logstash</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/logstash/logstash-8.18.2-x86_64.rpm\">https://artifacts.elastic.co/downloads/logstash/logstash-8.18.2-x86_64.rpm</a></td>\n</tr>\n<tr>\n<td>Kibana</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/kibana/kibana-8.18.2-x86_64.rpm\">https://artifacts.elastic.co/downloads/kibana/kibana-8.18.2-x86_64.rpm</a></td>\n</tr>\n<tr>\n<td>Filebeat</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.18.2-x86_64.rpm\">https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.18.2-x86_64.rpm</a></td>\n</tr>\n</tbody>\n</table>\n<h4 id=\"252-debian-系统\"><a class=\"anchor\" href=\"#252-debian-系统\">#</a> 2.5.2 Debian 系统</h4>\n<table>\n<thead>\n<tr>\n<th>软件名称</th>\n<th>版本</th>\n<th>下载地址</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>ElasticSearch</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.18.2-amd64.deb\">https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.18.2-amd64.deb</a></td>\n</tr>\n<tr>\n<td>Logstash</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/logstash/logstash-8.18.2-amd64.deb\">https://artifacts.elastic.co/downloads/logstash/logstash-8.18.2-amd64.deb</a></td>\n</tr>\n<tr>\n<td>Kibana</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/kibana/kibana-8.18.2-amd64.deb\">https://artifacts.elastic.co/downloads/kibana/kibana-8.18.2-amd64.deb</a></td>\n</tr>\n<tr>\n<td>Filebeat</td>\n<td>8.18.2</td>\n<td><a href=\"https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.18.2-amd64.deb\">https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.18.2-amd64.deb</a></td>\n</tr>\n</tbody>\n</table>\n",
            "tags": [
                "ELK"
            ]
        },
        {
            "id": "http://blog.jaxxwang.cn/posts/4103087246.html",
            "url": "http://blog.jaxxwang.cn/posts/4103087246.html",
            "title": "02 Elasticsearch 入门",
            "date_published": "2025-12-09T16:00:00.000Z",
            "content_html": "<h2 id=\"1-es-基本概念介绍\"><a class=\"anchor\" href=\"#1-es-基本概念介绍\">#</a> 1、ES 基本概念介绍</h2>\n<h3 id=\"11-es-是什么\"><a class=\"anchor\" href=\"#11-es-是什么\">#</a> 1.1 ES 是什么</h3>\n<p>Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎。</p>\n<h3 id=\"12-es-主要功能\"><a class=\"anchor\" href=\"#12-es-主要功能\">#</a> 1.2 ES 主要功能</h3>\n<p>数据存储、数据搜索、数据分析。</p>\n<h2 id=\"2-es-相关术语\"><a class=\"anchor\" href=\"#2-es-相关术语\">#</a> 2、ES 相关术语</h2>\n<h3 id=\"21-文档-document\"><a class=\"anchor\" href=\"#21-文档-document\">#</a> 2.1 文档 Document</h3>\n<p>Document 文档就是用户存在 es 中的数据，它是 es 中存储的最小单元。（类似于表中的一行数据）<br />\n<strong>注意</strong>：每个文档都有一个唯一的 ID 表示，可以自行指定，如果不指定 es 会自动生成。</p>\n<h3 id=\"22-索引-index\"><a class=\"anchor\" href=\"#22-索引-index\">#</a> 2.2 索引 Index</h3>\n<p>索引其实是一堆文档 Document 的集合。（它类似数据库的中的一个表）<br />\n在一个索引中，会有多个文档，而每个文档是由多个不同类型的字段拼接在一起的。</p>\n<h3 id=\"23-字段-filed\"><a class=\"anchor\" href=\"#23-字段-filed\">#</a> 2.3 字段 Filed</h3>\n<p>在 ES 中，Document 就是一个 Json Object，一个 Json Object 其实是由多个字段组成的，每个字段它有不同的数据类型。</p>\n<ul>\n<li>字符串：text、keyword。</li>\n<li>数值型：long，integer，short，byte，double，float</li>\n<li>布尔：boolean</li>\n<li>二进制：binary</li>\n<li>范围类型：integer_range，float_range，long_range，double_range，date_range</li>\n</ul>\n<h3 id=\"24-es-术语总结\"><a class=\"anchor\" href=\"#24-es-术语总结\">#</a> 2.4 ES 术语总结</h3>\n<p>ES 索引、文档、字段关系小结：<br />\n一个索引里面存储了很多的 Document 文档，一个文档就是一个 Json Object，一个 Json Object 是由多个不同或相同的 filed 字段组成。</p>\n<h2 id=\"3-es-操作方式\"><a class=\"anchor\" href=\"#3-es-操作方式\">#</a> 3、ES 操作方式</h2>\n<p>ES 的操作和我们传统的数据库操作不太一样，它是通过 Restful API 方式进行操作的，其实本质上就是通过 HTTP 的方式去变更我们的资源状态：</p>\n<ul>\n<li>通过 URI 指定要操作的资源，比如 Index、Document；</li>\n<li>通过 Http Method 指定要操作的方法，如 GET、POST、PUT、DELETE；</li>\n</ul>\n<p>常见操作 ES 的两种方式：Curl、Kibana DevTools</p>\n<h3 id=\"31-es-单节点部署\"><a class=\"anchor\" href=\"#31-es-单节点部署\">#</a> 3.1 ES 单节点部署</h3>\n<h4 id=\"311-centos-系列\"><a class=\"anchor\" href=\"#311-centos-系列\">#</a> 3.1.1 CentOS 系列</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、安装 Java 环境</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># yum install java-17-openjdk java-17-openjdk-devel</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2、安装 ES</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rpm -ivh elasticsearch-8.18.2-x86_64.rpm</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 3、关闭 ES 默认开启的 Security 认证</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/elasticsearch.yml</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\"># Enable security features</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>xpack.security.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>xpack.security.enrollment.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token comment\"># 4、修改 ES 的 JVM 堆内存</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/jvm.options</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token parameter variable\">-Xms1g</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token parameter variable\">-Xmx1g</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre></pre></td></tr><tr><td data-num=\"18\"></td><td><pre><span class=\"token comment\"># 5、启动 ES 单节点</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable --now elasticsearch</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre></pre></td></tr><tr><td data-num=\"21\"></td><td><pre><span class=\"token comment\"># 6. 端口验证</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># netstat -nltp</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre><span class=\"token comment\"># 9200    &lt;= HTTP 通信端口</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token comment\"># 9300    &lt;= 内部集群通信端口</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre></pre></td></tr><tr><td data-num=\"26\"></td><td><pre><span class=\"token comment\"># 7、访问 ES</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># curl localhost:9200</span></pre></td></tr></table></figure><p>访问 ES 正常返回结果：</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"name\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"es-node01.oldwang.net\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"cluster_name\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"elasticsearch\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token property\">\"cluster_uuid\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"HJlIqvnXQx2KfPzttxcA7A\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token property\">\"version\"</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"number\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    <span class=\"token property\">\"build_flavor\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"default\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    <span class=\"token property\">\"build_type\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"rpm\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"build_hash\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"16cc90cd2d08a3147ce02b07e50894bc060a4cbf\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"build_date\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"2099-04-05T14:45:26.420424304Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token property\">\"build_snapshot\"</span> <span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token property\">\"lucene_version\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"9.10.0\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>    <span class=\"token property\">\"minimum_wire_compatibility_version\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"7.17.0\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    <span class=\"token property\">\"minimum_index_compatibility_version\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"7.0.0\"</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>  <span class=\"token property\">\"tagline\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"You Know, for Search\"</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h4 id=\"312-ubuntu-系列\"><a class=\"anchor\" href=\"#312-ubuntu-系列\">#</a> 3.1.2 Ubuntu 系列</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 安装 Java 环境</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> <span class=\"token function\">apt</span> update</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> <span class=\"token function\">apt</span> <span class=\"token function\">install</span> <span class=\"token parameter variable\">-y</span> openjdk-17-jdk</pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 2. 安装 Elasticsearch</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> <span class=\"token function\">wget</span> https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.18.2-amd64.deb</pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> dpkg <span class=\"token parameter variable\">-i</span> elasticsearch-8.18.2-amd64.deb</pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\"># 3. 关闭 ES 默认开启的 Security 认证</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> <span class=\"token function\">vim</span> /etc/elasticsearch/elasticsearch.yml</pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token comment\"># 修改以下内容</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>xpack.security.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>xpack.security.enrollment.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token comment\"># 4. 修改 ES 的 JVM 堆内存</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> <span class=\"token function\">vim</span> /etc/elasticsearch/jvm.options</pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token comment\"># 修改</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre><span class=\"token parameter variable\">-Xms1g</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token parameter variable\">-Xmx1g</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre></pre></td></tr><tr><td data-num=\"21\"></td><td><pre><span class=\"token comment\"># 5. 启动 ES 单节点</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> systemctl <span class=\"token builtin class-name\">enable</span> <span class=\"token parameter variable\">--now</span> elasticsearch</pre></td></tr><tr><td data-num=\"23\"></td><td><pre></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token comment\"># 6. 端口验证</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> ss <span class=\"token parameter variable\">-nltp</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre><span class=\"token comment\"># 9200 &lt;= HTTP 通信端口</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre><span class=\"token comment\"># 9300 &lt;= 内部集群通信端口</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre></pre></td></tr><tr><td data-num=\"29\"></td><td><pre><span class=\"token comment\"># 7. 访问 ES</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span> <span class=\"token function\">curl</span> localhost:9200</pre></td></tr></table></figure><p>访问 ES 正常返回结果：</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"name\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"es-node1.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"cluster_name\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"elasticsearch\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token property\">\"cluster_uuid\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"xQUmZCMTQ7Ohi3TB25H0Yw\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token property\">\"version\"</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"number\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    <span class=\"token property\">\"build_flavor\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"default\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    <span class=\"token property\">\"build_type\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"deb\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"build_hash\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"c6b8d8d951c631db715485edc1a74190cdce4189\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"build_date\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"2025-05-23T10:07:06.210694702Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token property\">\"build_snapshot\"</span> <span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token property\">\"lucene_version\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"9.12.1\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>    <span class=\"token property\">\"minimum_wire_compatibility_version\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"7.17.0\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    <span class=\"token property\">\"minimum_index_compatibility_version\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"7.0.0\"</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>  <span class=\"token property\">\"tagline\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"You Know, for Search\"</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"32-curl-命令操作-es\"><a class=\"anchor\" href=\"#32-curl-命令操作-es\">#</a> 3.2 Curl 命令操作 ES</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、使用 Curl 命令来创建索引，录入一份文档</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># curl -XPUT 'http://localhost:9200/oldwang_index/_doc/1' \\</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token parameter variable\">-H</span> <span class=\"token string\">\"Content-Type: application/json\"</span> <span class=\"token punctuation\">\\</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token parameter variable\">-d</span> <span class=\"token string\">'&#123;</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>\"name\":\"oldwang\",</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>\"age\":18,</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>\"salary\": 1000000</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>&#125;'</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 2、使用 Curl 命令来查看录入的数据</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># curl -XGET 'http://localhost:9200/oldwang_index/_doc/1'</span></pre></td></tr></table></figure><p>查看数据返回结果：</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token property\">\"_index\"</span><span class=\"token operator\">:</span><span class=\"token string\">\"oldwang_index\"</span><span class=\"token punctuation\">,</span><span class=\"token property\">\"_id\"</span><span class=\"token operator\">:</span><span class=\"token string\">\"1\"</span><span class=\"token punctuation\">,</span><span class=\"token property\">\"_version\"</span><span class=\"token operator\">:</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span><span class=\"token property\">\"_seq_no\"</span><span class=\"token operator\">:</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token property\">\"_primary_term\"</span><span class=\"token operator\">:</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span><span class=\"token property\">\"found\"</span><span class=\"token operator\">:</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span><span class=\"token property\">\"_source\"</span><span class=\"token operator\">:</span><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"username\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"oldwang\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"age\"</span><span class=\"token operator\">:</span> <span class=\"token number\">18</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token property\">\"salary\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1000000</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"33-安装-kibana-操作-es\"><a class=\"anchor\" href=\"#33-安装-kibana-操作-es\">#</a> 3.3 安装 Kibana 操作 ES</h3>\n<h4 id=\"331-centos-系列\"><a class=\"anchor\" href=\"#331-centos-系列\">#</a> 3.3.1 CentOS 系列</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、安装 kibana</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rpm -ivh kibana-8.18.2-x86_64.rpm</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2、配置 Kibana</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/kibana/kibana.yml</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 配置内容：</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>server.port: <span class=\"token number\">5601</span>                                  <span class=\"token comment\"># kibana 默认监听端口</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>server.host: <span class=\"token string\">\"0.0.0.0\"</span>                             <span class=\"token comment\"># kibana 监听地址段</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>server.name: <span class=\"token string\">\"kibana-node\"</span>                         <span class=\"token comment\"># kibana 实例名称</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>server.publicBaseUrl: <span class=\"token string\">\"http://kibana.oldwang.net\"</span>    <span class=\"token comment\"># Kibana 的公共 URL, 例如分享链接、API 调用等都会使用该地址</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>elasticsearch.hosts: <span class=\"token punctuation\">[</span><span class=\"token string\">\"http://localhost:9200\"</span><span class=\"token punctuation\">]</span>     <span class=\"token comment\"># kibana 从 coordinating 节点获取数据 (此处 ES. Kibana 属同节点，因此填写 localhost; 正常应该填写 ES 服务器地址)</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>i18n.locale: <span class=\"token string\">\"zh-CN\"</span>                               <span class=\"token comment\"># kibana 汉化</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token comment\"># 3、启动 kibana</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable kibana --now</span></pre></td></tr></table></figure><h4 id=\"332-ubuntu-系列\"><a class=\"anchor\" href=\"#332-ubuntu-系列\">#</a> 3.3.2 Ubuntu 系列</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、安装 kibana</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># dpkg -i kibana-8.18.2-amd64.deb</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 2、配置 Kibana</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/kibana/kibana.yml</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 配置内容：</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>server.port: <span class=\"token number\">5601</span>                                  <span class=\"token comment\"># kibana 默认监听端口</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>server.host: <span class=\"token string\">\"0.0.0.0\"</span>                             <span class=\"token comment\"># kibana 监听地址段</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>server.name: <span class=\"token string\">\"kibana-node\"</span>                         <span class=\"token comment\"># kibana 实例名称</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>server.publicBaseUrl: <span class=\"token string\">\"http://192.168.80.150\"</span>      <span class=\"token comment\"># Kibana 的公共 URL, 例如分享链接、API 调用等都会使用该地址 (推荐使用域名地址)</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>elasticsearch.hosts: <span class=\"token punctuation\">[</span><span class=\"token string\">\"http://192.168.80.151:9200\"</span><span class=\"token punctuation\">]</span> <span class=\"token comment\"># 此处填写 ES 服务器地址，kibana 从 coordinating 节点获取数据</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>i18n.locale: <span class=\"token string\">\"zh-CN\"</span>                               <span class=\"token comment\"># kibana 汉化</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token comment\"># 3、启动 kibana</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable kibana --now</span></pre></td></tr></table></figure><h3 id=\"34-访问-kibana\"><a class=\"anchor\" href=\"#34-访问-kibana\">#</a> 3.4 访问 Kibana</h3>\n<p>访问地址： <code>http://192.168.80.150:5601</code></p>\n<h3 id=\"35-启用堆栈监测或-安装-metricbeat-实现\"><a class=\"anchor\" href=\"#35-启用堆栈监测或-安装-metricbeat-实现\">#</a> 3.5 启用堆栈监测（或 安装 Metricbeat 实现）</h3>\n<p>操作路径： <code>Management &gt; 堆栈监测 &gt; 使用内部收集设置 &gt; 打开 Monitoring</code></p>\n<h2 id=\"4-索引-api\"><a class=\"anchor\" href=\"#4-索引-api\">#</a> 4、索引 API</h2>\n<p>ES 有专门的 Index API，用于创建、更新、删除索引配置等。<br />\n操作入口： <code>Management &gt; 开发工具</code></p>\n<h3 id=\"41-创建索引\"><a class=\"anchor\" href=\"#41-创建索引\">#</a> 4.1 创建索引</h3>\n<p>创建索引相关 API：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 创建索引</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>PUT /oldwang_index</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 查看所有已存在的索引</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>GET _cat/indices</pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token comment\"># 查看健康状态</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>GET _cat/health</pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\"># 查看节点主机</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>GET _cat/nodes</pre></td></tr></table></figure><p>使用方式：在 Kibana 开发工具中输入需要运行的命令，单击运行发送请求。</p>\n<h3 id=\"42-删除索引\"><a class=\"anchor\" href=\"#42-删除索引\">#</a> 4.2 删除索引</h3>\n<p>删除索引 API：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 删除索引</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>DELETE /oldwang_index</pre></td></tr></table></figure><h3 id=\"43-查看索引\"><a class=\"anchor\" href=\"#43-查看索引\">#</a> 4.3 查看索引</h3>\n<p>使用 Kibana 查看索引路径： <code>Stack Management &gt; 索引管理 &gt; 索引</code></p>\n<h2 id=\"5-文档-api\"><a class=\"anchor\" href=\"#5-文档-api\">#</a> 5、文档 API</h2>\n<p>ES 为索引添加文档，有专门的 Document API：</p>\n<ul>\n<li>创建文档</li>\n<li>查询文档</li>\n<li>更新文档</li>\n<li>删除文档</li>\n</ul>\n<h3 id=\"51-创建文档\"><a class=\"anchor\" href=\"#51-创建文档\">#</a> 5.1 创建文档</h3>\n<h4 id=\"创建文档指定-id\"><a class=\"anchor\" href=\"#创建文档指定-id\">#</a> 创建文档（指定 ID）</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 创建一个文档 (指定 ID)</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>POST /oldwang_index/_doc/1</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token string\">\"username\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"oldwang\"</span>,</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token string\">\"age\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token number\">18</span>,</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token string\">\"salary\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token number\">1000000</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><p><strong>说明</strong>：创建文档时，如果索引不存在，ES 会自动创建对应的 index 和 type。</p>\n<h4 id=\"创建文档不指定-id\"><a class=\"anchor\" href=\"#创建文档不指定-id\">#</a> 创建文档（不指定 ID）</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 创建文档，不指定 ID（id 会生成随机字符串）</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>POST /oldwang_index/_doc</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token string\">\"username\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"oldwang\"</span>,</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token string\">\"age\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token number\">18</span>,</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token string\">\"salary\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token number\">1000000</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"52-查询文档\"><a class=\"anchor\" href=\"#52-查询文档\">#</a> 5.2 查询文档</h3>\n<h4 id=\"查询指定-id-文档\"><a class=\"anchor\" href=\"#查询指定-id-文档\">#</a> 查询指定 ID 文档</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>GET /oldwang_index/_doc/1</pre></td></tr></table></figure><h4 id=\"查询所有文档\"><a class=\"anchor\" href=\"#查询所有文档\">#</a> 查询所有文档</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>GET /oldwang_index/_search</pre></td></tr></table></figure><h4 id=\"查询指定内容\"><a class=\"anchor\" href=\"#查询指定内容\">#</a> 查询指定内容</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>GET /oldwang_index/_search</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token string\">\"query\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token string\">\"match\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>      <span class=\"token string\">\"username\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"oldwang\"</span>    </pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"53-批量创建文档\"><a class=\"anchor\" href=\"#53-批量创建文档\">#</a> 5.3 批量创建文档</h3>\n<p>ES 允许通过  <code>_bulk</code>  一次创建多个文档，从而减少网络传输开销，提升写入速率。</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 批量创建 Document</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>POST _bulk</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"index\"</span>:<span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"_index\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"tt\"</span>,<span class=\"token string\">\"_id\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"1\"</span><span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"name\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"oldwang\"</span>,<span class=\"token string\">\"age\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"18\"</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"create\"</span>:<span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"_index\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"tt\"</span>,<span class=\"token string\">\"_id\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"2\"</span><span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"name\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"oldqiang\"</span>,<span class=\"token string\">\"age\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"30\"</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"delete\"</span>:<span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"_index\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"tt\"</span>,<span class=\"token string\">\"_id\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"2\"</span><span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"update\"</span>:<span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"_id\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"1\"</span>,<span class=\"token string\">\"_index\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"tt\"</span><span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"doc\"</span>:<span class=\"token punctuation\">&#123;</span><span class=\"token string\">\"age\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"20\"</span><span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"54-批量查询文档\"><a class=\"anchor\" href=\"#54-批量查询文档\">#</a> 5.4 批量查询文档</h3>\n<p>ES 允许通过  <code>_mget</code>  一次查询多个文档。</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 批量查询 Document</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>GET _mget</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token string\">\"docs\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token punctuation\">[</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      <span class=\"token string\">\"_index\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"tt\"</span>,</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>      <span class=\"token string\">\"_id\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"1\"</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span>,</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>      <span class=\"token string\">\"_index\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"tt\"</span>,</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      <span class=\"token string\">\"_id\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"2\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"总结\"><a class=\"anchor\" href=\"#总结\">#</a> 总结</h3>\n<ol>\n<li>ES 核心概念：文档是最小存储单元（对应数据库行）、索引是文档集合（对应数据库表）、字段是文档的属性且有多种数据类型。</li>\n<li>ES 操作核心：基于 RESTful API，可通过 Curl 命令行或 Kibana 可视化工具操作，核心 HTTP 方法包括 PUT/GET/POST/DELETE。</li>\n<li>部署与使用：CentOS/Ubuntu 系统均支持 ES 和 Kibana 部署，Kibana 可汉化且提供友好的可视化操作界面，支持索引和文档的增删改查及批量操作。</li>\n</ol>\n",
            "tags": [
                "ELK"
            ]
        },
        {
            "id": "http://blog.jaxxwang.cn/posts/2265425726.html",
            "url": "http://blog.jaxxwang.cn/posts/2265425726.html",
            "title": "04 Filebeat 日志收集入门",
            "date_published": "2025-12-09T16:00:00.000Z",
            "content_html": "<h2 id=\"1-filebeat-基本介绍\"><a class=\"anchor\" href=\"#1-filebeat-基本介绍\">#</a> 1、Filebeat 基本介绍</h2>\n<h3 id=\"11-filebeat-是什么\"><a class=\"anchor\" href=\"#11-filebeat-是什么\">#</a> 1.1 Filebeat 是什么</h3>\n<p>Filebeat 是用于 <strong>&quot;转发&quot;</strong> 和 <strong>&quot;集中日志数据&quot;</strong> 的 <strong>&quot;轻量型数据采集器&quot;</strong>；<br />\nFilebeat 会监视指定的日志文件路径，收集日志事件并将数据转发到 Elasticsearch、Logstash、Redis、Kafka 存储服务器。</p>\n<h3 id=\"12-filebeat-主要组件\"><a class=\"anchor\" href=\"#12-filebeat-主要组件\">#</a> 1.2 Filebeat 主要组件</h3>\n<p>Filebeat 主要由两个核心组件组成：<strong>Input</strong> 和 <strong>Harvester</strong>。</p>\n<ul>\n<li><strong>Input（输入）</strong>：负责定位和识别需要读取的日志文件。可以使用文件的全路径、也可以是文件名称匹配等。</li>\n<li><strong>Harvester（收割机）</strong>：负责打开 Input 定义的这些文件，然后 <strong>逐行</strong> 读取文件内容。最后将内容发送到指定的输出端。</li>\n</ul>\n<p>这两个组件协同工作，确保将日志文件尾部 <strong>最新的数据</strong> 发送到指定的输出端。</p>\n<p><strong>配置示例</strong>：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>      <span class=\"token punctuation\">-</span> /var/log/oldwang.log      <span class=\"token comment\"># 指定日志路径</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      <span class=\"token punctuation\">-</span> /var/log/<span class=\"token important\">*.log</span>          <span class=\"token comment\"># 指定日志，匹配方式</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>      <span class=\"token comment\"># - /var/log/**/*.log     # 递归目录，完成日志的匹配</span></pre></td></tr></table></figure><h3 id=\"13-filebeat-工作流程\"><a class=\"anchor\" href=\"#13-filebeat-工作流程\">#</a> 1.3 Filebeat 工作流程</h3>\n<p>当 filebeat 启动后，filebeat 通过 Input 读取指定的日志路径，然后为该日志启动一个收割进程 harvester，每一个收割进程读取一个日志文件的新内容，并发送这些新的日志数据到处理程序 spooler，处理程序会集合这些事件，最后 filebeat 会发送集合的数据到你指定的位置。</p>\n<h2 id=\"2-filebeat-安装配置\"><a class=\"anchor\" href=\"#2-filebeat-安装配置\">#</a> 2、Filebeat 安装配置</h2>\n<h3 id=\"21-filebeat-安装\"><a class=\"anchor\" href=\"#21-filebeat-安装\">#</a> 2.1 Filebeat 安装</h3>\n<ol>\n<li>安装 Filebeat</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ dpkg <span class=\"token parameter variable\">-i</span> filebeat-8.18.2-amd64.deb</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rpm -ivh filebeat-8.18.2-x86_64.rpm</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动 Filebeat</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable --now filebeat.service</span></pre></td></tr></table></figure><h3 id=\"22-filebeat-配置说明\"><a class=\"anchor\" href=\"#22-filebeat-配置说明\">#</a> 2.2 Filebeat 配置说明</h3>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 定义 Filebeat 输入源</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log                      <span class=\"token comment\"># 输入类型为日志文件</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>                  <span class=\"token comment\"># 启用该输入</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      <span class=\"token punctuation\">-</span> /var/log/nginx/access.log  <span class=\"token comment\"># 指定日志路径</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    <span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"nginx-access\"</span><span class=\"token punctuation\">]</span>         <span class=\"token comment\"># 为该日志添加标签，可用于后续过滤或分析</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  </pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>      <span class=\"token punctuation\">-</span> /var/log/nginx/error.log   <span class=\"token comment\"># 指定日志路径</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>    <span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"nginx-error\"</span><span class=\"token punctuation\">]</span>          <span class=\"token comment\"># 为该日志添加标签</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token comment\"># 定义输出，将日志发送到 Elasticsearch</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token key atrule\">output.elasticsearch</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token key atrule\">hosts</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"elasticsearch:9200\"</span><span class=\"token punctuation\">]</span>     <span class=\"token comment\"># 指定 Elasticsearch 地址</span></pre></td></tr></table></figure><h2 id=\"3-filebeat-常用-input-插件\"><a class=\"anchor\" href=\"#3-filebeat-常用-input-插件\">#</a> 3、Filebeat 常用 Input 插件</h2>\n<h3 id=\"31-filebeat-从终端读取数据\"><a class=\"anchor\" href=\"#31-filebeat-从终端读取数据\">#</a> 3.1 Filebeat 从终端读取数据</h3>\n<ol>\n<li>配置 Filebeat 从终端读取数据，然后从终端输出消息</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># mkdir /etc/filebeat/conf.d</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ <span class=\"token function\">vim</span> /etc/filebeat/conf.d/01-stdin-output-console.yml</pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> stdin</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动 Filebeat，并明确指定配置文件路径，然后输入一条测试内容</li>\n</ol>\n<blockquote>\n<p>注意：基于如下方式启用 filebeat 的同时，需要将 filebeat 服务关闭。否则会报错： <code>Exiting: /var/lib/filebeat/filebeat.lock: data path already locked by another beat. Please make sure that multiple beats are not sharing the same data path (path.data)</code></p>\n</blockquote>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl stop filebeat.service</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ filebeat <span class=\"token parameter variable\">-e</span> <span class=\"token parameter variable\">-c</span> /etc/filebeat/conf.d/01-stdin-output-console.yml</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 输入内容</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>hello,filebeat</pre></td></tr></table></figure><ol start=\"3\">\n<li>结果返回</li>\n</ol>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-26T04:37:46.332Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>                      &lt;== Filebeat 当前从日志文件中读取到的位置</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span>                      &lt;== 日志来源文件路径 (空值<span class=\"token punctuation\">,</span> 因为此日志来自 stdin 输入而非文件)</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"hello,filebeat\"</span><span class=\"token punctuation\">,</span>        &lt;== 核心日志内容</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"stdin\"</span>                   &lt;== 表示输入来源为标准输入</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span>       &lt;== 产生日志的主机名信息</pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"ba6b6172-3cdf-4060-b43f-a018f79e5c42\"</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><blockquote>\n<p>说明： <code>offset: 0</code>  表示 Filebeat 刚开始读取该文件，从第一个字节（起始位置）开始读取。如果  <code>offset: 1500</code> ，表示 Filebeat 已经读取了前 1500 字节，它会从第 1501 字节继续读取。</p>\n</blockquote>\n<h3 id=\"32-filebeat-从网络中读取数据\"><a class=\"anchor\" href=\"#32-filebeat-从网络中读取数据\">#</a> 3.2 Filebeat 从网络中读取数据</h3>\n<p>在分布式系统或多服务架构中，直接从本地系统采集日志有时不太方便。为此，可以将应用程序日志通过 TCP 或 UDP 协议发送到特定网络端口，然后通过 Filebeat 接收此端口的日志数据。</p>\n<h4 id=\"321-监听-tcp-端口并输出到控制台\"><a class=\"anchor\" href=\"#321-监听-tcp-端口并输出到控制台\">#</a> 3.2.1 监听 TCP 端口并输出到控制台</h4>\n<ol>\n<li>编写配置</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ <span class=\"token function\">vim</span> /etc/filebeat/conf.d/02-tcp-output-console.yml</pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> tcp                 <span class=\"token comment\"># 指定类型为 TCP, 也可以是 UDP</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>              <span class=\"token comment\"># 启用该输入配置</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token key atrule\">host</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"0.0.0.0:5656\"</span>      <span class=\"token comment\"># 监听网络地址及端口</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token key atrule\">max_message_size</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"10M\"</span>   <span class=\"token comment\"># 限制单条消息最大为 10M. 默认值为 20MiB.</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>                <span class=\"token comment\"># 以格式化的美观方式输出日志</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动 Filebeat 并应用上述配置</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ filebeat <span class=\"token parameter variable\">-e</span> <span class=\"token parameter variable\">-c</span> /etc/filebeat/conf.d/02-tcp-output-console.yml</pre></td></tr></table></figure><ol start=\"3\">\n<li>验证 Filebeat 是否成功监听了 5656 端口</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ <span class=\"token function\">netstat</span> <span class=\"token parameter variable\">-nltp</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>tcp6       <span class=\"token number\">0</span>      <span class=\"token number\">0</span> :::5656                 :::*                    LISTEN      <span class=\"token number\">64290</span>/filebeat</pre></td></tr></table></figure><h4 id=\"322-监听-udp-端口并输出到控制台\"><a class=\"anchor\" href=\"#322-监听-udp-端口并输出到控制台\">#</a> 3.2.2 监听 UDP 端口并输出到控制台</h4>\n<ol>\n<li>编写配置</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ <span class=\"token function\">vim</span> /etc/filebeat/conf.d/02-udp-output-console.yml</pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> udp                 <span class=\"token comment\"># 指定类型为 UDP</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>              <span class=\"token comment\"># 启用该输入配置</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token key atrule\">host</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"0.0.0.0:5658\"</span>      <span class=\"token comment\"># 监听网络地址及端口</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token key atrule\">max_message_size</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"10M\"</span>   <span class=\"token comment\"># 限制单条消息最大为 10M. 默认值为 20MiB.</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    </pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>                <span class=\"token comment\"># 以格式化的美观方式输出日志</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动 Filebeat 并应用上述配置</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ filebeat <span class=\"token parameter variable\">-e</span> <span class=\"token parameter variable\">-c</span> /etc/filebeat/conf.d/02-udp-output-console.yml</pre></td></tr></table></figure><ol start=\"3\">\n<li>验证 Filebeat 是否成功监听了 5658 端口</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ <span class=\"token function\">netstat</span> <span class=\"token parameter variable\">-nltup</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>udp6       <span class=\"token number\">0</span>      <span class=\"token number\">0</span> :::5658                 :::*                                <span class=\"token number\">86005</span>/filebeat</pre></td></tr></table></figure><h4 id=\"323-模拟发送数据\"><a class=\"anchor\" href=\"#323-模拟发送数据\">#</a> 3.2.3 模拟发送数据</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"hello,tcp\"</span> <span class=\"token operator\">|</span> <span class=\"token function\">nc</span> <span class=\"token number\">192.168</span>.80.154 <span class=\"token number\">5656</span>      <span class=\"token comment\"># TCP 协议方式</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span>$ <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"hello,udp\"</span> <span class=\"token operator\">|</span> <span class=\"token function\">nc</span> <span class=\"token parameter variable\">-u</span> <span class=\"token number\">192.168</span>.80.154 <span class=\"token number\">5658</span>   <span class=\"token comment\"># UDP 协议方式</span></pre></td></tr></table></figure><h4 id=\"324-查看接收数据\"><a class=\"anchor\" href=\"#324-查看接收数据\">#</a> 3.2.4 查看接收数据</h4>\n<ul>\n<li>TCP 输入返回结果</li>\n</ul>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-26T05:00:32.381Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"tcp\"</span>                  &lt;== 当前日志的输入类型为 TCP</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span>    &lt;== 运行 Filebeat 代理的主机名</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"f3cc997d-dfc0-4716-a9ae-c1da98e63532\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"hello,tcp\"</span><span class=\"token punctuation\">,</span>          &lt;== 实际接收到的日志内容<span class=\"token punctuation\">,</span> 即通过 TCP 发送到 <span class=\"token number\">5656</span> 端口的原始数据</pre></td></tr><tr><td data-num=\"25\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    <span class=\"token property\">\"source\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>      <span class=\"token property\">\"address\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"192.168.80.151:44322\"</span>   &lt;== 发送日志的客户端 IP 地址</pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><ul>\n<li>UDP 输入返回结果</li>\n</ul>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-26T05:08:43.767Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    <span class=\"token property\">\"truncated\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"hello,udp\\n\"</span><span class=\"token punctuation\">,</span>    &lt;== 实际接收到的日志内容<span class=\"token punctuation\">,</span> 即通过 UDP 发送到 <span class=\"token number\">5658</span> 端口的原始数据</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token property\">\"source\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>      <span class=\"token property\">\"address\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"192.168.80.151:50754\"</span>    &lt;== 发送日志的客户端 IP 地址</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"udp\"</span>                    &lt;== 当前日志的输入类型为 UDP</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span>      &lt;== 运行 Filebeat 代理的主机名</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"af3b7435-9fc5-4c9b-882a-6a0e34ba1847\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"33-filebeat-从文件中读取数据\"><a class=\"anchor\" href=\"#33-filebeat-从文件中读取数据\">#</a> 3.3 Filebeat 从文件中读取数据</h3>\n<blockquote>\n<p>注意：Filebeat 7.16.0 版本之后 Log 被废弃，官方建议使用 filestream 插件。</p>\n</blockquote>\n<ol>\n<li>配置 Filebeat 从文件中读取数据</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/conf.d/03-file-output-console.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>    <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>      <span class=\"token punctuation\">-</span> /var/log/test.log      <span class=\"token comment\"># 指定需要监控的日志文件</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      <span class=\"token comment\"># - /var/log/*.log       # 监控 /var/log 目录下所有 .log 结尾的文件</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>      <span class=\"token comment\"># - /var/log/**/*.log    # 递归监控 /var/log 及其子目录下所有 .log 结尾的文件</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动 Filebeat</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 启动 Filebeat</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># filebeat -e -c /etc/filebeat/conf.d/03-file-output-console.yml</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># 向 /var/log/test.log 文件追加内容</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span> <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"hello,filebeat01\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span> <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"hello,filebeat02\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr></table></figure><ol start=\"3\">\n<li>查看 Filebeat 接收到的数据</li>\n</ol>\n<ul>\n<li>第一次输入返回结果</li>\n</ul>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-26T16:21:41.320Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>                        &lt;== 起始位置</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/test.log\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"hello,filebeat01\"</span><span class=\"token punctuation\">,</span>        &lt;== 输入内容</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"e793a9b2-afaa-41c5-8075-c1899f770c14\"</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><ul>\n<li>第二次输入返回结果</li>\n</ul>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-26T16:22:56.332Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">17</span><span class=\"token punctuation\">,</span>                    &lt;== 断点续读</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/test.log\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"hello,filebeat02\"</span><span class=\"token punctuation\">,</span>    &lt;== 输入内容</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"e793a9b2-afaa-41c5-8075-c1899f770c14\"</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h2 id=\"4-filebeat-常用-output\"><a class=\"anchor\" href=\"#4-filebeat-常用-output\">#</a> 4、Filebeat 常用 Output</h2>\n<p>Filebeat 常用的 Output 参考地址：<a href=\"https://www.elastic.co/guide/en/beats/filebeat/current/configuring-output.html\">https://www.elastic.co/guide/en/beats/filebeat/current/configuring-output.html</a></p>\n<h3 id=\"41-filebeat-输出至-es-集群\"><a class=\"anchor\" href=\"#41-filebeat-输出至-es-集群\">#</a> 4.1 Filebeat 输出至 ES 集群</h3>\n<ol>\n<li>配置 Filebeat 将日志采集，并输出到 Elasticsearch 集群</li>\n</ol>\n<h4 id=\"411-编写配置文件\"><a class=\"anchor\" href=\"#411-编写配置文件\">#</a> 4.1.1 编写配置文件</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/filebeat.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log                        <span class=\"token comment\"># 输入类型为日志文件</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>                    <span class=\"token comment\"># 启用该输入配置</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span> /var/log/test.log         <span class=\"token comment\"># 监控 /var/log/test.log 文件的日志</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 输出目标为 Elasticsearch 集群</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key atrule\">output.elasticsearch</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">hosts</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.152:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.153:9200\"</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure><h4 id=\"412-重启-filebeat-服务\"><a class=\"anchor\" href=\"#412-重启-filebeat-服务\">#</a> 4.1.2 重启 Filebeat 服务</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart filebeat</span></pre></td></tr></table></figure><h4 id=\"413-向监控的日志文件追加新内容\"><a class=\"anchor\" href=\"#413-向监控的日志文件追加新内容\">#</a> 4.1.3 向监控的日志文件追加新内容</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo \"hello,filebeat03\" >> /var/log/test.log</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>\n<p>通过 Cerebro 观察新写入到 ES 的索引数据</p>\n</li>\n<li>\n<p>索引默认格式说明<br />\n默认没有定义索引名称的情况下，索引默认格式为： <code>.ds-&#123;name&#125;-&#123;version&#125;-&#123;date&#125;-&#123;date&#125;-&#123;counter&#125;</code> <br />\n 例如： <code>.ds-filebeat-8.18.2-2099.05.01-000001</code></p>\n</li>\n</ol>\n<ul>\n<li>name：名称为 filebeat</li>\n<li>version：Filebeat 版本号</li>\n<li>date：索引创建日期，格式为 年。月. 日</li>\n<li>counter：自增的 6 位数计数器</li>\n</ul>\n<h3 id=\"42-filebeat-自定义索引名称\"><a class=\"anchor\" href=\"#42-filebeat-自定义索引名称\">#</a> 4.2 Filebeat 自定义索引名称</h3>\n<p>默认 Filebeat 写入 ES 的索引名称为  <code>.ds-filebeat-*</code> ，如果希望修改索引名称，则通过  <code>index</code>  关键字实现。</p>\n<ol>\n<li>修改 Filebeat 配置文件</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/filebeat.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token punctuation\">-</span> /var/log/test.log</pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key atrule\">output.elasticsearch</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">hosts</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.152:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.153:9200\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token key atrule\">index</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log-%&#123;[agent.version]&#125;-%&#123;+yyyy.MM.dd&#125;\"</span>      <span class=\"token comment\"># 自定义索引名称</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key atrule\">setup.ilm.enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span>                 <span class=\"token comment\"># 索引生命周期 ilm 功能默认开启，开启情况下索引名称只能为 .ds-filebeat-*</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token key atrule\">setup.template.name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log\"</span>          <span class=\"token comment\"># 定义模板名称</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token key atrule\">setup.template.pattern</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log-*\"</span>     <span class=\"token comment\"># 定义模板的 \"匹配索引名称规则\"</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token comment\"># 8.x 必须配置如下内容，否则不会创建索引，而会创建对应的索引数据流</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token key atrule\">setup.template.enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span>            <span class=\"token comment\"># 关掉默认的模板配置</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token key atrule\">setup.template.overwrite</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>           <span class=\"token comment\"># 允许覆盖已存在的同名模板</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>重启 Filebeat 产生新的索引</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl start filebeat</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl status filebeat</span></pre></td></tr></table></figure><ol start=\"3\">\n<li>向监控的日志文件追加新内容</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo \"hello,filebeat04\" >> /var/log/test.log</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo \"hello,filebeat05\" >> /var/log/test.log</span></pre></td></tr></table></figure><ol start=\"4\">\n<li>检查结果</li>\n</ol>\n<ul>\n<li>通过 Cerebro 检查结果</li>\n<li>通过 Kibana 检查结果，索引为  <code>test-log-8.18.2--2025.07.27</code> ，索引模板为  <code>test-log</code></li>\n</ul>\n<h3 id=\"43-filebeat-自定义索引分片\"><a class=\"anchor\" href=\"#43-filebeat-自定义索引分片\">#</a> 4.3 Filebeat 自定义索引分片</h3>\n<p>默认情况下 Filebeat 写入到 ES 的索引分片为 1，如果需要修改分片，可以通过以下两种方式：</p>\n<h4 id=\"方式-1通过-filebeat-配置文件\"><a class=\"anchor\" href=\"#方式-1通过-filebeat-配置文件\">#</a> 方式 1：通过 Filebeat 配置文件</h4>\n<ol>\n<li>修改 filebeat 配置文件</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/filebeat.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token punctuation\">-</span> /var/log/test.log</pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key atrule\">output.elasticsearch</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">hosts</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.152:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.153:9200\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token key atrule\">index</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log-%&#123;[agent.version]&#125;-%&#123;+yyyy.MM.dd&#125;\"</span>      <span class=\"token comment\"># 自定义索引名称</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key atrule\">setup.ilm.enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span>                 <span class=\"token comment\"># 索引生命周期 ilm 功能默认开启，开启情况下索引名称只能为 .ds-filebeat-*</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token key atrule\">setup.template.name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log\"</span>          <span class=\"token comment\"># 定义模板名称</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token key atrule\">setup.template.pattern</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log-*\"</span>     <span class=\"token comment\"># 定义模板的 \"匹配索引名称规则\"</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token comment\"># 8.x 必须配置如下内容，否则不会创建索引，而会创建对应的索引数据流</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token key atrule\">setup.template.enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span>            <span class=\"token comment\"># 关掉默认的模板配置</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token key atrule\">setup.template.overwrite</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>           <span class=\"token comment\"># 允许覆盖已存在的同名模板</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token key atrule\">setup.template.settings</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token key atrule\">index.number_of_shards</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3</span>        <span class=\"token comment\"># 每个索引的主分片数量为 3</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token key atrule\">index.number_of_replicas</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1</span>      <span class=\"token comment\"># 每个主分片的副本分片数量为 1</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>删除索引、删除索引模板，最后重启 filebeat</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>systemctl restart filebeat</pre></td></tr></table></figure><ol start=\"3\">\n<li>产生新的数据及索引</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo \"hello,filebeat04\" >> /var/log/test.log</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo \"hello,filebeat05\" >> /var/log/test.log</span></pre></td></tr></table></figure><ol start=\"4\">\n<li>验证索引状态</li>\n</ol>\n<h4 id=\"方式-2手动创建索引模板\"><a class=\"anchor\" href=\"#方式-2手动创建索引模板\">#</a> 方式 2：手动创建索引模板</h4>\n<ol>\n<li>修改 filebeat 配置文件</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/filebeat.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token punctuation\">-</span> /var/log/test.log</pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token key atrule\">output.elasticsearch</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">hosts</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.152:9200\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"192.168.80.153:9200\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token key atrule\">index</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log-%&#123;[agent.version]&#125;-%&#123;+yyyy.MM.dd&#125;\"</span>      <span class=\"token comment\"># 自定义索引名称</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token key atrule\">setup.ilm.enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span>                 <span class=\"token comment\"># 索引生命周期 ilm 功能默认开启，开启情况下索引名称只能为 .ds-filebeat-*</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token key atrule\">setup.template.name</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log\"</span>          <span class=\"token comment\"># 定义模板名称</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token key atrule\">setup.template.pattern</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test-log-*\"</span>     <span class=\"token comment\"># 定义模板的 \"匹配索引名称规则\"</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token comment\"># 8.x 必须配置如下内容，否则不会创建索引，而会创建对应的索引数据流</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token key atrule\">setup.template.enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span>            <span class=\"token comment\"># 关掉默认的模板配置</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token key atrule\">setup.template.overwrite</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>           <span class=\"token comment\"># 允许覆盖已存在的同名模板</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>手动创建索引的模板，然后设定主分片数据和副本分片数量</li>\n</ol>\n<figure class=\"highlight http\"><figcaption data-lang=\"HTTP\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>PUT /_index_template/test-log         // 索引模板名称</pre></td></tr><tr><td data-num=\"2\"></td><td><pre>&#123;</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  \"index_patterns\": [\"test-log-*\"],   // 模板匹配并关联哪些索引;</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  \"template\": &#123;</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    \"settings\": &#123;</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>      \"index\": &#123;</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>        \"number_of_shards\": 3,</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>        \"number_of_replicas\": 1</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>      &#125;</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    &#125;</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  &#125;</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>&#125;</pre></td></tr></table></figure><ol start=\"3\">\n<li>\n<p>验证索引模板</p>\n</li>\n<li>\n<p>删除此前的索引，然后重启服务，验证索引状态 (三分片，一副本)</p>\n</li>\n</ol>\n<h2 id=\"5-filebeat-字段添加\"><a class=\"anchor\" href=\"#5-filebeat-字段添加\">#</a> 5、Filebeat 字段添加</h2>\n<h3 id=\"51-使用-tags-添加标签\"><a class=\"anchor\" href=\"#51-使用-tags-添加标签\">#</a> 5.1 使用 tags 添加标签</h3>\n<p>在 Filebeat 中，可以使用  <code>tags</code>  配置项为每条数据添加一个标签列表。例如：可以为访问日志添加  <code>access_log</code>  标签，为错误日志添加  <code>error_log</code>  标签。这些标签在后续的日志处理和分析阶段可以用于有效地标识和筛选数据。</p>\n<ol>\n<li>配置文件编写</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/conf.d/04-log-output-console.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span> /var/log/access.log</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"system-access\"</span><span class=\"token punctuation\">]</span>            <span class=\"token comment\"># 为输入日志添加标签</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span> /var/log/error.log</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"system-error\"</span><span class=\"token punctuation\">]</span>             <span class=\"token comment\"># 为输入日志添加标签</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动对应的 filebeat</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># filebeat -e -c /etc/filebeat/conf.d/04-log-output-console.yml</span></pre></td></tr></table></figure><ol start=\"3\">\n<li>追加日志内容</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo test-access >> /var/log/access.log</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo test-error >> /var/log/error.log</span></pre></td></tr></table></figure><ol start=\"4\">\n<li>验证对应的结果</li>\n</ol>\n<ul>\n<li>tags: system-access 结果</li>\n</ul>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-27T07:22:52.136Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/access.log\"</span>  &lt;== 日志路径</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"test-access\"</span><span class=\"token punctuation\">,</span>          &lt;== 日志内容</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"tags\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token string\">\"system-access\"</span>                  &lt;== 日志标签</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span>                    &lt;== 输入类型</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"b5cc1683-2c57-47dc-811d-b1627c94d9ad\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><ul>\n<li>tags: system-error 结果</li>\n</ul>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-27T07:22:52.136Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/error.log\"</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"test-error\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"tags\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token string\">\"system-error\"</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"b5cc1683-2c57-47dc-811d-b1627c94d9ad\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"52-使用-fields-添加字段\"><a class=\"anchor\" href=\"#52-使用-fields-添加字段\">#</a> 5.2 使用 fields 添加字段</h3>\n<p>在 Filebeat 中，可以使用  <code>fields</code>  配置项为每条数据添加自定义字段。</p>\n<ol>\n<li>配置文件编写</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/conf.d/05-log-output-console.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span> /var/log/access.log</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  </pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token key atrule\">fields</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>    <span class=\"token key atrule\">namespace</span><span class=\"token punctuation\">:</span> system<span class=\"token punctuation\">-</span>access       <span class=\"token comment\"># 自定义字段</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token key atrule\">fields_under_root</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>          <span class=\"token comment\"># 若设置为 true 时，则将 fields 添加的自定义字段放在顶级字段中，默认为 false.</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token key atrule\">console</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动对应的 filebeat</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># filebeat -e -c /etc/filebeat/conf.d/05-log-output-console.yml</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># echo test-access >> /var/log/access.log</span></pre></td></tr></table></figure><ol start=\"3\">\n<li>查看 Filebeat 输出的结果</li>\n</ol>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-27T07:45:22.216Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"namespace\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"system-access\"</span><span class=\"token punctuation\">,</span>    &lt;== 自定义字段内容</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"4d716c9b-06eb-4a30-a511-e2d0ddf32f60\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">24</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/access.log\"</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"test-access\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h2 id=\"6-filebeat-处理器\"><a class=\"anchor\" href=\"#6-filebeat-处理器\">#</a> 6、Filebeat 处理器</h2>\n<h3 id=\"61-处理器-processors\"><a class=\"anchor\" href=\"#61-处理器-processors\">#</a> 6.1 处理器 Processors</h3>\n<p>在 Filebeat 中，Processors 用于在数据发送到目标后端之前，可以对源数据执行预处理的组件。这些处理器可以执行各种数据转换任务，如修改、添加或删除字段等。常见的处理器包括：</p>\n<ul>\n<li>add_fields: 向数据中添加新的字段。</li>\n<li>drop_fields: 删除数据中的指定字段。</li>\n<li>rename: 重命名数据中的字段。</li>\n</ul>\n<p>参考文档：<a href=\"https://www.elastic.co/guide/en/beats/filebeat/8.18/filtering-and-enhancing-data.html\">https://www.elastic.co/guide/en/beats/filebeat/8.18/filtering-and-enhancing-data.html</a></p>\n<h3 id=\"62-删除消息中的内容\"><a class=\"anchor\" href=\"#62-删除消息中的内容\">#</a> 6.2 删除消息中的内容</h3>\n<ol>\n<li>配置文件编写（过滤掉 DEBUG 开头的日志）</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/conf.d/06-log-processors-output-console.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span> /var/log/test.log         <span class=\"token comment\"># 目标日志文件路径</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">processors</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">drop_event</span><span class=\"token punctuation\">:</span>                    <span class=\"token comment\"># 丢弃符合条件的日志事件</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>      <span class=\"token key atrule\">when</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>        <span class=\"token key atrule\">regexp</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>          <span class=\"token key atrule\">message</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"^DEBUG\"</span>        <span class=\"token comment\"># 匹配规则: message 字段以 DEBUG 开头</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token key atrule\">console</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><blockquote>\n<p>排除 log.level: info 的日志配置</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">processors</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">drop_event</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>      <span class=\"token key atrule\">when</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>        <span class=\"token key atrule\">equals</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>          <span class=\"token key atrule\">log.level</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"info\"</span></pre></td></tr></table></figure></blockquote>\n<ol start=\"2\">\n<li>启动 filebeat 并写入测试内容</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># filebeat -e -c /etc/filebeat/conf.d/06-log-processors-output-console.yml</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 向 test.log 写入 4 条内容</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"DEBUG: Hello\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"DEBUG: Hello\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"ADEBUG: Hello\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"BDEBUG: Hello\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr></table></figure><ol start=\"3\">\n<li>输出结果<br />\n仅显示 ADEBUG 和 BDEBUG 开头的日志，DEBUG 开头的日志被成功过滤。</li>\n</ol>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-27T13:13:43.324Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">14</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/test.log\"</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"ADEBUG: Hello\"</span><span class=\"token punctuation\">,</span>            &lt;==</pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"6bd21962-ed78-431b-9aac-e866a0643dd4\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre></pre></td></tr><tr><td data-num=\"33\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-27T13:19:38.415Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"36\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"38\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"39\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"40\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"41\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"42\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"43\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"44\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">54</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"45\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"46\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/test.log\"</span></pre></td></tr><tr><td data-num=\"47\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"48\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"49\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"BDEBUG: Hello\"</span><span class=\"token punctuation\">,</span>            &lt;==</pre></td></tr><tr><td data-num=\"50\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"51\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span></pre></td></tr><tr><td data-num=\"52\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"53\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"54\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"55\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"56\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"57\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"6bd21962-ed78-431b-9aac-e866a0643dd4\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"58\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span></pre></td></tr><tr><td data-num=\"59\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"60\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"61\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"62\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"63\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"63-删除无用字段\"><a class=\"anchor\" href=\"#63-删除无用字段\">#</a> 6.3 删除无用字段</h3>\n<ol>\n<li>配置文件编写</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/conf.d/07-log-processors-output-console.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span> /var/log/test.log             <span class=\"token comment\"># 目标日志文件路径</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">processors</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">drop_fields</span><span class=\"token punctuation\">:</span>                       <span class=\"token comment\"># 移除指定字段的处理器</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>      <span class=\"token key atrule\">fields</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"ecs\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"host\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"input\"</span><span class=\"token punctuation\">]</span>   <span class=\"token comment\"># 需要删除的字段列表</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token key atrule\">console</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动 filebeat 并写入测试内容</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># filebeat -e -c /etc/filebeat/conf.d/07-log-processors-output-console.yml</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 向 test.log 写入内容</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Hello filebeat\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr></table></figure><ol start=\"3\">\n<li>检查对应的结果<br />\n会发现 ecs、host、input 等字段都被删除了。</li>\n</ol>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-27T13:25:48.805Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">68</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/test.log\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Hello filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"d73fa509-7ce0-4832-94cb-9f572ca69ada\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure><h3 id=\"64-重写源数据信息\"><a class=\"anchor\" href=\"#64-重写源数据信息\">#</a> 6.4 重写源数据信息</h3>\n<ol>\n<li>配置文件编写</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/filebeat/conf.d/08-log-processors-output-console.yml</span></pre></td></tr></table></figure><p>配置文件内容：</p>\n<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token key atrule\">filebeat.inputs</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">-</span> <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> log</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span> /var/log/test.log            <span class=\"token comment\"># 目标日志文件路径</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">processors</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">rename</span><span class=\"token punctuation\">:</span>                <span class=\"token comment\"># 字段重命名处理器</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>      <span class=\"token key atrule\">fields</span><span class=\"token punctuation\">:</span>              <span class=\"token comment\"># 需要重命名的字段列表</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">from</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"agent.name\"</span> <span class=\"token comment\"># 原字段名</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>        <span class=\"token key atrule\">to</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"agent_name\"</span>   <span class=\"token comment\"># 新字段名 (顶级字段)</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">from</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"agent.type\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>        <span class=\"token key atrule\">to</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"agent_type\"</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">from</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"log.file.path\"</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>        <span class=\"token key atrule\">to</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"log_file_path\"</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token key atrule\">output.console</span><span class=\"token punctuation\">:</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token key atrule\">pretty</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token key atrule\">console</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr></table></figure><ol start=\"2\">\n<li>启动 filebeat 并写入测试内容</li>\n</ol>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@web01 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># filebeat -e -c /etc/filebeat/conf.d/08-log-processors-output-console.yml</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 向 test.log 写入内容</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Hello filebeat\"</span> <span class=\"token operator\">>></span> /var/log/test.log</pre></td></tr></table></figure><ol start=\"3\">\n<li>检查 filebeat 输出的结果<br />\n字段结构从嵌套变为平级，更易于后续处理。</li>\n</ol>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>  <span class=\"token property\">\"@timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-07-28T15:26:45.256Z\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>  <span class=\"token property\">\"@metadata\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token property\">\"beat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"_doc\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token property\">\"agent\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.18.2\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>    <span class=\"token property\">\"ephemeral_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"dea0a33b-419f-4900-9e2c-0a2fbace6092\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>    <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"db23f4d1-8f1e-48ac-a632-b7411303f161\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token property\">\"ecs\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>    <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8.0.0\"</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>  <span class=\"token property\">\"log\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre>    <span class=\"token property\">\"offset\"</span><span class=\"token operator\">:</span> <span class=\"token number\">83</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre>    <span class=\"token property\">\"file\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>  <span class=\"token property\">\"input\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"log\"</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>  <span class=\"token property\">\"agent_name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span><span class=\"token punctuation\">,</span>        &lt;==</pre></td></tr><tr><td data-num=\"24\"></td><td><pre>  <span class=\"token property\">\"agent_type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"filebeat\"</span><span class=\"token punctuation\">,</span>                 &lt;==</pre></td></tr><tr><td data-num=\"25\"></td><td><pre>  <span class=\"token property\">\"log_file_path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/var/log/test.log\"</span><span class=\"token punctuation\">,</span>     &lt;==</pre></td></tr><tr><td data-num=\"26\"></td><td><pre>  <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Hello filebeat\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre>  <span class=\"token property\">\"host\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"es-node4.wang.org\"</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre>  <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure>",
            "tags": [
                "ELK"
            ]
        },
        {
            "id": "http://blog.jaxxwang.cn/posts/3192084428.html",
            "url": "http://blog.jaxxwang.cn/posts/3192084428.html",
            "title": "03 Elasticsearch 集群",
            "date_published": "2025-12-09T16:00:00.000Z",
            "content_html": "<h2 id=\"1-elasticsearch-集群\"><a class=\"anchor\" href=\"#1-elasticsearch-集群\">#</a> 1、ElasticSearch 集群</h2>\n<h3 id=\"11-es-集群优势\"><a class=\"anchor\" href=\"#11-es-集群优势\">#</a> 1.1 ES 集群优势</h3>\n<p>Elasticsearch 集群是由多个节点组成的一个分布式系统。<br />\n使用 Elasticsearch 集群有以下几个优点：</p>\n<ol>\n<li><strong>扩展性</strong>：Elasticsearch 集群将数据分布在多个节点，也就是可以使用更多的 CPU、内存、磁盘等。从而能够进行大规模的数据存储和处理工作。随着数据不断的增长，可以通过向集群添加更多的节点来应对。这样即使数据量达到 PB 级别，Elasticsearch 集群仍可以正常工作。<br />\n场景说明：应用程序每天生成数百万条日志。单个服务器可能很快就会被数据量压垮。使用 Elasticsearch 集群后，就可以将数据均匀分布到多个节点上，这样每个节点只需要负责处理一部分的数据，从而实现整体的扩展性，以应对大规模的数据增长。</li>\n<li><strong>数据的容灾</strong>：Elasticsearch 集群通过在多个节点上存储数据的副本，来实现数据的容灾。意味着，如果某个节点发生故障，数据仍然可以从其他节点的副本中快速恢复，无需人工干预，从而减少了业务中断的风险。从而保证了整个集群的正常运行。</li>\n<li><strong>服务的高可用性</strong>：Elasticsearch 集群具有自动检测节点故障的能力。当某个节点发生故障时，集群会将故障节点上的任务快速分配给其他正常运行的节点。这样，即使某个节点发生故障，整个集群仍可以继续正常运行。（用户几乎感觉不到任何影响。）</li>\n</ol>\n<h3 id=\"12-es-如何组集群\"><a class=\"anchor\" href=\"#12-es-如何组集群\">#</a> 1.2 ES 如何组集群</h3>\n<ol>\n<li>\n<p>单节点 ES，如下图所示；</p>\n</li>\n<li>\n<p>如果单节点出现问题，服务就不可用了，新增一个 ES 节点加入集群</p>\n</li>\n</ol>\n<p>Elasticsearch 集群是由多个节点组成的，通过  <code>cluster.name</code>  定义集群名称，然后每个节点通过  <code>node.name</code>  来标识在集群中的名称。<br />\n <code>cluster.name</code>  相同则表示隶属于同一个集群。</p>\n<h2 id=\"2-es-集群环境部署\"><a class=\"anchor\" href=\"#2-es-集群环境部署\">#</a> 2、ES 集群环境部署</h2>\n<h3 id=\"20-环境地址规划\"><a class=\"anchor\" href=\"#20-环境地址规划\">#</a> 2.0 环境地址规划</h3>\n<table>\n<thead>\n<tr>\n<th>系统版本</th>\n<th>主机名称</th>\n<th>IP 地址</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RockyLinux9 | Ubuntu2204</td>\n<td><a href=\"http://kibana.wang.org\">kibana.wang.org</a></td>\n<td>192.168.80.150</td>\n</tr>\n<tr>\n<td>RockyLinux9 | Ubuntu2204</td>\n<td><a href=\"http://es-node1.wang.org\">es-node1.wang.org</a></td>\n<td>192.168.80.151</td>\n</tr>\n<tr>\n<td>RockyLinux9 | Ubuntu2204</td>\n<td><a href=\"http://es-node2.wang.org\">es-node2.wang.org</a></td>\n<td>192.168.80.152</td>\n</tr>\n<tr>\n<td>RockyLinux9 | Ubuntu2204</td>\n<td><a href=\"http://es-node3.wang.org\">es-node3.wang.org</a></td>\n<td>192.168.80.153</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"21-node1-集群节点配置\"><a class=\"anchor\" href=\"#21-node1-集群节点配置\">#</a> 2.1 node1 集群节点配置</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、安装 elasticSearch</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># yum install java-17-openjdk java-17-openjdk-devel -y</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rpm -ivh elasticsearch-8.18.2-x86_64.rpm</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span>$ dpkg <span class=\"token parameter variable\">-i</span> elasticsearch-8.18.2-amd64.deb</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 2、配置 elasticSearch</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/elasticsearch.yml</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>cluster.name: es-cluster                <span class=\"token comment\"># 集群名称</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>node.name: es-node1                     <span class=\"token comment\"># 节点名称</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>path.data: /var/lib/elasticsearch       <span class=\"token comment\"># 数据存储路径</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>path.logs: /var/log/elasticsearch       <span class=\"token comment\"># 日志存储路径</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token comment\"># bootstrap.memory_lock: true           # 内存锁定，避免 es 使用 swap</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>network.host: <span class=\"token number\">192.168</span>.80.151            <span class=\"token comment\"># 本机 IP 地址，监听在本地哪个地址上</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>http.port: <span class=\"token number\">9200</span>                         <span class=\"token comment\"># 监听端口</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>discovery.seed_hosts: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span>  <span class=\"token comment\"># 集群主机列表</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre>cluster.initial_master_nodes: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span>  <span class=\"token comment\"># 参与选举的主机，仅第一次启动集群时进行选举 [可以填写 node.name 的名称]</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token comment\"># 注释如下行重复配置 [重要]</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre><span class=\"token comment\"># cluster.initial_master_nodes: [\"es-node1.wang.org\"]</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre></pre></td></tr><tr><td data-num=\"20\"></td><td><pre><span class=\"token comment\"># 关闭 Security</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>xpack.security.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre>xpack.security.enrollment.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token comment\"># 3. 配置 JVM 内存</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/jvm.options</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre><span class=\"token parameter variable\">-Xms512m</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre><span class=\"token parameter variable\">-Xmx512m</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre></pre></td></tr><tr><td data-num=\"29\"></td><td><pre><span class=\"token comment\"># 4. 重启 ES 服务</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rm -rf /var/log/elasticsearch/*</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart elasticsearch</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node1 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable --now elasticsearch</span></pre></td></tr></table></figure><h3 id=\"22-node2-集群节点配置\"><a class=\"anchor\" href=\"#22-node2-集群节点配置\">#</a> 2.2 node2 集群节点配置</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、安装 elasticSearch</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># yum install java-17-openjdk java-17-openjdk-devel -y</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rpm -ivh elasticsearch-8.18.2-x86_64.rpm</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span>$ dpkg <span class=\"token parameter variable\">-i</span> elasticsearch-8.18.2-amd64.deb</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 2、配置 elasticSearch</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/elasticsearch.yml</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>cluster.name: es-cluster</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>node.name: es-node2</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>path.data: /var/lib/elasticsearch</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>path.logs: /var/log/elasticsearch</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>network.host: <span class=\"token number\">192.168</span>.80.152            <span class=\"token comment\"># 本机 IP 地址</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>discovery.seed_hosts: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>cluster.initial_master_nodes: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token comment\"># 注释如下行重复配置 [重要]</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token comment\"># cluster.initial_master_nodes: [\"es-node2.wang.org\"]</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre></pre></td></tr><tr><td data-num=\"18\"></td><td><pre><span class=\"token comment\"># 关闭 Security</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>xpack.security.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>xpack.security.enrollment.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre></pre></td></tr><tr><td data-num=\"22\"></td><td><pre><span class=\"token comment\"># 3. 配置 JVM 内存</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/jvm.options</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token parameter variable\">-Xms512m</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre><span class=\"token parameter variable\">-Xmx512m</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre></pre></td></tr><tr><td data-num=\"27\"></td><td><pre><span class=\"token comment\"># 4. 重启 ES 服务</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rm -rf /var/log/elasticsearch/*</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart elasticsearch</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node2 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable --now elasticsearch</span></pre></td></tr></table></figure><h3 id=\"23-node3-集群节点配置\"><a class=\"anchor\" href=\"#23-node3-集群节点配置\">#</a> 2.3 node3 集群节点配置</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、安装 elasticSearch</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># yum install java-17-openjdk java-17-openjdk-devel -y</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rpm -ivh elasticsearch-8.18.2-x86_64.rpm</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span>$ dpkg <span class=\"token parameter variable\">-i</span> elasticsearch-8.18.2-amd64.deb</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># 2、配置 elasticSearch</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/elasticsearch.yml</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>cluster.name: es-cluster</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>node.name: es-node3</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>path.data: /var/lib/elasticsearch</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>path.logs: /var/log/elasticsearch</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>network.host: <span class=\"token number\">192.168</span>.80.153        <span class=\"token comment\"># 本机 IP 地址</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>discovery.seed_hosts: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>cluster.initial_master_nodes: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token comment\"># 注释如下行重复配置 [重要]</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token comment\"># cluster.initial_master_nodes: [\"es-node3.wang.org\"]</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token comment\"># 关闭 Security</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre>xpack.security.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre>xpack.security.enrollment.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre></pre></td></tr><tr><td data-num=\"23\"></td><td><pre><span class=\"token comment\"># 3. 配置 JVM 内存</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/jvm.options</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre><span class=\"token parameter variable\">-Xms512m</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre><span class=\"token parameter variable\">-Xmx512m</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre></pre></td></tr><tr><td data-num=\"28\"></td><td><pre><span class=\"token comment\"># 4. 重启 ES 服务</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rm -rf /var/log/elasticsearch/*</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart elasticsearch</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable --now elasticsearch</span></pre></td></tr></table></figure><h2 id=\"3-es-集群状态检测\"><a class=\"anchor\" href=\"#3-es-集群状态检测\">#</a> 3、ES 集群状态检测</h2>\n<h3 id=\"31-es-集群指标状态\"><a class=\"anchor\" href=\"#31-es-集群指标状态\">#</a> 3.1 ES 集群指标状态</h3>\n<p><code>Cluster Health</code>  获取集群的健康状态，整个集群状态包括以下三种：</p>\n<ol>\n<li><strong>green</strong>：健康状态，指所有主副分片都正常分配</li>\n<li><strong>yellow</strong>：所有主分片都正常分配，但是有副本分片未正常分配</li>\n<li><strong>red</strong>：有主分片未分配，也就是索引不完备，写可能有问题。（但不代表不能读取数据）</li>\n</ol>\n<p>检查 ES 集群是否正常运行，可以通过 curl、Cerebro 两种方式。</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">curl</span> http://127.0.0.1:9200/_cat/health</pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">curl</span> http://127.0.0.1:9200/_cat/nodes?v</pre></td></tr></table></figure><h3 id=\"32-curl-命令检查集群状态\"><a class=\"anchor\" href=\"#32-curl-命令检查集群状态\">#</a> 3.2 Curl 命令检查集群状态</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、使用 curl 工具检查 ES 集群状态</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node3 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># curl http://192.168.80.151:9200/_cluster/health?pretty=true</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>  <span class=\"token string\">\"cluster_name\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"es-cluster\"</span>,</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>  <span class=\"token string\">\"status\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"green\"</span>,</pre></td></tr><tr><td data-num=\"6\"></td><td><pre>  <span class=\"token string\">\"timed_out\"</span> <span class=\"token builtin class-name\">:</span> false,</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>  <span class=\"token string\">\"number_of_nodes\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">3</span>,</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>  <span class=\"token string\">\"number_of_data_nodes\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">3</span>,</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>  <span class=\"token string\">\"active_primary_shards\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">36</span>,</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>  <span class=\"token string\">\"active_shards\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">72</span>,</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>  <span class=\"token string\">\"relocating_shards\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"12\"></td><td><pre>  <span class=\"token string\">\"initializing_shards\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"13\"></td><td><pre>  <span class=\"token string\">\"unassigned_shards\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"14\"></td><td><pre>  <span class=\"token string\">\"unassigned_primary_shards\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"15\"></td><td><pre>  <span class=\"token string\">\"delayed_unassigned_shards\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"16\"></td><td><pre>  <span class=\"token string\">\"number_of_pending_tasks\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"17\"></td><td><pre>  <span class=\"token string\">\"number_of_in_flight_fetch\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"18\"></td><td><pre>  <span class=\"token string\">\"task_max_waiting_in_queue_millis\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">0</span>,</pre></td></tr><tr><td data-num=\"19\"></td><td><pre>  <span class=\"token string\">\"active_shards_percent_as_number\"</span> <span class=\"token builtin class-name\">:</span> <span class=\"token number\">100.0</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre></pre></td></tr><tr><td data-num=\"22\"></td><td><pre><span class=\"token comment\"># 2、也可以编写脚本监控 ES 集群状态</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> http://192.168.80.151:9200/_cluster/health?pretty<span class=\"token operator\">=</span>true <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token string\">\"status\"</span> <span class=\"token operator\">|</span> <span class=\"token function\">awk</span> <span class=\"token parameter variable\">-F</span> <span class=\"token string\">'\"'</span> <span class=\"token string\">'&#123;print $4&#125;'</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token comment\"># 输出: green</span></pre></td></tr></table></figure><h3 id=\"33-安装-cerebro-检查集群状态\"><a class=\"anchor\" href=\"#33-安装-cerebro-检查集群状态\">#</a> 3.3 安装 Cerebro 检查集群状态</h3>\n<p>cerebro 是可视化工具，用于检查 ES 集群状态。</p>\n<h4 id=\"rockylinux9-部署-cerebro\"><a class=\"anchor\" href=\"#rockylinux9-部署-cerebro\">#</a> RockyLinux9 部署 Cerebro</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1、安装 java, 它目前仅支持 java1.8 版本</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># 并不支持较高的 java 版本，\"因此不要与 ES 安装在同一节点上\"</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel -y</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 2、安装 Cerebro</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># wget https://github.com/lmenezes/cerebro/releases/download/v0.9.4/cerebro-0.9.4-1.noarch.rpm</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rpm -ivh cerebro-0.9.4-1.noarch.rpm</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\"># 3、配置 Cerebro</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/cerebro/application.conf</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>data.path: <span class=\"token string\">\"/var/lib/cerebro/cerebro.db\"</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token comment\"># data.path = \"./cerebro.db\"</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token comment\"># 4、启动 Cerebro</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl start cerebro</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token comment\"># 查看端口</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre><span class=\"token punctuation\">[</span>root@kibana ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># netstat -lntp</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre>Proto Recv-Q Send-Q Local Address   Foreign Address     State       PID/Program name</pre></td></tr><tr><td data-num=\"20\"></td><td><pre>tcp6       <span class=\"token number\">0</span>      <span class=\"token number\">0</span> :::9000         :::*                LISTEN     <span class=\"token number\">504</span>/java</pre></td></tr></table></figure><h4 id=\"ubuntu2204-部署-cerebro\"><a class=\"anchor\" href=\"#ubuntu2204-部署-cerebro\">#</a> Ubuntu2204 部署 Cerebro</h4>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 可以将其安装在 Kibana 主机</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\"># 依赖 JDK-11</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># apt -y install openjdk-11-jdk</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 下载包，官方提供了 DEB 和 RPM 包</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># wget https://github.com/lmenezes/cerebro/releases/download/v0.9.4/cerebro_0.9.4_all.deb</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># 安装</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># dpkg -i cerebro_0.9.4_all.deb</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token comment\"># 启动</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl start cerebro.service</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token comment\"># 默认服务无法启动，端口无法打开</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># ss -ntlp | grep 9000</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token comment\"># 默认无法启动，查看日志，可以看到以下提示，原因是默认 cerebro.db 文件所有目录没有权限导致</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># journalctl -u cerebro</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token comment\"># 报错: Caused by: java.sql.SQLException: opening db: './cerebro.db': 权限不够</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre></pre></td></tr><tr><td data-num=\"21\"></td><td><pre><span class=\"token comment\"># 修改配置文件</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/cerebro/application.conf</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre>data.path: <span class=\"token string\">\"/var/lib/cerebro/cerebro.db\"</span>  <span class=\"token comment\"># 取消此行注释</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token comment\"># data.path = \"./cerebro.db\"              # 注释此行，默认路径是 /usr/share/cerebro/cerebro.db</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre></pre></td></tr><tr><td data-num=\"26\"></td><td><pre><span class=\"token comment\"># 此目录自动生成</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># ll -d /var/lib/cerebro</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre>drwxr-xr-x <span class=\"token number\">2</span> cerebro cerebro <span class=\"token number\">4096</span>   <span class=\"token number\">4</span>月 <span class=\"token number\">10</span>     <span class=\"token number\">2021</span> /var/lib/cerebro/</pre></td></tr><tr><td data-num=\"29\"></td><td><pre></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token comment\"># 重启服务</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart cerebro.service</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl enable --now cerebro.service</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre></pre></td></tr><tr><td data-num=\"34\"></td><td><pre><span class=\"token comment\"># 默认监听 9000 端口</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre><span class=\"token punctuation\">[</span>root@ubuntu2204 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># ss -ntlp | grep 9000</span></pre></td></tr><tr><td data-num=\"36\"></td><td><pre>LISTEN   <span class=\"token number\">0</span>   <span class=\"token number\">100</span>   *:9000           *:*         users:<span class=\"token variable\"><span class=\"token punctuation\">((</span>\"java\"<span class=\"token punctuation\">,</span>pid<span class=\"token operator\">=</span><span class=\"token number\">26333</span><span class=\"token punctuation\">,</span>fd<span class=\"token operator\">=</span><span class=\"token number\">155</span><span class=\"token punctuation\">))</span></span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre></pre></td></tr><tr><td data-num=\"38\"></td><td><pre><span class=\"token comment\"># 访问下面链接地址</span></pre></td></tr><tr><td data-num=\"39\"></td><td><pre>http://192.168.80.150:9000</pre></td></tr></table></figure><h4 id=\"访问-cerebro-页面\"><a class=\"anchor\" href=\"#访问-cerebro-页面\">#</a> 访问 Cerebro 页面</h4>\n<p>在  <code>Node address</code>  输入框中输入任意 ES 集群节点的地址： <code>http://192.168.80.151:9200</code></p>\n<h2 id=\"4-es-集群节点类型\"><a class=\"anchor\" href=\"#4-es-集群节点类型\">#</a> 4、ES 集群节点类型</h2>\n<p>ES 集群中节点类型介绍：</p>\n<ul>\n<li>Master</li>\n<li>Data</li>\n<li>Ingest</li>\n<li>Coordinating</li>\n</ul>\n<h3 id=\"41-cluster-state\"><a class=\"anchor\" href=\"#41-cluster-state\">#</a> 4.1 Cluster State</h3>\n<p><code>Cluster State</code>  是用来存储 Elasticsearch 集群相关的元数据信息。它存储在每个节点上，主要包含以下信息：</p>\n<ul>\n<li>节点信息：这部分信息包括节点名称或节点的 IP、节点的 IP 地址或端口等。</li>\n<li>索引元数据：这部分信息包括索引的名称、索引的配置设置（如分片数量、副本数量等）以及字段类型和属性等。</li>\n</ul>\n<h3 id=\"42-master-角色\"><a class=\"anchor\" href=\"#42-master-角色\">#</a> 4.2 Master 角色</h3>\n<ol>\n<li>Elasticsearch 集群中只能有一个处于激活状态的 Master 节点。Master 节点负责管理和控制整个集群的操作；</li>\n<li>Master 节点负责维护集群状态（Cluster State）。当集群状态发生变化（例如，新增或删除索引、修改索引设置等）时，Master 节点会将更新后的集群状态同步给其他节点，以保持整个集群的状态一致性。</li>\n<li>Master 节点是通过选举产生的。集群中的节点可以设置  <code>node.master: true</code>  来允许它成为 Master 节点的候选者（默认为 true）。如果当前的 Master 节点失效或不可用时，集群会自动触发选举过程，从候选者中选出一个新的 Master 节点。</li>\n</ol>\n<table>\n<thead>\n<tr>\n<th>版本</th>\n<th>角色配置</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>7.X 版本</td>\n<td>Master 角色: <br>  <code>node.master: true</code>  <br>  <code>node.data: false</code>  <br> Data 角色: <br>  <code>node.master: false</code>  <br>  <code>node.data: true</code>  <br> Coordinating 角色: <br>  <code>node.master: false</code>  <br>  <code>node.data: false</code></td>\n</tr>\n<tr>\n<td>8.X 版本</td>\n<td>Master 角色: <br>  <code>node.roles: [&quot;master&quot;,&quot;data&quot;]</code>  (既当 master, 又当 data) <br> Data 角色: <br>  <code>node.roles: [&quot;data&quot;]</code>  <br> Coordinating 角色: <br>  <code>node.roles: []</code></td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"43-data-角色\"><a class=\"anchor\" href=\"#43-data-角色\">#</a> 4.3 Data 角色</h3>\n<p>Data 节点是 Elasticsearch 集群中负责存储数据的节点。默认情况下，集群中的所有节点都是 Data 类型。</p>\n<ol>\n<li>可以通过设置  <code>node.data: true</code> （默认为 true）来保持节点作为 Data 节点。</li>\n<li>当创建索引后，索引中的数据会被存储在一个或多个 Data 节点上。这些能够存储索引数据的节点被称为 Data 节点。Data 节点负责处理数据查询、聚合和搜索等操作，它们直接影响整个集群的性能和存储能力。</li>\n</ol>\n<p>通过合理分配和管理 Data 节点，可以提高 Elasticsearch 集群的数据处理能力、查询性能和存储容量。在实际应用中，需要根据业务需求和硬件资源来调整 Data 节点的数量和配置。</p>\n<h3 id=\"44-ingest-角色\"><a class=\"anchor\" href=\"#44-ingest-角色\">#</a> 4.4 Ingest 角色</h3>\n<p>Ingest 节点是 Elasticsearch 集群中负责预处理文档的过程，它允许文档在被写入到 Elasticsearch 之前，对其进行处理、清洗、或转换。</p>\n<ol>\n<li>假设你有一个包含日志数据的 JSON 文档，其中包含一个时间戳字段，但格式不符合标准。我们就可以在文档被写入之前，使用 date 处理器来转换时间戳字段的格式。</li>\n<li><code>node.ingest: true</code>  表示该节点可以对文档进行预处理操作。如果你希望某个节点不处理 Ingest 任务，可以设置为 false。</li>\n</ol>\n<h3 id=\"45-coordinating-角色\"><a class=\"anchor\" href=\"#45-coordinating-角色\">#</a> 4.5 Coordinating 角色</h3>\n<p>处理请求的节点被称为 Coordinating 节点。Coordinating 节点是 Elasticsearch 集群中所有节点的默认角色，无法取消。</p>\n<ol>\n<li>Coordinating 节点主要负责将请求路由到正确的节点。例如，创建索引的请求会被 Coordinating 节点路由到 Master 节点进行处理，而数据查询或写入的请求会被路由到相应的 Data 节点上。</li>\n<li>当一个节点同时设置  <code>node.master：false</code> 、 <code>node.data：false</code>  时，该节点仅充当 Coordinating 路由节点的角色。</li>\n</ol>\n<h3 id=\"46-角色设定示例\"><a class=\"anchor\" href=\"#46-角色设定示例\">#</a> 4.6 角色设定示例</h3>\n<ol>\n<li>如果希望节点只作为主节点<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ES7.X</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key atrule\">node.master</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key atrule\">node.data</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ES8.X</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">node.roles</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"master\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"ingest\"</span><span class=\"token punctuation\">]</span>    <span class=\"token comment\"># 只做 master, 不当 data</span></pre></td></tr></table></figure></li>\n<li>如果希望节点只作为数据节点<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ES7.X</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key atrule\">node.master</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key atrule\">node.data</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ES8.X</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">node.roles</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"data\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"ingest\"</span><span class=\"token punctuation\">]</span>    <span class=\"token comment\"># 只当 data, 不做 master</span></pre></td></tr></table></figure></li>\n<li>如果希望节点同时担任数据节点和主节点<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ES7.X</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key atrule\">node.master</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key atrule\">node.data</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ES8.X</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">node.roles</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"master\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"data\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"ingest\"</span><span class=\"token punctuation\">]</span>    <span class=\"token comment\"># 同时担任 master data</span></pre></td></tr></table></figure></li>\n<li>如果希望节点不担任任何特定角色（不推荐）<figure class=\"highlight yaml\"><figcaption data-lang=\"YAML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># ES7.X</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token key atrule\">node.master</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token key atrule\">node.data</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">false</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># ES8.X</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token key atrule\">node.roles</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>    <span class=\"token comment\"># 不担任任何角色</span></pre></td></tr></table></figure></li>\n</ol>\n<h3 id=\"5案例演示\"><a class=\"anchor\" href=\"#5案例演示\">#</a> 5. 案例演示</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 修改 ES 配置</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>root@es-node1: <span class=\"token function\">vim</span> /etc/elasticsearch/elasticsearch.yml</pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node.roles: <span class=\"token punctuation\">[</span><span class=\"token string\">\"data\"</span>, <span class=\"token string\">\"ingest\"</span><span class=\"token punctuation\">]</span>    <span class=\"token comment\"># 不做 master 节点 (默认每个节点都存在: master data ingest)</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 重启 ES 服务</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>root@es-node1: systemctl restart elasticsearch</pre></td></tr></table></figure><h2 id=\"5-es-集群分片\"><a class=\"anchor\" href=\"#5-es-集群分片\">#</a> 5、ES 集群分片</h2>\n<h3 id=\"51-什么是分片\"><a class=\"anchor\" href=\"#51-什么是分片\">#</a> 5.1 什么是分片</h3>\n<p>分片是处理和存储 PB 级别数据的基础。在 Elasticsearch 中，分片是一种<strong>数据分区机制</strong>，它允许将一份完整的数据分散存储到集群的多个不同服务器上。而每个分片只是索引的一个部分，这使得它们可以独立进行存储和查询。</p>\n<p>在 Elasticsearch 中，分片又被分为了两种类型：</p>\n<ol>\n<li><strong>主分片</strong>：主要负责存储数据。创建后主分片的数量是固定的（不允许修改）。</li>\n<li><strong>副本分片</strong>：每个主分片可以配置一个或多个副本分片，以增强数据的容错能力。副本分片从对应的主分片同步数据，确保在主分片出现问题时仍能提供服务。</li>\n</ol>\n<h3 id=\"52-什么是副本分片\"><a class=\"anchor\" href=\"#52-什么是副本分片\">#</a> 5.2 什么是副本分片</h3>\n<p>副本分片主要用于提高数据的可用性，这样即使某个节点发生故障，系统依然可以自动从其他节点上的副本分片中恢复，并继续提供数据访问服务。</p>\n<p>如下图所示，node2 上是 oldwang_index 索引的一个完整副本数据。</p>\n<h3 id=\"53-es-集群如何增大容量\"><a class=\"anchor\" href=\"#53-es-集群如何增大容量\">#</a> 5.3 ES 集群如何增大容量</h3>\n<ol>\n<li>如下 3 个节点的 ES 集群，创建了一个 oldwang_index 索引，同时指定了 3 个分片，和 1 个副本<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 创建索引，设定主分片和副本分片</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>PUT /oldwang_index</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>    <span class=\"token string\">\"settings\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>    <span class=\"token string\">\"index\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>        <span class=\"token string\">\"number_of_shards\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token number\">3</span>,    <span class=\"token comment\"># 主分片</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>        <span class=\"token string\">\"number_of_replicas\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token number\">1</span>   <span class=\"token comment\"># 副本分配</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>    <span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token comment\"># 动态修改副本分片</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>PUT /oldwang_index/_settings</pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token punctuation\">&#123;</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre>    <span class=\"token string\">\"number_of_replicas\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token number\">2</span>    <span class=\"token comment\"># 三节点，三分片。因此最多只需要两副本就完全够了.</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token punctuation\">&#125;</span></pre></td></tr></table></figure></li>\n</ol>\n<p><strong>问题</strong>：目前一共有 3 个 ES 节点，如果此时增加一个新节点 是否能提高 oldwang_index 索引数据容量？<br />\n<strong>答案</strong>：不能，因为 oldwang_index 只有 3 个分片，已经分布在 3 台节点上，那么新增的第四个节点对于 oldwang_index 而言是无法使用到的。所以也无法带来数据容量的提升。</p>\n<h3 id=\"54-es-集群如何增加读性能\"><a class=\"anchor\" href=\"#54-es-集群如何增加读性能\">#</a> 5.4 ES 集群如何增加读性能</h3>\n<p><strong>问题</strong>：目前一共有 3 个 ES 节点，如果增加副本数是否能提高 oldwang_index 索引的读性能？<br />\n<strong>答案</strong>：不能，因为新增的副本还是会分布在这 node1、node2、node3 这三个节点上的，还是使用了相同的资源，也就意味着有读请求来时，这些请求还是会分配到 node1、node2、node3 上进行处理、也就意味着，还是利用了相同的硬件资源，所以不会提升读性能。</p>\n<p><strong>问题</strong>：如果需要增加读吞吐量性能，应该怎么来做？<br />\n<strong>答案</strong>：增加读吞吐量还是需要添加节点，比如在增加三个节点 node4、node5、node6 那么将原来的 R0、R1、R2 分别迁移至新增的三个节点上，当有读请求来时会被分配 node4、node5、node6，也就意味着有新的 CPU、内存、IO，这样就不会在占用 node1、node2、node3 的硬件资源，那么这个时候读吞吐量才会得到真正的提升。</p>\n<h3 id=\"55-es-副本与分片总结\"><a class=\"anchor\" href=\"#55-es-副本与分片总结\">#</a> 5.5 ES 副本与分片总结</h3>\n<p>分片数和副本的设定非常重要，需要在集群部署前进行仔细规划：</p>\n<ol>\n<li><strong>分片过小</strong>：可能导致在后续需要水平扩容时无法通过增加节点来实现，因为数据已经在现有节点上达到了分布的极限。</li>\n<li><strong>分片过大</strong>：可能会导致单个节点上分布过多的分片，从而造成资源的浪费。此外，过多的分片也会影响 ES 的查询性能。</li>\n</ol>\n<h2 id=\"6-es-集群故障转移\"><a class=\"anchor\" href=\"#6-es-集群故障转移\">#</a> 6、ES 集群故障转移</h2>\n<h3 id=\"61-什么是故障转移\"><a class=\"anchor\" href=\"#61-什么是故障转移\">#</a> 6.1 什么是故障转移</h3>\n<p>所谓故障转移指的是，当集群中有节点发生故障时，这个集群是如何进行自动修复的。<br />\nES 集群目前是由 3 个节点组成，此时集群状态是 green。</p>\n<h3 id=\"62-模拟节点故障案例\"><a class=\"anchor\" href=\"#62-模拟节点故障案例\">#</a> 6.2 模拟节点故障案例</h3>\n<p>假设：node1 所在机器宕机导致服务终止，此时 ES 集群会如何处理；大体分为三个步骤：</p>\n<ol>\n<li>\n<p><strong>重新选举</strong></p>\n</li>\n<li>\n<p><strong>主分片调整</strong></p>\n</li>\n<li>\n<p><strong>副本分片调整</strong></p>\n</li>\n<li>\n<p><strong>重新选举阶段</strong>：node2 和 node3 发现 node1 无法响应；一段时间后会发起 master 选举。此时集群状态变为 Red 状态，假定选择 node2 为 master 节点；</p>\n</li>\n<li>\n<p><strong>主分片调整阶段</strong>：node2 发现主分片 P0 未分配，将 node3 上的 R0 提升为主分片。此时所有的主分片都正常分配，集群状态变为 Yellow 状态；</p>\n</li>\n<li>\n<p><strong>副本分片调整阶段</strong>：node2 将 P0 和 P1 主分片 重新生成新的副本分片 R0、R1。此时集群状态变为 Green；</p>\n</li>\n</ol>\n<h2 id=\"7-es-文档路由原理\"><a class=\"anchor\" href=\"#7-es-文档路由原理\">#</a> 7、ES 文档路由原理</h2>\n<p>ES 文档分布式存储，当一个文档存储至 ES 集群时，存储的原理是什么样的？<br />\n如图所示，当我们想在一个集群保存文档时，Document1 是如何存储到分片 P1 的？选择 P1 的依据是什么？</p>\n<p>其实是有一个 <strong>文档到分片的映射算法</strong>，其目的是使所有文档均匀分布在所有的分片上。ES 既不使用随机算法，也不使用轮询算法，而是通过以下公式计算文档对应的分片：</p>\n<pre><code>shard = hash(routing) % number_of_primary_shards\n</code></pre>\n<ul>\n<li><code>hash</code> ：算法保证将数据均匀分散在分片中</li>\n<li><code>routing</code> ：是一个关键参数，默认是文档 id, 也可以自定义。</li>\n<li><code>number_of_primary_shards</code> ：主分片数（与主分片取模）</li>\n</ul>\n<p><strong>注意</strong>：该算法与主分片数相关，一旦确定后便不能更改主分片。因为一旦修改主分片数量， <code>shard</code>  的计算结果就会完全不一样，会导致无法定位到原有数据。</p>\n<p><strong>总结</strong>：ES 用  <code>hash(routing) % 主分片数</code>  来把文档分配到对应分片，确保分布均衡且可定位，因此主分片数不能改，否则找不到数据。</p>\n<h3 id=\"71-文档的创建流程\"><a class=\"anchor\" href=\"#71-文档的创建流程\">#</a> 7.1 文档的创建流程</h3>\n<ol>\n<li>客户端发送请求：请求发送到任意节点（协调节点）。</li>\n<li>路由计算：协调节点 根据文档 ID 计算分片号： <code>shard = hash(document_id) % 主分片数量</code></li>\n<li>定位主分片：找到对应的主分片所在节点。</li>\n<li>主分片写入：写入内存 + translog，同时转发给副本分片。</li>\n<li>副本写入：副本分片完成相同写入操作。</li>\n<li>写入成功：所有副本确认后，最终返回成功响应给客户端。</li>\n</ol>\n<h3 id=\"72-文档的读取流程\"><a class=\"anchor\" href=\"#72-文档的读取流程\">#</a> 7.2 文档的读取流程</h3>\n<ol>\n<li>客户端发起查询请求：发送到任意节点（协调节点）。</li>\n<li>协调节点分发请求到所有分片：查询是并行的，包括主分片和副本分片中任选一个。</li>\n<li>每个分片独立查询：每个分片返回自己的匹配结果（文档 + 分数等）。</li>\n<li>协调节点合并结果：统一排序、分页等，生成最终结果。</li>\n<li>返回客户端：查询结果发送回客户端。</li>\n</ol>\n<h3 id=\"73-文档批量创建的流程\"><a class=\"anchor\" href=\"#73-文档批量创建的流程\">#</a> 7.3 文档批量创建的流程</h3>\n<p>（原文未补充内容）</p>\n<h3 id=\"74-文档批量读取的流程\"><a class=\"anchor\" href=\"#74-文档批量读取的流程\">#</a> 7.4 文档批量读取的流程</h3>\n<p>（原文未补充内容）</p>\n<h2 id=\"8-es-集群节点扩展\"><a class=\"anchor\" href=\"#8-es-集群节点扩展\">#</a> 8、ES 集群节点扩展</h2>\n<h3 id=\"81-环境准备\"><a class=\"anchor\" href=\"#81-环境准备\">#</a> 8.1 环境准备</h3>\n<table>\n<thead>\n<tr>\n<th>系统版本</th>\n<th>主机名称</th>\n<th>IP 地址</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RockyLinux9</td>\n<td>es-node4</td>\n<td>192.168.80.154</td>\n</tr>\n<tr>\n<td>RockyLinux9</td>\n<td>es-node5</td>\n<td>192.168.80.155</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"82-es-扩展-data-节点\"><a class=\"anchor\" href=\"#82-es-扩展-data-节点\">#</a> 8.2 ES 扩展 Data 节点</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@node4 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># grep \"^[a-Z]\" /etc/elasticsearch/elasticsearch.yml</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>cluster.name: es-cluster            <span class=\"token comment\"># 集群名称</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node.name: es-node4                 <span class=\"token comment\"># 节点名称</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>node.roles: <span class=\"token punctuation\">[</span><span class=\"token string\">\"data\"</span>, <span class=\"token string\">\"ingest\"</span><span class=\"token punctuation\">]</span>      <span class=\"token comment\"># ES8.x 配置 Data 节点，不参与 Master 选举</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>http.port: <span class=\"token number\">9200</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>path.data: /var/lib/elasticsearch</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>path.logs: /var/log/elasticsearch</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>network.host: <span class=\"token number\">192.168</span>.80.154        <span class=\"token comment\"># 内网 IP 地址</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\"># bootstrap.memory_lock: true</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>discovery.seed_hosts: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token comment\"># Enable security features</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>xpack.security.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre>xpack.security.enrollment.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token comment\"># ES7.X 配置方式</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token comment\"># node.data: true          # Data 节点</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre><span class=\"token comment\"># node.master: false       # 不参与 Master 选举</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre></pre></td></tr><tr><td data-num=\"20\"></td><td><pre><span class=\"token punctuation\">[</span>root@node4 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart elasticsearch</span></pre></td></tr></table></figure><p>访问 CereBro 验证节点，路径： <code>Nodes &gt; Data 角色</code></p>\n<h3 id=\"83-es-扩展-coordinating-节点\"><a class=\"anchor\" href=\"#83-es-扩展-coordinating-节点\">#</a> 8.3 ES 扩展 Coordinating 节点</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@node5 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># grep \"^[a-Z]\" /etc/elasticsearch/elasticsearch.yml</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>cluster.name: es-cluster                <span class=\"token comment\"># 集群名称</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>node.name: es-node5                     <span class=\"token comment\"># 节点名称</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>node.roles: <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>                          <span class=\"token comment\"># ES8 配置 Coordinating 节点</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>http.port: <span class=\"token number\">9200</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>path.data: /var/lib/elasticsearch</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>path.logs: /var/log/elasticsearch</pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># bootstrap.memory_lock: true</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>network.host: <span class=\"token number\">192.168</span>.80.155             <span class=\"token comment\"># 内网 IP 地址</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>discovery.seed_hosts: <span class=\"token punctuation\">[</span><span class=\"token string\">\"192.168.80.151\"</span>, <span class=\"token string\">\"192.168.80.152\"</span>, <span class=\"token string\">\"192.168.80.153\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token comment\"># Enable security features</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>xpack.security.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre>xpack.security.enrollment.enabled: <span class=\"token boolean\">false</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre><span class=\"token comment\"># ES7.X 配置方式</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token comment\"># node.data: false     # 不参与 Data 节点</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre><span class=\"token comment\"># node.master: false   # 不参与 Master 选举</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token punctuation\">[</span>root@node5 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart elasticsearch</span></pre></td></tr></table></figure><h3 id=\"84-节点扩展检查\"><a class=\"anchor\" href=\"#84-节点扩展检查\">#</a> 8.4 节点扩展检查</h3>\n<p>通过 cerebro 检查集群扩展后的状态。<br />\n如果出现集群无法加入、或者加入集群被拒绝，尝试删除  <code>/var/lib/elasticsearch</code>  下的文件，然后重启 ES：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@node5 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rm -rf /var/lib/elasticsearch/*</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@node5 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart elasticsearch</span></pre></td></tr></table></figure><p>如果将 data 节点修改为 Coordinating 节点，需要清理数据，否则无法启动：</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># repurpose 重新调整</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@node5 ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># /usr/share/elasticsearch/bin/elasticsearch-node repurpose</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>------------------------------------------------------------------------</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>WARNING: Elasticsearch MUST be stopped before running this tool.</pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>Found <span class=\"token number\">1</span> indices <span class=\"token punctuation\">(</span><span class=\"token number\">1</span> shards and <span class=\"token number\">1</span> index meta data<span class=\"token punctuation\">)</span> to clean up</pre></td></tr><tr><td data-num=\"7\"></td><td><pre>Use <span class=\"token parameter variable\">-v</span> to see list of paths and indices affected</pre></td></tr><tr><td data-num=\"8\"></td><td><pre>Node is being re-purposed as no-master and no-data. Clean-up of index data will be performed.</pre></td></tr><tr><td data-num=\"9\"></td><td><pre>Do you want to proceed?</pre></td></tr><tr><td data-num=\"10\"></td><td><pre>Confirm <span class=\"token punctuation\">[</span>y/N<span class=\"token punctuation\">]</span> y</pre></td></tr><tr><td data-num=\"11\"></td><td><pre>Node successfully repurposed to no-master and no-data.</pre></td></tr></table></figure><p>访问 CereBro 验证节点，路径： <code>Nodes &gt; Coordinating 角色</code></p>\n<h2 id=\"9-es-集群调优建议\"><a class=\"anchor\" href=\"#9-es-集群调优建议\">#</a> 9、ES 集群调优建议</h2>\n<h3 id=\"91-内核参数优化\"><a class=\"anchor\" href=\"#91-内核参数优化\">#</a> 9.1 内核参数优化</h3>\n<ol>\n<li><strong>内核参数优化</strong><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/sysctl.conf</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>fs.file-max<span class=\"token operator\">=</span><span class=\"token number\">655360</span>                        <span class=\"token comment\"># 设定系统最大打开文件描述符数，建议修改为 655360 或者更高；</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>vm.max_map_count <span class=\"token operator\">=</span> <span class=\"token number\">262144</span>                 <span class=\"token comment\"># 用于限制一个进程可以拥有的虚拟内存大小，建议修改成 262144 或更高。</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre>net.core.somaxconn <span class=\"token operator\">=</span> <span class=\"token number\">32768</span>                <span class=\"token comment\"># 设置系统允许的最大套接字监听（TCP SYN）队列长度；</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>net.ipv4.tcp_tw_reuse <span class=\"token operator\">=</span> <span class=\"token number\">1</span>                 <span class=\"token comment\"># 启用 TCP TIME-WAIT 状态的套接字重用。</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\"># net.ipv4.ip_local_port_range = 1000 65535 # 设置本地端口范围，即操作系统分配给本地套接字的端口号范围。</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>net.ipv4.tcp_max_tw_buckets <span class=\"token operator\">=</span> <span class=\"token number\">400000</span>      <span class=\"token comment\"># 表示操作系统允许 TIME_WAIT 数量的最大值，如果超过这个数字，TIME_WAIT 套接字将立刻被清除</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">[</span>root@node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># sysctl -p</span></pre></td></tr></table></figure></li>\n<li><strong>调整用户最大进程数（nproc），调整进程最大打开的文件描述符（nofile）</strong><figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">[</span>root@node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># rm -f /etc/security/limits.d/20-nproc.conf     # 删除默认 nproc 设定文件</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/security/limits.conf</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>*                soft    core           unlimited</pre></td></tr><tr><td data-num=\"4\"></td><td><pre>*                hard    core           unlimited</pre></td></tr><tr><td data-num=\"5\"></td><td><pre>*                soft    nproc          <span class=\"token number\">1000000</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre>*                hard    nproc          <span class=\"token number\">1000000</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre>*                soft    nofile         <span class=\"token number\">1000000</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre>*                hard    nofile         <span class=\"token number\">1000000</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre>*                soft    memlock        <span class=\"token number\">32000</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre>*                hard    memlock        <span class=\"token number\">32000</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre>*                soft    msgqueue       <span class=\"token number\">8192000</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre>*                hard    msgqueue       <span class=\"token number\">8192000</span></pre></td></tr></table></figure></li>\n</ol>\n<h3 id=\"92-配置参数优化\"><a class=\"anchor\" href=\"#92-配置参数优化\">#</a> 9.2 配置参数优化</h3>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 1. 启用内存锁定，避免 ES 使用 swap 交换分区，频繁的交换，会导致 IOPS 变高.</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># vim /etc/elasticsearch/elasticsearch.yml</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre>bootstrap.memory_lock: <span class=\"token boolean\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token comment\"># 2. 当 ES 配置内存锁定后，需要确保操作系统允许 Elasticsearch 进程锁定足够的内存.</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># sed -i '/\\[Service\\]/a LimitMEMLOCK=infinity' /usr/lib/systemd/system/elasticsearch.service</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\"># 3. 重新启动 elasticSearch</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl daemon-reload</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token punctuation\">[</span>root@es-node ~<span class=\"token punctuation\">]</span><span class=\"token comment\"># systemctl restart elasticsearch</span></pre></td></tr></table></figure><h3 id=\"93-jvm-参数优化\"><a class=\"anchor\" href=\"#93-jvm-参数优化\">#</a> 9.3 JVM 参数优化</h3>\n<h4 id=\"931-基础原则\"><a class=\"anchor\" href=\"#931-基础原则\">#</a> 9.3.1 基础原则</h4>\n<p>要估算 JVM 内存配置，主要看两点：</p>\n<ul>\n<li>要存多少数据</li>\n<li>有多少个节点（服务器）</li>\n</ul>\n<p>经验公式：<strong>1GB 内存 可以支持 48GB ~ 96GB 的数据量</strong>（通常按 1:48 来算最保险）<br />\n单个主分片大小最好控制在 <strong>30GB~50GB</strong></p>\n<h4 id=\"932-怎么估算内存和分片\"><a class=\"anchor\" href=\"#932-怎么估算内存和分片\">#</a> 9.3.2 怎么估算内存和分片？</h4>\n<p><strong>第一步</strong>：算出实际需要存储的数据量</p>\n<pre><code>实际存储量 = 总数据量 × (副本数 + 1)    // 因为副本也要占空间\n</code></pre>\n<p>例如：总数据量 1TB + 副本数据 → 实际存储数据量 2TB</p>\n<p><strong>第二步</strong>：算每个节点要存多少数据</p>\n<pre><code>每节点存储 = 实际数据量 ÷ 节点数    // 再加上 20% 预留空间\n</code></pre>\n<p>示例：实际存储量 2TB / 3 节点 + 20% 预留空间 → 每节点存储 850G</p>\n<p><strong>第三步</strong>：算每个节点需要多少内存</p>\n<pre><code>节点内存 ≈ 每节点存储量 ÷ 48（按1:48比例来算）\n</code></pre>\n<p>示例：每节点存储量 850G ÷ 48 → 节点内存 17 G</p>\n<p><strong>第四步</strong>：算分片数量（用于 ES）</p>\n<pre><code>主分片数量 = 总数据量 ÷ 30GB（建议一个分片控制在 30GB 左右）\n总分片数 = 主分片数 × (副本数 + 1)\n</code></pre>\n<p>示例：主分片数量 ≈ 33 → 总分片数 ≈ 66</p>\n<h4 id=\"933-两个简单例子\"><a class=\"anchor\" href=\"#933-两个简单例子\">#</a> 9.3.3 两个简单例子</h4>\n<p><strong>示例 1</strong>：1TB 数据，3 个节点，1 个副本</p>\n<ol>\n<li>实际要存：1TB × (1 + 1) = 2 TB</li>\n<li>每节点：2TB ÷ 3 ≈ 700GB → 加 20% ≈ 850GB    // 单节点实际存储</li>\n<li>内存需求：850GB ÷ 48 ≈ 17GB                // 单节点建议内存 17 * 2 ≈ 34G</li>\n<li>JVM 配置：每个节点内存 17GB</li>\n<li>分片数量：1TB ÷ 30GB ≈ 33 个主分片</li>\n<li>总分片数 = 33 × 2 = 66 个</li>\n<li>单个索引分片数<br />\n a. 每日数据量 ÷ 30G = （总数据量 ÷ 保留天数）÷ 30G<br />\nb. 100 ÷ 30G = 3 分片            // 每天 100G 日志<br />\n c. 1024 ÷ 30G = 33 分片      // 每天 1024G 日志</li>\n</ol>\n<p><strong>示例 2</strong>：2TB 数据，3 个节点，1 个副本</p>\n<ol>\n<li>实际要存：2TB × 2 = 4TB</li>\n<li>每节点：4TB ÷ 3 ≈ 1.4TB → 加 20% ≈ 1.7TB            // 单节点存储</li>\n<li>内存需求：1.7TB ÷ 48 ≈ 35GB → 超过建议上限（31GB）→ ⚠️ 不够用，得加节点！</li>\n</ol>\n<p>增加到 4 个节点</p>\n<ol>\n<li>每节点：4TB ÷ 4 = 1TB → 加 20% ≈ 1.2TB</li>\n<li>内存需求：1.2TB ÷ 48 ≈ 25GB → 合理！</li>\n<li>分片数量：2TB ÷ 30GB = 60 个主分片 → 总分片数 = 60 × 2 = 120 个</li>\n</ol>\n<p><strong>结论</strong>：用 4 个节点，内存控制在 31GB 以内，刚刚好！</p>\n<h4 id=\"934-生产环境建议\"><a class=\"anchor\" href=\"#934-生产环境建议\">#</a> 9.3.4 生产环境建议</h4>\n<ul>\n<li>每天数据量：约 1TB</li>\n<li>机器配置：16 核，64GB 内存，6TB 磁盘（3 台 ECS）</li>\n<li>JVM 设置：最大和最小内存都设为 31GB</li>\n<li>最好不要超过 32GB（超过后 JVM 的内存优化会失效）</li>\n<li>ES 清理策略：只保留最近 1~2 周的数据，避免磁盘被撑爆。</li>\n</ul>\n<p>✅ <strong>结论</strong></p>\n<ul>\n<li>每天数据约 1TB，建议单分片控制在 30~50GB，1TB / 30GB ≈ 每天 33 个主分片。</li>\n<li>实际存储量 = 日志量 × (副本数 + 1)，估算内存按 1:48 比例。</li>\n<li>JVM 不建议超过 31GB，超过后 G1 GC 优化失效。</li>\n<li>索引清理建议使用 ILM，仅保留最近 1~2 周数据，避免磁盘撑满。</li>\n</ul>\n<hr />\n",
            "tags": [
                "ELK"
            ]
        }
    ]
}