Micrometer 系列【5】Counter 计数器
文章目录1. 整体介绍1.1 基础概念1.2 计数器类型1.2.1 CumulativeCounter 累加计数器1.2.2 StepCounter 步进区间计数器1.2.3 DropwizardCounter 第三方适配器1.2.4 CompositeCounter 复合多路分发计数器1.2.5 NoopCounter 空操作无实现计数器1.3 核心规范1.4 使用方式3. 手动计数器3.1 创建方式3.1.1 静态工厂创建3.1.2 流式构建器3.2 埋点使用主动打点3.3 查看计数器数值3.3.1 方式 1直接调用 counter.count()3.3.2 方式 2通过 registry 遍历所有 Meter调用 measure() 采集指标3.3.3 方式 3重新获取 Counter 再取值4. Counted AOP 自动计数器4.1 核心概念4.2 使用示例4.3 MeterTag 从方法入参动态提取标签4.4 优势和劣势5. 外部函数计数器5.1 核心定义5.2 使用示例5.3 优势和劣势1. 整体介绍1.1 基础概念Counter计数器是Micrometer八大计量器中最常用、最基础的埋点类型用于统计单调递增事件总量例如请求次数、异常次数、消息生产/消费次数。统一顶层接口Counter核心两个方法increment(double amount)计数累加埋点打点入口count()读取当前计数值注意事项所有计量器统一顶层接口为Meter全部由MeterRegistry注册表创建、托管Counter是Meter的子接口分为普通手动计数器、CountedAOP自动计数器、FunctionCounter外部函数计数器三类计数器仅输出一类指标【累计计数值】Counter接口仅支持正向累加increment()传入的增量必须为正数不支持负数递减。1.2 计数器类型横向对比总表类名计数模型核心用途典型绑定 RegistryCumulativeCounter全量累计标准累加指标时序库后台算ratePrometheusMeterRegistryStepCounter步进窗口增量直接输出周期增量云端SaaS监控DatadogMeterRegistryDropwizardCounter第三方桥接兼容Codahale/Dropwizard旧metrics体系DropwizardMeterRegistryCompositeCounter多路分发聚合一套埋点同时上报多个监控后端CompositeMeterRegistryNoopCounter空操作降级监控关闭时兜底避免空指针、减少分支判断所有Registry禁用时自动切换1.2.1 CumulativeCounter 累加计数器核心字段DoubleAdder高并发线程安全累加器比AtomicDouble吞吐更高。privatefinalDoubleAddervalue;处理逻辑increment()不断往DoubleAdder叠加数值count()返回程序启动以来累计总和不会重置。特点累计型cumulative数值只涨不跌Prometheus、InfluxDB等绝大多数时序库默认使用适合统计总请求数、总错误数、总下单量等永久累加指标。优缺点✅ 简单、并发性能好❌ 无法直接看区间增量需后端计算速率rate 当前 - 上一次1.2.2 StepCounter 步进区间计数器该计数器向监控系统上报单个采集步长内的增量count()返回的是上一完整周期的事件增量而非服务全生命周期总和。核心字段StepDouble内置双缓冲区当前窗口缓冲区 上一完整窗口缓冲区依赖Clock和采集步长stepMillis如60s。privatefinalStepDoublevalue;处理逻辑increment()只写入当前活跃窗口count()返回上一个完整采集周期的增量值_closingRollover()周期到切换缓冲区旧窗口数据冻结供采集新窗口清零。特点数值会周期性重置天然输出区间增量直接可算QPS内存存双窗口少量额外开销。适配按周期推送、不做差值计算的监控系统Datadog、New Relic、Wavefront等SaaS监控系统需要直接拿到“这一分钟产生了多少次”不用后台再算差值。1.2.3 DropwizardCounter 第三方适配器核心字段是桥接适配层把MicrometerCounterAPI转发给DropwizardCodahale原生Meter。privatefinalcom.codahale.metrics.Meterimpl;逻辑映射increment(amount)→impl.mark((long) amount)Dropwizard Meter仅支持long类型传入double会强制强转long小数会丢失精度count()→impl.getCount()返回Dropwizard底层累计总数。定位兼容老项目原有Dropwizard Metrics迁移到Micrometer时无缝兼容封装第三方metrics库屏蔽底层API差异统一Micrometer埋点入口。1.2.4 CompositeCounter 复合多路分发计数器继承AbstractCompositeMeter内部持有多个子 Counter对应多个Registry例如同时输出PrometheusDatadog。核心方法解读increment(double amount)一次埋点打点遍历所有注册的子计数器同步累加实现多监控系统同时上报。count()只取第一个子计数器的值复合场景下读数值仅做兜底展示无业务计算意义。registerNewMeter() 当新增Registry时自动用Meter.Id重建对应类型的子Counter注册到新注册表newNoopMeter()无注册器时返回空实现NoopCounter。使用场景多监控共存业务同时对接PrometheusLokiDatadog埋点只写一次多路输出。1.2.5 NoopCounter 空操作无实现计数器处理逻辑Overridepublicvoidincrement(doubleamount){}// 空方法不做任何累加Overridepublicdoublecount(){return0;}触发时机MeterRegistry被关闭/禁用Composite无任何子注册器全局metrics开关关闭作用空对象模式避免埋点代码频繁判空if(counter ! null)埋点代码无感知降级关闭监控不影响业务主流程零性能损耗。1.3 核心规范1. 重复埋点冗余禁止若业务逻辑需要同时记录耗时使用Timer即可Timer内置事件总次数统计无需额外新增Counter同理DistributionSummary自带count统计不要重复创建计数器。2.观测指标优先看速率而非原始绝对值原始累计总值会受实例运行时长干扰服务重启后数值直接归零图表断崖下跌。生产告警、大盘分析务必基于单位时间速率QPS/TPS。示例消息队列监控用速率区分消息入队/消费快慢不受实例重启、运行天数影响。1.4 使用方式分类埋点方式数值维护方是否调用 increment 埋点指标含义依赖框架普通手动 Counter开发者主动埋点Counter 内部累加必须手动调用累计事件次数 / 区间增量无纯 MicrometerCounted AOP CounterAOP 自动埋点Counter 内部累加框架自动调用无需手写方法调用总次数、异常次数Spring AOPFunctionCounter无主动埋点外部业务对象维护调用无效不做计数当前瞬时存量快照无3. 手动计数器开发者主动在业务代码获取Counter对象手动调用increment()/increment(n)完成计数埋点是最基础、灵活度最高的埋点方式。3.1 创建方式3.1.1 静态工厂创建通过MeterRegistry.counter()静态工厂创建全局缓存同名同标签实例重复创建不会新建对象。创建注册表MeterRegistryregistrynewSimpleMeterRegistry();支持标签维度拆分// 创建指标名api.request携带标签envtestCountercounterregistry.counter(api.request,Tags.of(env,test));3.1.2 流式构建器低频元数据指标说明、基础单位通过Counter.builder()链式配置最终调用register()注册到注册表CountercounterCounter.builder(api.request).baseUnit(requests)// 基础计量单位.description(HTTP接口总请求次数)// 指标描述同步推送到监控平台.tags(region,test,server,gateway)// 多维度标签.register(registry);3.2 埋点使用主动打点业务分支、异常、事件发生处手动累加支持整数 / 浮点数增量// 请求 1counter.increment();// 请求 10counter.increment(10);3.3 查看计数器数值3.3.1 方式 1直接调用 counter.count()Counter接口自带count()方法直接读出当前计数值// 直接读取计数器当前值doubletotalcounter.count();System.out.println(接口总请求数total);// 输出 11.03.3.2 方式 2通过 registry 遍历所有 Meter调用 measure() 采集指标measure()是Meter统一对外暴露指标数据的标准方法监控组件底层都是靠这个读取数据返回Measurement对象// 遍历注册表内所有计量器for(Metermeter:registry.getMeters()){System.out.println(指标名称meter.getId().getName());System.out.println(标签meter.getId().getTags());// 读取指标观测值for(Measurementmeasurement:meter.measure()){System.out.println(统计类型measurement.getStatistic());System.out.println(指标数值measurement.getValue());}System.out.println(------------------------);}输出示例指标名称api.request 标签[tag(regiontest), tag(servergateway)] 统计类型COUNT 指标数值11.03.3.3 方式 3重新获取 Counter 再取值代码其他位置没有持有Counter对象时可通过registry.counter(名称, 标签) 重新拿到实例再调用count()// 根据指标名、标签匹配获取已注册的CounterCounterfindCounterregistry.counter(api.request,Tags.of(region,test,server,gateway));System.out.println(查询到的请求总数findCounter.count());4. Counted AOP 自动计数器4.1 核心概念基于Spring AOP动态代理实现的全自动埋点仅需在类 / 方法上加Counted注解无需手写counter.increment()支持同步、异步Async方法框架自动拦截方法执行完成计数逻辑。两种织入方式编译/加载期AspectJ织入Spring AOP动态代理日常Spring项目主流方案。AOP内部执行逻辑示例调用方法前通过注解元数据构建Meter.Id从registry获取 / 创建Counter方法正常返回执行counter.increment()标签resultsuccess方法抛出异常可配置单独累加异常计数携带异常类名标签方法执行结束切面释放上下文对业务无感知。底层实际计量对象仍是标准CumulativeCounter/StepCounter等只是埋点动作由AOP环绕通知自动执行。4.2 使用示例SpringBoot自动配置CountedAspect若自动配置失效需手动注册切面BeanConfigurationpublicclassCountedConfiguration{// 注册切面全局生效BeanpublicCountedAspectcountedAspect(MeterRegistryregistry){returnnewCountedAspect(registry);}}使用示例// 基础用法方法调用成功自动1Counted(valueuser.login.count,extraTags{device,mobile})publicvoidlogin(Stringusername){// 纯业务代码无任何埋点逻辑}// 进阶区分成功/失败计数、记录异常类型、自定义描述Counted(valueapi.order.create,description订单创建接口调用统计,recordFailuresAsExceptionstrue,// 异常单独打异常标签extraTags{source,h5},failTagerror.type// 异常类型存入tag)publicOrdercreateOrder(OrderDTOdto){returnorderService.save(dto);}异步方法同样生效AsyncCountedpublicCompletableFuture?asyncPay(){returnCompletableFuture.supplyAsync(()-{// 支付逻辑});}4.3 MeterTag 从方法入参动态提取标签常规Counted仅能写死静态标签若需要把接口入参、业务参数作为指标维度搭配MeterTag注解使用需要手动配置标签解析处理器。配置标签解析器// 自定义参数值解析器ValueResolvervalueResolverparameter-custom_tag_value[parameter];// Spring EL表达式解析器ValueExpressionResolverelResolvernewSpelValueExpressionResolver();// 给切面绑定处理器countedAspect.setMeterTagAnnotationHandler(newCountedMeterTagAnnotationHandler(clazz-valueResolver,clazz-elResolver));支持四种标签提取模式interfaceOrderApi{// 模式1自定义ValueResolver解析参数CountedvoidresolverTagDemo(MeterTag(keypay_type,resolverValueResolver.class)StringpayParam);// 模式2SpEL表达式生成标签值CountedvoidelTagDemo(MeterTag(keydesc,expressionpay_ type)Stringtype);// 模式3直接调用参数toString()作为标签值CountedvoidsimpleTagDemo(MeterTag(order_id)LongorderId);// 模式4单个参数挂载多个标签CountedvoidmultiTagDemo(MeterTag(keychannel,expressionch: data.channel)MeterTag(keysource,expressiondata.source)DataHolderdata);}调用后指标校验示例// 直接toStringapi.simpleTagDemo(15L);assertThat(registry.get(method.counted).tag(order_id,15).counter().count()).isEqualTo(1);// 自定义解析器api.resolverTagDemo(alipay);assertThat(registry.get(method.counted).tag(pay_type,custom_tag_value[alipay]).counter().count()).isEqualTo(1);限制说明CountedAspect不支持元注解嵌套Counted必须直接标注在目标方法上。4.4 优势和劣势✅优势零埋点代码无业务侵入接口统一规范全局统一管控所有接口 / 服务方法调用量避免漏埋天然区分成功、失败调用快速统计接口错误率统一添加固定标签服务名、环境、模块。❌ 劣势依赖Spring AOP仅能作用于Spring Bean的public方法无法细粒度区分方法内部多分支逻辑只能统计整个方法调用次数不能自定义增量数值每次调用固定1内部调用this.xxx ()AOP拦截失效无法计数。5. 外部函数计数器5.1 核心定义和前两类完全相反没有任何increment主动埋点操作Counter自身不存储、不累加数值指标采集时自动回调传入的外部函数读取外部已存在的数值作为当前计数值。不属于Cumulative/Step实现体系是独立实现的特殊Counter:典型业务场景连接池状态数据库活跃连接数、Redis客户端连接数在线存量当前在线用户、活跃会话数量队列堆积MQ待消费消息、线程池排队任务数内存缓存本地缓存key数量、限流当前排队请求数。约束开发者必须保证读取的函数返回值只增不减Micrometer不会校验单调性。调用functionCounter.increment()不会报错但内部是空实现不会改变任何数值无实际作用所有数值维护交给外部业务对象。5.2 使用示例通过registry.more().counter()函数式构造器注册绑定外部对象与取值函数CacheguavaCache...;// 开启内置统计的Guava缓存// 自动抓取 cache.stats().evictionCount() 单调递增数值registry.more().counter(cache.evict.total,Tags.of(cache,user),guavaCache,c-c.stats().evictionCount());流式构建器// 自定义状态对象提供单调递增count()方法CacheStatestatenewCacheState();FunctionCountercounterFunctionCounter.builder(cache.hit.total,state,state-state.count()).baseUnit(hits).description(缓存命中总次数).tags(region,prod).register(registry);数据更新逻辑业务代码自主修改外部变量FunctionCounter完全不参与数值修改没有increment()埋点逻辑监控组件定时拉取指标时自动执行取值函数拿到实时最新值上报。5.3 优势和劣势✅ 优势复用业务已有状态变量无需额外维护一套计数适合瞬时存量指标在线人数、连接数、队列堆积长度无埋点侵入不需要在事件处写计数代码。❌ 劣势不支持增量打点仅能读取外部现成数值取值函数执行时机在指标采集阶段高频采集会带来额外性能消耗无法统计事件发生次数只适合存量快照类指标函数执行异常会直接导致指标无数据。

