tw4ld6 发表于 2024-10-10 17:08:30

Micrometer源码分析


    <h1 style="color: black; text-align: left; margin-bottom: 10px;">前言</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">好久没输出了,<span style="color: black;">近期</span>比较忙,<span style="color: black;">1星期</span>把一个季度的东西干完才有机会输出。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span>编码速度非常快(质量<span style="color: black;">亦</span>非常高),超出一个极限(超出其他所有职能<span style="color: black;">分部</span>的速度),<span style="color: black;">那样</span>不可能有人会占用你的时间。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">就像Integer.MAX_VALUE+1,超出极限了<span style="color: black;">便是</span>负数。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">本章基于springboot3.0.7分析micrometer1.10.7<span style="color: black;">关联</span>源码。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">本章<strong style="color: blue;">不会</strong><span style="color: black;">太多</span>关注:</p>prometheus客户端<span style="color: black;">怎样</span><span style="color: black;">运用</span>PromQLspringboot3放弃sleuth,转而<span style="color: black;">运用</span>micrometer-tracingpush模式收集metrics<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">本章<strong style="color: blue;">仅限于</strong>分析micrometer:</p>以micrometer接入prometheus的实现为抓手,<span style="color: black;">瞧瞧</span><span style="color: black;">怎样</span><span style="color: black;">创立</span>一套metrics模型pull模式收集metricsmicrometer做业务埋点,api<span style="color: black;">怎样</span><span style="color: black;">运用</span>更<span style="color: black;">恰当</span>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">从SpringBoot入手</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">其实<span style="color: black;">通常</span><span style="color: black;">状况</span>下,我都不太会看和Spring集成<span style="color: black;">关联</span>的东西,除了<span style="color: black;">有些</span>脱离Spring<span style="color: black;">没法</span>(或不会去<span style="color: black;">选取</span>)单独<span style="color: black;">运用</span>的框架,<span style="color: black;">例如</span>Seata。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">这儿</span>看一下Micrometer有<span style="color: black;">那些</span>核心的Bean,好找入口分析。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">通常</span><span style="color: black;">状况</span>下<span style="color: black;">不必</span>看Spring部分,无非是怎么去new一个对象,无论你用什么看起来<span style="color: black;">高挑</span>上的<span style="color: black;">办法</span>,本质<span style="color: black;">便是</span>这个。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">PrometheusMetricsExportAutoConfiguration</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Properties配置类PrometheusConfig(micrometer<span style="color: black;">供给</span>):</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/fe10493df6a342b7a51c5c7482a44949~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=1FU3%2FbILhvjMNcnHItJKm8U4tHM%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">PrometheusMeterRegistry</strong>(micrometer<span style="color: black;">供给</span>):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">核心类,MeterRegistry实现,<span style="color: black;">保留</span>所有Meter,micrometer与prometheus集成</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/00e9b86dce334d99b3ab6700d6c7a57d~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=qN6cw8OgTtWGCadDiQUtMubhRpM%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">CollectorRegistry(prometheus<span style="color: black;">供给</span>):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">prometheus收集metrics的api</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/494ff4d9790d42e6a7633dad5c0dcd17~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=9JtmB6EMQzmHtpoXHg4zNQZ81bk%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">DefaultExemplarSampler(prometheus<span style="color: black;">供给</span>):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">prometheus<span style="color: black;">针对</span>Exemplar的支持,metrics<span style="color: black;">相关</span>trace</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8193989d806b4b6ead3b1a86e5b13c2e~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=JuOKrMigzngaE%2B7A2r%2BgNiNwveo%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">PrometheusScrapeEndpoint(springboot<span style="color: black;">供给</span>):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">暴露/actuator/prometheus端点给prometheus拉metrics</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/1e2479755e5549beaac64d90c3438283~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=8MBlb39tXmrdoGmb2KV0v4uI6Pg%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">MetricsAutoConfiguration</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Clock(micrometer<span style="color: black;">供给</span>):时钟,用于获取时间,<span style="color: black;">便是</span>System.currentTimeMillis。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8db89eff74364e46b38ab904e31a8163~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=2Bpw3EAZh%2F9rlhXqCL41umPqCnw%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">MeterRegistryPostProcessor(springboot<span style="color: black;">供给</span>):有两个<span style="color: black;">功效</span></p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">1)<span style="color: black;">针对</span>MeterRegistry类型的Bean做<span style="color: black;">有些</span>全局配置处理,<span style="color: black;">例如</span>加入全局MeterFilter,做Meter过滤;</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">2)<span style="color: black;">针对</span>MeterBinder类型的Bean,主动触发bind<span style="color: black;">办法</span>注册meter到MeterRegistry;</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ccf448a10bd54d7791fb9a5fd64241f4~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=c4flXnYUx666uecvJUb4HZHI4DQ%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">PropertiesMeterFilter(springboot<span style="color: black;">供给</span>):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">基于management.metrics配置项的MeterFilter;</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/f7a539e0eb8b4aedb6371c60653bc44b~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=JaFS%2FhxBXT%2Bqk0v%2Bf3%2Fs72%2Bz5k0%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Mircometer模型</h1>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Meter</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Meter聚合了一组度量(Measurement),用Id<span style="color: black;">表率</span>这组度量。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">每次measure<span style="color: black;">办法</span>返回都是相同数量、相同<span style="color: black;">次序</span>的一组瞬时value。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/f7b166b0c61d4cf2838dfa8981787979~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=oCDAO0t3sCqUNtSrXrsu4GfMf3U%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Id</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Id<span style="color: black;">重点</span>由三部分<span style="color: black;">构成</span>:name-meter名,tags-meter标签集合,type-meter的类型。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Id#hashCode:<span style="color: black;">然则</span>Id的<span style="color: black;">独一</span>性,仅由name和tag决定。(equals代码不贴了,太长)</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/51cb8af29187492bb2f046dfd4bbfa87~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=CysESgMVlYUmdF1Jo4ECcia9OSw%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/3c3d2897c14841f5bfb333fdfa8a33b9~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=CQUIhraUyxKKH5xNCXacz7Xu2OU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Tag</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Tags由多个Tag<span style="color: black;">构成</span>;而Tag由一对kv<span style="color: black;">构成</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当kv相<span style="color: black;">同期</span>,Tag相同;当所有Tag相同,Tags相同。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/65e531a464b649c3bc1c927ed89dee31~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=uDzXzdO%2FJwpjPVz29j7gNaxJqew%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Tag#hasCode:</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8b8dbaab46fd4d5bba6be54b9da290ea~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=j%2BslFRiDk7BSz3BCPuDtz9cuFlk%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Measurement</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">度量<span style="color: black;">包括</span>两个属性:</p>DoubleSupplier:一个返回double的supplier函数;Statistic:枚举,<span style="color: black;">针对</span>一个度量的描述;<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/eca31127be944702a65a3e024ed781b9~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=CUzR4EmyP7mWhF%2FDiqAQ3CcVwtw%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8a8ba78d7bdd41fdb9c796b17430c2b6~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=L00mnyRbCWbcIgaee8NxxkoH4OA%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">转换Prometheus格式</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">例如</span>jvm内存<span style="color: black;">运用</span><span style="color: black;">状况</span>,暴露给prometheus的数据格式如下:</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/e81cab81c9894411aed550b702998753~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=%2Fn1ARBt5rbAqlZm7WKxGvQLtV1M%3D" style="width: 50%; margin-bottom: 20px;"></div>jvm_memory_used是Id.name,bytes是单位;{application="sb3-app",area="nonheap",id="Compressed Class Space",}是Tags;<span style="color: black;">这儿</span>一行是一个Measurement度量,这个Meter<span style="color: black;">仅有</span>一个度量;<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">例如</span>某个端点的http请求,暴露给prometheus的数据格式如下:</p>ini复制代码http_server_requests_seconds_count{application="sb3-app",error="none",exception="none",method="GET",outcome="SUCCESS",status="200",uri="/metric",} 2.0
    http_server_requests_seconds_sum{application="sb3-app",error="none",exception="none",method="GET",outcome="SUCCESS",status="200",uri="/metric",} 0.006369008
    http_server_requests_seconds_max{application="sb3-app",error="none",exception="none",method="GET",outcome="SUCCESS",status="200",uri="/metric",} 0.004348599
    http_server_requests是Id.name,seconds是单位;{...uri="/metric",}是Tags;一个端点的http请求(一个Id)有3个Measurement度量,count是请求总数,sum是请求总时长,max是请求最大时长;<h1 style="color: black; text-align: left; margin-bottom: 10px;">MeterRegistry</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">一个抽象类,内存中存储Meter。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/bd5fad778044419781e03c929d92ed66~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=bGqBTSl9TNqU0V2hNaK0MDx5KTo%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">MeterRegistry<span style="color: black;">供给</span><span style="color: black;">有些</span>方便<span style="color: black;">运用</span>的注册Meter<span style="color: black;">办法</span>,<span style="color: black;">例如</span>注册一个Counter类型的meter。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8182ba9ae05c4137839ba82a0f66a3f7~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=IDnsx6gUyBjF0apIwoJx%2FvuzLlg%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">为此,子类需要实现<span style="color: black;">有些</span>构建Meter的<span style="color: black;">办法</span>,<span style="color: black;">例如</span>构建一个Counter。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/6b13c1f4c32a493391a46d59278b68f9~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=s5aXczXA%2BSg9BO9tvgzeJUsCxpg%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">MeterRegistry<span style="color: black;">供给</span>注册Meter的骨架<span style="color: black;">办法</span>getOrCreateMeter流程如下:</p>MeterFilter#accept过滤Meter.IdMeterFilter#configure<span style="color: black;">按照</span>Meter.Id二次处理DistributionStatisticConfigbuilder#apply执行用户回调构建Meter同义meter注册meter注册Listener<span style="color: black;">通告</span>注册mter<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/d74b83ed8490492ea39361b64a70ec3d~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=QKMrhIv1XgUsA4DDaTxRerwzLok%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">MeterBinder</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">除了直接调用MeterRegistry<span style="color: black;">能够</span>注册Meter之外。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">部分Metrics会实现MeterBinder接口,将Meter注册到MeterRegistry。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/19aba13c03954b58b011c12b379879c6~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=URGtcasabHT5Vn%2F6Lx5LQqaP%2BSQ%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在SpringBoot中,MeterRegistryPostProcessor会来触发所有MeterBinder的注册动作。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">几种Meter</h1>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Counter</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Counter只会返回一个double类型的度量,是一个只增不减的计数器。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/65bc500d10ca46ef99625ec4f64ea34c~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=BuXjtMvkRbl02273crQJjYAshsI%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">micrometer<span style="color: black;">针对</span>Prometheus的实现是<strong style="color: blue;">PrometheusCounter</strong>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">PrometheusCounter除了一个DoubleAddr计数器之外,还有一个<strong style="color: blue;">Exemplar</strong>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ffea56564bda45978c14f3580167887f~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=LbJAIrsQL3IiK8bC7vrTSBycpgw%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">每次更新计数器,还会更新Exemplar。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/5d771b4c981748068a392e84ed2990f0~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=QEJtzco5c9YBgMz1fp0XqMw9mWE%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这个<strong style="color: blue;">Exemplar的<span style="color: black;">功效</span><span style="color: black;">便是</span><span style="color: black;">相关</span>metric和trace</strong>,见OpenMetrics。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在客户端侧,<span style="color: black;">倘若</span>加入tracing<span style="color: black;">关联</span>组件,就能<span style="color: black;">运用</span>Exemplar,见SpringBoot+micrometer-tracing。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在prometheus侧,需要开启exemplar-storage特性,见Prometheus+exemplars-storage。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在grafana侧,<span style="color: black;">能够</span><span style="color: black;">经过</span>metric拿到Exemplar,而Exemplar中<span style="color: black;">包括</span>trace_id,方便定位问题。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/a20608ec04af4cba9b11b7e465ac33e5~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=8vZjwqTIP%2FjqXnWh7E4MwhBqYgI%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">需要<span style="color: black;">重视</span>的是,<span style="color: black;">日前</span>Exemplar仅支持prometheus,<span style="color: black;">因此</span>这两个模型都是prometheus客户端<span style="color: black;">供给</span>的。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/5bbd6bdab4ac445d8069b3d51aabb7d4~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=oUoBkT%2B8oDfmoLhYzg1x7Pq20lc%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">PrometheusCounter#updateExemplar:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">每次increment都会调用CounterExemplarSampler采集一个Exemplar,替换Counter中的Exemplar。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">因此</span>promethues配置scrape_interval=15s抓取一次,<span style="color: black;">那样</span>只会抓到<span style="color: black;">近期</span>一次Counter记录到的trace。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/3a71925713434aebaf4d1a048fac3322~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=BxUvT8m6JepNQReEYeV9N%2BVMECU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">DefaultExemplarSampler#doSample:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当满足下面两个<span style="color: black;">要求</span>的<span style="color: black;">状况</span>下,才会采集新的Exemplar,Exemplar<span style="color: black;">包括</span>当前线程中的trace信息</p><span style="color: black;">倘若</span>trace要采集(isSampled=true)距离上次采样时间超过一<span style="color: black;">按时</span>间(minRetentionIntervalMs=7109ms)<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">不满足<span style="color: black;">以上</span><span style="color: black;">要求</span>,PrometheusCounter中的Exemplar不会更新。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/9f4461803934442a953d09f868823f09~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=3VLYojTONX%2FPCSx9VxpaotBV86g%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Gauge</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">Gauge</strong>只会返回一个double类型的度量,可增可减。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/30194b84a4c5492eaa9baef4109b34f1~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=LX3Ol%2F82uKdLtoxi6o1xWaN4lEU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">micrometer<span style="color: black;">针对</span>Prometheus<span style="color: black;">无</span>特殊实现,<span style="color: black;">运用</span><strong style="color: blue;">DefaultGauge</strong>。</p>value:一个Function函数,获取double类型度量,不像Counter<span style="color: black;">通常</span>自己就能<span style="color: black;">守护</span>一个计数器;ref:<span style="color: black;">做为</span>Function入参对象,一个弱引用,<span style="color: black;">通常</span><span style="color: black;">来讲</span>ref引用的对象是一个长生命周期对象;<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">重视</span>Gauge<span style="color: black;">没法</span><span style="color: black;">供给</span>Exemplar,即<span style="color: black;">没法</span>关联trace。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/9d0fd84bdd2642469b6eafcd4e91c62a~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=RPAOLJ2FIov5ClvItd4VA4o3sIE%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Timer</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Timer用于跟踪<span style="color: black;">海量</span><span style="color: black;">短期</span>运行事件的计时器,<span style="color: black;">通常</span>这些事件在一分钟以内,<span style="color: black;">例如</span>http请求。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/1846893ffac64cb7857ab0aea5071389~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=nfn%2BT15wmk3zhZURzUuCKnGp4TU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Timer有三个度量:count-总数、totalTime-总耗时、max-最长耗时。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/e709a45bc5b14827978ccabaf213a700~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=Eb5ZL%2BYpGg2%2F9p%2FCIkrOflSYOhs%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Timer用于统计事件时长,埋点方式有多种。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">例如</span>,在事件<span style="color: black;">起始</span>需要Timer#start拿到一个Timer.Sample。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/cf2935d0df3c4b6282beef7ce81c23ae~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=Wd8LuZf2bGBHXQCrhy1deMkLr20%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在事件结束需要Timer.Sample#stop,调用Timer实例的record<span style="color: black;">办法</span>记录事件耗时。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/dfa59fd541a4467a84a68550c83762b7~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=d7dOCIyndgyL6WysIntcj%2F3QW8g%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">又<span style="color: black;">例如</span>,Timer#record直接记录耗时,需要子类实现。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/f1d05b6404b04bfd8308977b6facf187~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=7ipAf24Z6KocGVuCq2Wabilw%2FkM%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">AbstractTimer实现了record<span style="color: black;">规律</span>,忽略Histogram和IntervalEstimator,子类需要实现recordNonNegative。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/afd703c9e9a94598a0167215e3da94bc~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=GBgJagmaY7gn58izB8Ii5uIpIq0%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">PrometheusTimer#recordNonNegative:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">三个度量计算,重点关注一下TimeWindowMax。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">重视</span>,单纯PrometheusTimer并不支持Exemplar,Exemplar依<span style="color: black;">附着</span>Histogram<span style="color: black;">运用</span>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/28de6862179e472cbefc1588a5e7cac9~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=8mBBTpPhctV2ccDle0gSv%2BNNib0%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/819cf42523cf4dfea1544fd8115d7c43~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=tvdV1318S3ik3QxKabPvTme1RH0%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowMax属性如下,<span style="color: black;">重点</span>是<span style="color: black;">经过</span>一个环形数组,<span style="color: black;">每一个</span>数组元素存储1分钟内的最大时长。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/f4aa0d56dbde431bbbb04d88e84e3fb8~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=0a%2BSr087g48tCqQb5y6sLZ7OX64%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowMax的滚动间隔时长和环形数组容量,都取自于DistributionStatisticConfig。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/df6d5a59fa394a96a873c3c4fc47ab7e~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=i2ES8IGddu8KZK%2FVy8dJ%2BNKjbro%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在记录最值的时候,先滚动,<span style="color: black;">而后</span>用采样值更新所有桶中的最值。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/577481ad1d654a00bcdefed54cfd9692~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=1nmA896qEvyAK11jlzuv9lEJiX0%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">滚动<span style="color: black;">办法</span>如下,<span style="color: black;">初期</span>版本(1.6.11之前)有bug(issue=2647),可能<span style="color: black;">没法</span>采集到正确的最值。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowMax#rotate:超过一分钟未滚动,才进行滚动。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/5f9eff29eb0143b892dfbd7b30753373~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=rFsNo43%2Fv55jwO%2B7H3kaYDkKT58%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowMax#rotate:第<span style="color: black;">一起</span>滚动<span style="color: black;">规律</span></p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这个是issue=2647新增的<span style="color: black;">规律</span>,<span style="color: black;">倘若</span>超过3分钟未滚动,清空所有桶,并更新上次滚动时间。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/88677af195224b50a4d7f98e50a35643~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=JCjcdSEDl2BIrM%2Fuj4FDQjYE%2BqA%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowMax#rotate:第二块滚动<span style="color: black;">规律</span></p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">初期</span>版本<span style="color: black;">仅有</span>这<span style="color: black;">一起</span>滚动<span style="color: black;">规律</span>,问题在于timer<span style="color: black;">长时间</span>未被调用,lastRotateTimestampMillis上次滚动时间<span style="color: black;">没法</span>正确更新。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8806993ea3914137a92f463373187e65~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=z67ZujlJmKi2G7J8oDXZ%2BOZoZWg%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowMax#poll:获取最值的<span style="color: black;">办法</span>,先尝试滚动,<span style="color: black;">而后</span>获取当前桶中的最值。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">注:滚动和获取最值做了同步synchronized。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/f5ad14fd582b40ec83bc120b2a03aef4~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=NZkEIxqA1e3dCIGXJxKiCcHjVao%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">以官方测试用例为例,<span style="color: black;">规律</span>如下。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">需要理解的是,TimeWindowMax最值并不是1分钟内的最值,是3分钟内的最值。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/39341ffb69ea4790ba7cefc85aea9397~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=pI8PhDjFPNyWgFOKq6oeprj1%2Bb4%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">官方<span style="color: black;">叫作</span>为:基于可配置环形缓冲区的分布衰减最大值。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/a2d0127fce174cb89f079a929fecfd8a~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=soHDwyA%2FcBlM54jvPJExSoCR71c%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">LongTaskTimer</h1>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/1b81c2674d2b4e248eb5771eb32a29c4~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=yFF8xMLGcIN7WPKQ2xRQCABFkQc%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">LongTaskTimer和Timer完全<span style="color: black;">区别</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">LongTaskTimer用于度量<strong style="color: blue;">正在执行的任务数量</strong>和<strong style="color: blue;">这些任务<span style="color: black;">已然</span>执行的时长</strong>,重点<span style="color: black;">便是</span>in-flight。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">LongTaskTimer<span style="color: black;">亦</span>支持Histogram。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/3086a33bb42448b8ae97c8d7e723dc6e~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=4TKqlbJmxLufGsTVLj5Oydg6Uco%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">举个例子:</p>typescript复制代码@RestController
    public class OrderMetrics implements MeterBinder {

    private LongTaskTimer longTaskTimer;

    @Override
    public void bindTo(MeterRegistry meterRegistry) {
    longTaskTimer = LongTaskTimer.builder("order.long.task")
    .publishPercentileHistogram(true)
    .publishPercentiles(0.5, 0.95)
    .minimumExpectedValue(Duration.ofSeconds(10))
    .maximumExpectedValue(Duration.ofSeconds(20))
    .register(meterRegistry);
    }

    @GetMapping("/order/longtask")
    public String longtask() {
    EXECUTOR.submit(() -&gt; {
    LongTaskTimer.Sample sample = longTaskTimer.start();
    int time = RANDOM.nextInt(10, 20);
    try {
    TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
    sample.stop();
    return;
    }
    sample.stop();
    });
    return "success";
    }
    }<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">虽然历史曾经有过LongTaskTimer采集数据(从histogram数据<span style="color: black;">能够</span>看到)。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">然则</span>active_count、duration_sum、max都为0,<span style="color: black;">由于</span>LongTaskTimer的度量仅针对in-flight数据,当所有任务执行完毕,这些度量都会变成0。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/5c552836e4e04181a6717afc00f60563~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=PfP2e7nr%2BYopjtQJAA%2BaBH%2FqdRU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Prometheus接入的实现是<strong style="color: blue;">CumulativeHistogramLongTaskTimer</strong>,<span style="color: black;">仅有</span>Histogram<span style="color: black;">关联</span>的takeSnapshot<span style="color: black;">办法</span>有点特殊,<span style="color: black;">规律</span>都走<strong style="color: blue;">DefaultLongTaskTimer</strong>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Histogram部分放在后面统一看,<span style="color: black;">这儿</span>Histogram的特点和其他Prometheus接入的实现类似,桶计数要<span style="color: black;">运用</span>累积数量。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ffa87acd61024ff58f9539b0f82fbbd4~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=ROu8D1nRuxT3aVO0f40wyN%2F6pBM%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">DefaultLongTaskTimer#start:创建Sample实例,放入activeTasks集合存储。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/12f6f8ac05594342964e1ca3c79d39fb~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=tOcPZZefyhEtYF5QTp1p44WetAM%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">DefaultLongTaskTimer.SampleImpl#stop:从activeTasks集合移除Sample。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/c4779a01d6114027a3bd03474b71b983~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=FwdnuFeiZoLtyitEAh3fyuwAfQw%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">获取度量,duration统计所有正在执行任务的累计时长,activeTasks统计正在执行的任务数量。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/276135dcd9924023b564ea165bbdd32a~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=I%2FNnDYtugK1VnpXFe29L2pvw%2B4k%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">max统计此时执行最长的时长。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/b8d054905c2c43d383bd84b95b032a55~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=Y2jNLopV12UdU8EWZuksTMIExsY%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">DistributionSummary</h1>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/204ac9dfeefa4c428280b45fd3bd2652~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=Ad2vo4TAHYd4BBu9kMIXb5Llb70%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在micrometer侧,DistributionSummary和Timer几乎<span style="color: black;">无</span>区别,仅仅是单位上的区别。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Timer是时间,而DistributionSummary是任意值。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">A distribution summary tracks the distribution of events. It is similar to a timer structurally, but records values that do not represent a unit of time. For example, you could use a distribution summary to measure the payload sizes of requests hitting a server.</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Histogram</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Histogram不属于Meter,依<span style="color: black;">附着</span>Timer和DistributionSummary。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">案例</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">默认<span style="color: black;">状况</span>下,普通的Timer不会开启Histogram,案例<span style="color: black;">经过</span>Timer统计订单详情的P50和P95。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">注:<span style="color: black;">运用</span>micrometer<span style="color: black;">供给</span>的TimedAspect加Timed注解<span style="color: black;">亦</span><span style="color: black;">能够</span>,api更灵活。</p>typescript复制代码@RestController
    public class OrderMetrics implements MeterBinder {
    private Timer orderDetailTimer;
    @Override
    public void bindTo(MeterRegistry meterRegistry) {
    orderDetailTimer = Timer.builder("order.detail")
    .publishPercentileHistogram(true)
    .publishPercentiles(0.5, 0.95)
    // 默认1ms-30s
    .minimumExpectedValue(Duration.ofMillis(1))
    .maximumExpectedValue(Duration.ofSeconds(5))
    .register(meterRegistry);
    }
    public void orderDetailRecord(long time, TimeUnit unit) {
    orderDetailTimer.record(time, unit);
    }

    @GetMapping("/order/detail")
    public String detail() {
    log.info("订单详情<span style="color: black;">起始</span>"); // for trace
    int time = RANDOM.nextInt(1, 2000);
    this.orderDetailRecord(time, TimeUnit.MILLISECONDS);
    log.info("订单详情结束"); // for trace
    return "success";
    }
    }<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">暴露给prometheus的数据格式如下:</p>order_detail_seconds_bucket,<span style="color: black;">表率</span>1ms到5s<span style="color: black;">每一个</span>桶中的请求数量,这个数量是依次累计的,第10个桶<span style="color: black;">包括</span>前1-9个桶中所有请求数量的总和,支持Exemplar;order_detail_seconds{quantile},<span style="color: black;">表率</span>P50和P95对应的值;<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/a91fcee9a5484b80acd5b201e1e11aa7~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=hvBYT8gnXEgb6hAdwssDC1a4U%2F0%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">HistogramSnapshot</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">针对</span>部分Meter,<span style="color: black;">例如</span>Timer和Summary,支持Histogram,会实现takeSnapshot<span style="color: black;">办法</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">takeSnapshot返回一个Histogram的快照,不属于Measurement度量。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/0d9130d64ed14d13b43c94be24cee264~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=b8RK5B7a96OWKfKodjSwnD0fSvM%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">HistogramSnapshot</strong>除了传统的count、total、max这种度量之外,还有两个数组:</p><strong style="color: blue;">percentileValues</strong>:分位数对应值,<span style="color: black;">例如</span>案例P50对应值在percentileValues的位置,P95对应值在percentileValues的位置,即案例order_detail_seconds{quantile}<strong style="color: blue;">histogramCounts</strong>:<span style="color: black;">每一个</span>桶中的数量,即案例order_detail_seconds_bucket<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/2101ff3a852f42578616b7917dcc6b75~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=D7jPgHMcCEp5Ri4WkSuaXY7wbIQ%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">PrometheusTimer#takeSnapshot</strong>:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">针对</span>PrometheusTimer<span style="color: black;">来讲</span>,<strong style="color: blue;">桶计数需要走自己的histogram来获取</strong>,而<strong style="color: blue;">分位数值走父类的histogram获取</strong>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">至于<span style="color: black;">为何</span>需要这么<span style="color: black;">繁杂</span>分两个Histogram来获取数据,是<span style="color: black;">由于</span>Prometheus<span style="color: black;">针对</span>桶计数需要完整的数据,而不是滚动的Histogram。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">言外之意,桶计数需要从进程<span style="color: black;">起步</span>到进程停止,完整生命周期内累计的数据;而分位数值是滚动数据。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/5bde9c90ce5f44e6a4c93ffb5f1a4d81~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=GmJgSWcyfpYAhzg2b02YlrlxoMI%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">父类AbstractTimer的Histogram走<strong style="color: blue;">TimeWindowPercentileHistogram</strong>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/d0c21bc7dfd9438d8f57645788fb1b94~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=M8tA1%2BkTBXiWUZp0Hspa2B%2BVftg%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">自己的Histogram走<strong style="color: blue;">PrometheusHistogram</strong>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/bd13831e11d24d2ab006c07f84c7fae4~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=xh7PI1jyLakpv5Cy39rnk1aw%2BiY%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">PrometheusHistogram</strong>底层是micrometer的<strong style="color: blue;">TimeWindowFixedBoundaryHistogram</strong>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/52b21673ae9d4e21baa7989e74671487~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=RCIg1eeqP36hv1crIB2f1Uc58lw%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">全部</span>Histogram<span style="color: black;">触及</span>到的继承关系如下,一点一点来看吧。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/871d9b91f4514387aad908a897e41653~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=covUHzlR8QtHzhqHVxBqyukGW8M%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">Histogram</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Histogram<span style="color: black;">自己</span>具备takeSnapshot能力,<span style="color: black;">因此</span><span style="color: black;">通常</span>Timer和Summary都会委派底层Histogram生成快照。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">除此以外,record<span style="color: black;">办法</span>记录埋点值。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ee9f03e843964faba763ad59a35b0c75~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=5evImrRerFKwkxqynOqGoKPr5sI%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">AbstractTimeWindowHistogram</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">和TimeWindowMax类似,<span style="color: black;">经过</span>一个环形数组存储埋点值。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">只<span style="color: black;">不外</span>数组元素是泛型T,即AbstractTimeWindowHistogram<span style="color: black;">能够</span>理解为<strong style="color: blue;">存储了x个时间窗口内的T</strong>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">相较于TimeWindowMax多了<span style="color: black;">有些</span>Histogram专属的属性,泛型U是一个<strong style="color: blue;">累积Histogram</strong>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这个累计Histogram大概是啥意思,后面再看。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8c74c279af084b3ea1e0abd2715fca9f~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=U%2BoX9%2Bzu2WIGMR%2F0dFQ0ebhV0IU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">记录采集值和TimeWindowMax<span style="color: black;">规律</span>类似,recordLong记录bucket需要子类实现。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/74441a1bfddd481e9ac405d792a942e6~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=zDpr9ySAkMInhHpKvCkKS9HGCTQ%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">AbstractTimeWindowHistogram#takeSnapshot:获取HistogramSnapshot的骨架<span style="color: black;">办法</span>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ac64bd45f1384a97b5f2ccc5397a9122~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=huM45jHQSe7KDP4CeW3gzzN9jVA%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">子类需要实现三个抽象<span style="color: black;">办法</span>用于获取HistogramSnapshot:</p>accumulate:累计Histogram,后面再看;valueAtPercentile:获取分位数对应的值,<span style="color: black;">例如</span>P95对应2秒;countAtValue:获取某个桶中的采样总数,<span style="color: black;">例如</span>传入1秒,得到0.5-1秒总共有5个请求;<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/733a7563f9e34ea08c8e9aa48fcfe9ce~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=xBsHveS16RGXstTxaK6hfkwR3Ps%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">TimeWindowPercentileHistogram</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在PrometheusTimer中,仅用于获取分位数值,<span style="color: black;">例如</span>P95=2秒。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">DoubleRecorder</strong>即泛型T,是底层环形数组中的元素,用于记录<span style="color: black;">每一个</span>时间窗口内的采样值;</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">DoubleHistogram</strong>即泛型U,是底层定义的累计Histogram,当takeSnapshot会将当前窗口的采样值T累计到U;</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这两个类都不是micrometer自己的,是HdrHistogram<span style="color: black;">供给</span>的,<span style="color: black;">无</span>其他任何依赖,当jdk用<span style="color: black;">就可</span>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ed34f599485848c8bde8633bbb5dffa0~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=JbvF14ScA6bnCh11lt5zVHR0%2FTw%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在记录采样值时,调用HdrHistogram记录。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p26-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/f601beb316564de1bfd6bd6005e5ce25~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=eoDXmS7PYiz8K%2BNlOniEp4aRsGk%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在创建snapshot时,将当前窗口的DoubleRecorder灌入DoubleHistogram。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/edf912ad688641ac911675821b052649~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=LDBndB4%2Be%2FJ0zP8nTH9%2FAxEAdqQ%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">由于</span>Prometheus只用<span style="color: black;">这儿</span>的分位数值,<span style="color: black;">因此</span>只用看valueAtPercentile,调用DoubleHistogram#getValueAtPercentile这个api<span style="color: black;">就可</span>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/54463ecadfda4a7e8adffe55cf8ac38d~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=stZzF3CwxZcHUeEp6OXSZcbLXgQ%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">因此</span><span style="color: black;">根据</span>这个<span style="color: black;">规律</span>,<span style="color: black;">是不是</span>能采集到分位数值其实和采集频率<span style="color: black;">相关</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span>在一个时间窗口(1分钟)内不来采集,<span style="color: black;">那样</span>就不会调用累积Histogram<span style="color: black;">办法</span>,<span style="color: black;">那样</span>这个时间窗口的数据就会随着底层环形数组滚动而丢失。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">另外</span>,HdrHistogram统计Pxx总归是有误差的,不会把所有采样值都放到内存中。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/7786e03506ad481fb20bbcebd246f79f~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=4Ny0Lkc7moZvzc4snuUTX01Kq30%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">能够</span><span style="color: black;">经过</span><span style="color: black;">调节</span>DistributionStatisticConfig#<strong style="color: blue;">percentilePrecision</strong>来<span style="color: black;">提高</span>精度,<span style="color: black;">然则</span>耗费内存会更多。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">默认精度是1,<span style="color: black;">详细</span><span style="color: black;">规律</span>我<span style="color: black;">亦</span>不深究了。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/fed7af6ea9454b4fbdd032c6f12c7938~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=u0MiQ88SrV%2FY0fM%2FtXKHOuxksX0%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">TimeWindowFixedBoundaryHistogram</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在Prometheus场景下,TimeWindowFixedBoundaryHistogram仅用于<strong style="color: blue;">统计<span style="color: black;">每一个</span>桶中的采样数量</strong>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">特点是PrometheusHistogram在构造父类时,写死了两个参数:</p><strong style="color: blue;">expiry</strong>:1825天,<span style="color: black;">寓意</span>着底层的环形数组永远不滚动;<strong style="color: blue;">bufferLength</strong>:1,<span style="color: black;">寓意</span>着底层的环形数组<span style="color: black;">仅有</span>一个元素;<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/60ea9eb27ca648bb9349b763c2380ae5~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=FVA7R8Kr0ccUcVNfadXZQiL2Zj4%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">从TimeWindowFixedBoundaryHistogram的泛型参数来看:</p>T:底层环形数组元素,是内部类TimeWindowFixedBoundaryHistogram.FixedBoundaryHistogram;U:Void,<span style="color: black;">因此</span>不支持累计Histogram;<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/2b7ca9768cd446e8a7eb073c2ca4e6e1~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=4scJKKhYFrF3H3YJS4guvqzhrdo%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">从成员变量来看,<span style="color: black;">重点</span>是有一组buckets。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">例如</span>案例会划分为57个bucket,<span style="color: black;">每一个</span>bucket的元素是一个时间值,从1毫秒到5秒。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/89866ce9211a4b009cb83445b799b85d~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=aPHorNwBp3NWJHbPxY%2Fa3WBiUTI%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowFixedBoundaryHistogram记录采样值:</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/0cfb6a2e5fb9435695751bb1fe9ce93e~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=JzvjwHQ7KoxZRBrb2%2BBTsd2Ckpk%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TimeWindowFixedBoundaryHistogram获取桶内的采样数量,走cumulativeBucketCounts=true:</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/655f2befa0e1492f8474776aefa5ee6c~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=bVuna66pFrwsBxdDSmFkNZLeCEU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">FixedBoundaryHistogram</strong><span style="color: black;">守护</span>了一个和bucket长度一致的原子长整型数组values。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/a9b45435d55c42508a1b5a1aaa07a0fd~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=dcooUomFdBtaV9cr8%2F3hvLDb8lY%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">FixedBoundaryHistogram#record<span style="color: black;">办法</span>:</p>从bucket数组中,找到最大的<span style="color: black;">少于</span>等于采样值的bucket下标(算法题二分<span style="color: black;">查询</span>变形);values对应下标元素自增,即统计采样值到某个bucket中;<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/6139f5eda80e41f79a445a48f51d04b6~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=K60vG69bVE%2BUp%2B7Q5MTpUlc4ras%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">FixedBoundaryHistogram#countAtValueCumulative:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">获取桶内数量的时候,Prometheus需要把该桶之前的数据累加。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">即0-1秒有1个请求,1-2秒有1个请求,入参2秒获取的数据<span style="color: black;">实质</span>是2个,和案例中一致。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/45b86593ed4146c0ab885b6788edda2f~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=J3VvGdysGtVNRndf7PK38K6bHhk%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">PrometheusHistogram</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">PrometheusHistogram<span style="color: black;">守护</span>了一组和父类<span style="color: black;">同样</span>的buckets数组,一组死值。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">特点在于PrometheusHistogram支持记录<span style="color: black;">每一个</span>bucket对应的Exemplar。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/2b5f6b663f7d441aa8606a3a9496f5fe~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=vO%2B5TW7w7qg7fRLmyF90BhKNAF4%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">每次采集数据,找到采样值所属bucket(二分),并记录Exemplar,<span style="color: black;">规律</span>和PrometheusCounter类似。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/4ff4c2c1c51640458ad0e74d63341ea8~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=PT04%2Bm7c9fxTKivxUIl4grrgZjo%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">关于业务埋点</h1>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">怎样</span>定义业务Meter</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">1、固定tag的Meter</strong></p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">其实大部分Meter的tag都是可穷举可预知的。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">为了减少内存和cpu的浪费,不必在运行时去注册Meter到MeterRegistry,虽然MeterRegistry#getOrCreateMeter支持判断同一个Meter仅注册一次。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">例如</span>:Jvm内存分堆和非堆,<span style="color: black;">那样</span><span style="color: black;">运用</span>MeterBinder在ioc容器<span style="color: black;">起步</span><span style="color: black;">周期</span>就<span style="color: black;">能够</span>注册Meter了。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/f357bad34c5b48fb9e6882ee4ddd63ca~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=MciK5PCXi27Np4cL2bkGx52ATEI%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">例如</span>我要统计<span style="color: black;">区别</span>订单的下单数量的走势,<span style="color: black;">按照</span>订单类型枚举OrderType直接在ioc容器<span style="color: black;">起步</span><span style="color: black;">周期</span>注册Counter<span style="color: black;">就可</span>,运行时只需要调用increment api,而不需要再去走getOrCreateMeter。</p>typescript复制代码@Component
    public class OrderMetrics implements MeterBinder {

    private static final Map&lt;OrderType, Counter&gt; ORDER_COUNT = new HashMap&lt;&gt;();

    @Override
    public void bindTo(MeterRegistry meterRegistry) {
    for (OrderType orderType : OrderType.values()) {
    Counter counter = meterRegistry.counter("order.count", "order.type", orderType.getCode());
    ORDER_COUNT.put(orderType, counter);
    }
    }

    public void orderIncr(OrderType orderType) {
    ORDER_COUNT.get(orderType).increment();
    }
    }<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">2、非固定tag的Meter</strong></p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">有些<span style="color: black;">状况</span>,tag纬度<span style="color: black;">非常多</span>,且tag不太能穷举,只能在运行<span style="color: black;">周期</span>注册Meter到MeterRegistry</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">如DefaultMeterObservationHandler(springboot2不是这个),统计http请求耗时,默认tag纬度很多(uri+status+exception+method+outcome)不可能<span style="color: black;">起步</span><span style="color: black;">周期</span>穷举。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ca88b1d97bd14033a657ebb00f209c1c~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=98rVNrsUmF4sdYFPkfInMNb6FtI%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">举个不<span style="color: black;">必定</span>很恰当的例子,订单取消订单<span style="color: black;">原由</span>类型,<span style="color: black;">能够</span>无限扩充,仅用于放在看板上分析,不需要每次新增<span style="color: black;">原由</span>类型,就修改后端服务。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/88cec36b59fa4a598f695517994270ab~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=ynNwOhaVBjzYpqPEmzwI2Jk1LjQ%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当然了,<span style="color: black;">运用</span>Prometheus采集metrics<span style="color: black;">咱们</span>应该避免<span style="color: black;">出现</span>高基数问题。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">开箱即用的Meter</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">SpringBoot<span style="color: black;">供给</span>了<span style="color: black;">非常多</span>开箱即用的Meter,举几个<span style="color: black;">初期</span>版本不<span style="color: black;">必定</span>有的例子。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">ThreadPoolTaskExecutor/ThreadPoolTaskScheduler</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这两个类都是Spring<span style="color: black;">供给</span>的,包装了普通的jdk的线程池,<span style="color: black;">供给</span>了<span style="color: black;">非常多</span>在Spring里的<span style="color: black;">加强</span>功能。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">针对</span>这两类bean,SpringBoot会暴露线程池的<span style="color: black;">关联</span>meter,对业务<span style="color: black;">亦</span>比较有<span style="color: black;">帮忙</span>。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/bbd901d09815431b837b3c37c16372fb~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=xkyiIlaN5txU2O8kK2L8HUZoRa8%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">除了executor_completed是Counter之外,其他都是Guage。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ce161fd619c54c889199c391d469807c~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=aqBSW7OvW4SZvo1y61T%2Fgsietss%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">DefaultMeterObservationHandler</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在springboot<span style="color: black;">初期</span>版本,<span style="color: black;">运用</span>自己写的WebMvcMetricsFilter来记录http.server.requests指标。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在新版本中,<span style="color: black;">运用</span>micrometer<span style="color: black;">供给</span>了DefaultMeterObservationHandler。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/3002ba29410b4802a391bcf534f9ecbb~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=iLvLoO1V3f3pjgcIMsN4DJ0jgcU%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">区别在于DefaultMeterObservationHandler不仅采集普通Timer的,还采集了LongTaskTimer,即<span style="color: black;">能够</span>看到正在处理(in-flight)的请求metrics。</p>
    <div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/42cbeb40214b480a8937ea721d61dbbb~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1728815862&amp;x-signature=jdGoNlC2FW2WzrOq7gDZzwcCMYg%3D" style="width: 50%; margin-bottom: 20px;"></div>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">总结</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Mircometer的核心模型就两个:</p>Meter:<span style="color: black;">包括</span>一组瞬时Measurement度量,用一个<span style="color: black;">独一</span>标识Id(name+Tags)来标识这组度量;MeterRegistry:存储Meter的<span style="color: black;">地区</span>,getOrCreateMeter<span style="color: black;">办法</span><span style="color: black;">掌控</span>同一个Id的Meter只注册一个Meter实例;<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">注册Meter<span style="color: black;">通常</span>有两种方式:</p>实现MeterBinder接口,由ioc容器回调bindTo<span style="color: black;">办法</span>,注册Meter;运行时构造Meter实例,<span style="color: black;">经过</span>MeterRegistry#register API注册Meter;<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">五种Meter模型:</p>Counter:只<span style="color: black;">包括</span>一个只增不减的double类型度量,支持Exemplar;Gauge:只<span style="color: black;">包括</span>一个可增可减的double类型度量,不支持Exemplar;Timer:用于跟踪<span style="color: black;">海量</span><span style="color: black;">短期</span>运行事件的计时器,<span style="color: black;">包括</span>三个度量count总数、totalTime总耗时、max最长耗时。其中max默认统计的是3分钟内的最大值,基于环形数组实现,数组容量bufferLength=3,<span style="color: black;">每一个</span>元素<span style="color: black;">表率</span>时长expiry=1分钟。支持Histogram,依托Histogram支持Exemplar;LongTaskTimer:用于度量正在执行(in-flight)的任务,<span style="color: black;">包括</span>active_count正在执行任务数、duration正在执行任务总时长、max正在执行任务的最大时长,支持Histogram,依托Histogram支持Exemplar;DistributionSummary:和Timer的实现几乎一致,区别在于DistributionSummary用于统计非时间的任意值,支持Histogram,依托Histogram支持Exemplar;<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">关于Histogram:</p>桶计数:percentileHistogram=true开启桶计数,桶数量由minimumExpectedValue和maximumExpectedValue确定。在Prometheus场景下,桶计数需要累计<span style="color: black;">全部</span>进程生命周期中的所有计数,底层TimeWindowFixedBoundaryHistogram<span style="color: black;">守护</span>了一个永远不滚动的1容量的环形数组;分位数值:percentiles非空开启分位数值记录,分位数值数量由percentiles确定。收集时会将当前时间窗口内的计数,灌入累积Histogram,底层<span style="color: black;">运用</span>三方工具HdrHistogram实现;支持Exemplar:对于<span style="color: black;">每一个</span>桶,支持记录Exemplar;


nqkk58 发表于 2024-10-21 18:19:26

你的见解真是独到,让我受益良多。

m5k1umn 发表于 2024-10-24 18:19:15

对于这个问题,我有不同的看法...

b1gc8v 发表于 2024-10-26 20:33:33

期待你更多的精彩评论,一起交流学习。

4lqedz 发表于 2024-11-10 07:53:48

论坛的成功是建立在我们诚恳、务实、高效、创新和团结合作基础上,我们要把这种精神传递下去。

1fy07h 发表于 3 天前

谷歌外贸网站优化技术。

b1gc8v 发表于 昨天 23:02

认真阅读了楼主的帖子,非常有益。
页: [1]
查看完整版本: Micrometer源码分析