<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>告警 - tag - 沐木</title><link>https://oldletter.cn/tags/%E5%91%8A%E8%AD%A6/</link><description>告警 - tag - 沐木</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Fri, 24 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://oldletter.cn/tags/%E5%91%8A%E8%AD%A6/" rel="self" type="application/rss+xml"/><item><title>数据开放平台架构设计（五）：监控与治理</title><link>https://oldletter.cn/posts/dp-05-monitor-and-governance/</link><pubDate>Fri, 24 Apr 2026 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/dp-05-monitor-and-governance/</guid><description><![CDATA[<blockquote>
<p><strong>上一篇：</strong> <a href="/posts/dp-04-data-transform/" rel="">数据开放平台（四）：数据转换与加工</a></p></blockquote>
<p>数据开放平台上线之后，更怕两件事：一是出了问题不知道，二是知道了问题找不到原因。API 响应慢了，是 SQL 没走索引还是数据库负载高？某个调用方报错，是参数传错了还是数据源挂了？某个字段被改了，谁改的？什么时候改的？</p>
<p>这些问题靠翻代码加日志是搞不定的，需要系统化的监控和治理能力。这一篇聊四个核心能力：<strong>调用链追踪</strong>、<strong>慢查询告警</strong>、<strong>数据血缘</strong>、<strong>审计日志</strong>。</p>
<hr>
<h2 id="一调用链追踪">一、调用链追踪</h2>
<p>每个 API 调用都要记录完整的执行链路：从请求进来到响应返回，中间经历了哪些步骤，每步耗时多少。</p>
<h3 id="traceid-机制">TraceId 机制</h3>
<p>每个请求分配一个全局唯一的 TraceId，贯穿整个调用链。后续所有日志、指标、告警都带上这个 TraceId，方便关联查询。</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-java">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="nd">@Component</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nd">@Order</span><span class="p">(</span><span class="o">-</span><span class="n">100</span><span class="p">)</span><span class="w"> </span><span class="c1">// 最先执行</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">TraceHandler</span><span class="w"> </span><span class="kd">implements</span><span class="w"> </span><span class="n">PipelineHandler</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">TRACE_ID</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;X-Trace-Id&#34;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Override</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">before</span><span class="p">(</span><span class="n">SqlApiConfig</span><span class="w"> </span><span class="n">config</span><span class="p">,</span><span class="w"> </span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Object</span><span class="o">&gt;</span><span class="w"> </span><span class="n">params</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                        </span><span class="n">PipelineContext</span><span class="w"> </span><span class="n">context</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">// 优先用调用方传来的 TraceId（链路透传）</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">String</span><span class="w"> </span><span class="n">traceId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">RequestContext</span><span class="p">.</span><span class="na">getHeader</span><span class="p">(</span><span class="n">TRACE_ID</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">traceId</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">traceId</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">generateTraceId</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">context</span><span class="p">.</span><span class="na">setTraceId</span><span class="p">(</span><span class="n">traceId</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">// 记录请求开始时间</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">context</span><span class="p">.</span><span class="na">setStartTime</span><span class="p">(</span><span class="n">System</span><span class="p">.</span><span class="na">currentTimeMillis</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">// TraceId 放入 MDC，后续日志自动带上</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">MDC</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="s">&#34;traceId&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">traceId</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">MDC</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="s">&#34;apiId&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="na">getApiId</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">MDC</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="s">&#34;apiPath&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="na">getApiPath</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Override</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">after</span><span class="p">(</span><span class="n">SqlApiConfig</span><span class="w"> </span><span class="n">config</span><span class="p">,</span><span class="w"> </span><span class="n">Object</span><span class="w"> </span><span class="n">result</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                       </span><span class="n">PipelineContext</span><span class="w"> </span><span class="n">context</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="kt">long</span><span class="w"> </span><span class="n">elapsed</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">System</span><span class="p">.</span><span class="na">currentTimeMillis</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">context</span><span class="p">.</span><span class="na">getStartTime</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">log</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">&#34;API 调用完成 traceId={} api={} elapsed={}ms rows={}&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">context</span><span class="p">.</span><span class="na">getTraceId</span><span class="p">(),</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="na">getApiPath</span><span class="p">(),</span><span class="w"> </span><span class="n">elapsed</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">result</span><span class="w"> </span><span class="k">instanceof</span><span class="w"> </span><span class="n">Collection</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="p">((</span><span class="n">Collection</span><span class="o">&lt;?&gt;</span><span class="p">)</span><span class="w"> </span><span class="n">result</span><span class="p">).</span><span class="na">size</span><span class="p">()</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">MDC</span><span class="p">.</span><span class="na">clear</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">generateTraceId</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">UUID</span><span class="p">.</span><span class="na">randomUUID</span><span class="p">().</span><span class="na">toString</span><span class="p">().</span><span class="na">replace</span><span class="p">(</span><span class="s">&#34;-&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="p">).</span><span class="na">substring</span><span class="p">(</span><span class="n">0</span><span class="p">,</span><span class="w"> </span><span class="n">16</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div></div>
<h3 id="调用链记录">调用链记录</h3>
<p>每个步骤的耗时和结果都记录下来，形成完整的调用链：</p>]]></description></item></channel></rss>