相关新闻

「NoSQL」技术之 MongoDB 篇:物理备份磁盘膨胀率减少 90% 的内核优化实践

「NoSQL」技术之 MongoDB 篇:物理备份磁盘膨胀率减少 90% 的内核优化实践

关键词:MongoDB、WiredTiger、物理备份、空间回收、备份回档提速MongoDB 常见的备份方式有两种:逻辑备份和物理备份。逻辑备份需要逐条遍历集合,期间持续消耗 CPU、内存与业务侧的查询带宽,TB 级实例往往要跑十几个小时&#xff0…

2026/10/18 6:55:25 阅读更多 →
从原生 K8s 到 Helm:彻底搞懂 templates/、values 与 Chart.yaml

从原生 K8s 到 Helm:彻底搞懂 templates/、values 与 Chart.yaml

从原生 K8s 到 Helm:彻底搞懂 templates/、values 与 Chart.yaml刚学完 k8s/ 文件夹里那一堆原生 YAML,以为自己"懂"了 Kubernetes 部署。打开 helm/ 目录后却懵了:templates/ 里全是 {{ .Values.xxx }},values.yaml、v…

2026/10/18 13:25:42 阅读更多 →
如何用3个现代Anki主题让记忆学习变得赏心悦目:Prettify美化模板完全指南

如何用3个现代Anki主题让记忆学习变得赏心悦目:Prettify美化模板完全指南

如何用3个现代Anki主题让记忆学习变得赏心悦目:Prettify美化模板完全指南 【免费下载链接】anki-prettify Collection of customizable Anki flashcard templates with modern and clean themes. 项目地址: https://gitcode.com/gh_mirrors/an/anki-prettify …

2026/10/17 6:34:24 阅读更多 →

最新新闻

计算机网络综合实验方案:VLAN、OSPF、NAT与抓包分析全链路

计算机网络综合实验方案:VLAN、OSPF、NAT与抓包分析全链路

简介:这份华北电力大学计算机网络综合实验报告配套资料,面向计算机、网络工程等专业学生及需要完成课程设计的学习者,聚焦网络设备配置与协议分析两大实践方向。资源包内含1个doc文档,约21.91MB,完整呈现实验任务书、设…

2026/10/18 20:44:14 阅读更多 →
用Unity打造透明桌面挂件:Win32窗口与点击穿透详解

用Unity打造透明桌面挂件:Win32窗口与点击穿透详解

做桌面挂件、桌面时钟、动态壁纸这类需求时,很多人第一反应是用WPF、Electron或者Qt去写,但真到要精细控制3D渲染、粒子特效、骨骼动画的时候,这些方案一个比一个难受。绕一圈之后你会发现,用Unity来做“透明软件背景、显示桌面内…

2026/10/18 20:44:14 阅读更多 →
UE5蓝图截图实战:从HighResShot到RenderTarget完整指南

UE5蓝图截图实战:从HighResShot到RenderTarget完整指南

不是跟AI对话,下面直接放正文。这篇文章我按自己这些年做UE项目的习惯来写,聊的全是蓝图里和截屏死磕的实战经验,希望对为截图功能纠结过的同学有点用。1. 截图功能的应用场景与方案选型先说一句大实话:截图这件事,在U…

2026/10/18 20:44:14 阅读更多 →
离线部署轻量Agent:无网无卡也能跑通工具调用与自动化

离线部署轻量Agent:无网无卡也能跑通工具调用与自动化

很多人问我:不联网的电脑上,到底能不能跑出一个像样的AI应用来?在还没有真正动手之前,我也觉得这事悬。但当我花了将近两周时间,把一款开源轻量模型塞进一台没有外网的办公笔记本里,再给它套上Agent框架、接…

2026/10/18 20:44:14 阅读更多 →
Flutter鸿蒙适配必知:Platform View机制原理与踩坑实践

Flutter鸿蒙适配必知:Platform View机制原理与踩坑实践

前段时间我把一套基于 Flutter 的跨平台应用(下文就叫它模拟项目X吧)往鸿蒙生态迁移,最让我头疼的还不是改 Dart 代码,而是地图、视频这类必须依赖原生 SDK 的模块。页面能跑起来,可原生控件死活上不了屏,查…

2026/10/18 20:44:14 阅读更多 →
OSPF多区域实战:LSA类型、ABR机制与特殊区域配置

OSPF多区域实战:LSA类型、ABR机制与特殊区域配置

很多人学OSPF时,单区域配置玩得很溜,一到多区就懵了:明明就是两条network命令的事,为什么还要分骨干区、特殊区,甚至搞出一堆LSA类型?更麻烦的是,多区之后再看路由表,你会发现区域间…

2026/10/18 20:43:12 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →