服务监控 | 彻底搞懂Dropwizard Metrics一篇就够了
Metrics是一个提供服务性能检测工具的Java类库,它提供了功能强大的性能指标工具库用于度量生产环境中的各关键组件性能。
度量类型
Metrics提供了以下几种基本的度量类型:
Gauge
:用于提供自定义度量。Counter
:计数器,本质是一个java.util.concurrent.atomic.LongAdder
。Histogram
:直方图数据。Meter
:统计系统中某一事件的响应速率,如TPS、QPS。该项指标值直接反应系统当前的处理能力Timer
:计时器,是Meter
和Histogram
的结合,可以统计接口请求速率和响应时长。
Gauge
Gauge
是对一项值的瞬时度量。我们可以通过实现Gauge
接口来根据业务场景自定义度量。
例如,想要度量队列中处于等待状态的作业数量:
public class QueueManager {
private final Queue queue;
public QueueManager(MetricRegistry metrics, String name) {
this.queue = new Queue();
// 通过MetricRegistry 的register方法注册Gauge度量
metrics.register(MetricRegistry.name(QueueManager.class, name, "size"),
new Gauge<Integer>() {
@Override
public Integer getValue() {
return queue.size();
}
});
}
}
官方目前提供了以下几种Gauge
实现:
Counter
Counter
是一个常规计数器,用于对某项指标值进行累加或者递减操作。
Counter
本质是一个java.util.concurrent.atomic.LongAdder
,在多线程同时更新计数器的场景下,当并发量较大时,LongAdder
比AtomicLong
具有更高的吞吐量,当然空间资源消耗也更大一些。
final Counter evictions = registry.counter(name(SessionStore.class, "cache-evictions"));
evictions.inc();
evictions.inc(3);
evictions.dec();
evictions.dec(2);
Histograms
Histogram
反应的是数据流中的值的分布情况。包含最小值、最大值、平均值、中位数、p75、p90、p95、p98、p99以及p999数据分布情况。
private final Histogram responseSizes = metrics.histogram(name(RequestHandler.class, "response-sizes"));
public void handleRequest(Request request, Response response) {
// etc
responseSizes.update(response.getContent().length);
}
Histogram
计算分位数的方法是先对整个数据集进行排序,然后取排序后的数据集中特定位置的值(比如p99就是取倒序1%位置的值)。这种方式适合于小数据集或者批处理系统,不适用于要求高吞吐量、低延时的服务。
对于数据量较大,系统对吞吐量、时延要求较大的场景,我们可以采用抽样的方式获取数据。通过动态地抽取程序运行过程中的能够代表系统真实运行情况的一小部分数据来实现对整个系统运行指标的近似度量,这种方法叫做蓄水池算法(reservoir sampling)。
Metrics中提供了各式各样的Reservoir
实现:
Meter
Meter
用于度量事件响应的平均速率,它表示的是应用程序整个运行生命周期内的总速率(总请求响应量/处理请求的总毫秒数,即每秒请求数)。
除此之外,Meter
还提供了1分钟、5分钟以及15分钟的动态平均响应速率。
final Meter getRequests = registry.meter(name(WebProxy.class, "get-requests", "requests"));
getRequests.mark();
getRequests.mark(requests.size());
Timer
Timer
会度量服务的响应速率,同时也会统计服务响应时长的分布情况。
final Timer timer = registry.timer(name(WebProxy.class, "get-requests"));
final Timer.Context context = timer.time();
try {
// handle request
} finally {
context.stop();
}
Reporters
通过上述各项度量监测服务指标后,我们可以通过Reporters报表导出度量结果。metrics-core
模块中实现了以下几种导出指标的Report:
Console Reporters
定时向控制台发送服务的各项指标数据。
final ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(1, TimeUnit.MINUTES);
CsvReporter
定时向给定目录下的.csv
文件追加服务各项指标数据。对于每一项指标都会在指定目录下创建一个.csv
文件,然后定时(本例中是1s)向每个文件中追加指标最新数据。
final CsvReporter reporter = CsvReporter.forRegistry(registry)
.formatFor(Locale.US)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build(new File("~/projects/data/"));
reporter.start(1, TimeUnit.SECONDS);
JmxReporter
将服务的各项度量指标通过JMX MBeans暴露出来,之后可以使用VisualVM查看指标数据。生产环境不建议使用。
final JmxReporter reporter = JmxReporter.forRegistry(registry).build();
reporter.start();
Slf4jReporter
Slf4jReporter
允许我们将服务的指标数据作为日志记录到日志文件中。
final Slf4jReporter reporter = Slf4jReporter.forRegistry(registry)
.outputTo(LoggerFactory.getLogger("com.example.metrics"))
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(1, TimeUnit.MINUTES);
如何使用
直接引用
直接依赖Metrics的核心库,通过其提供的各类API完成服务指标数据度量。
- 引入Maven依赖
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${metrics.version}</version>
</dependency>
- 创建一个
MetricRegistry
对象,它是Metrics类库的核心类,所有的应用指标都需要注册到MetricRegistry
。
// 实例化MetricsRegistry
final MetricRegistry metrics = new MetricRegistry();
// 开启Console Reporter
startConsoleReporter();
Meter requests = metrics.meter(name(MetricsConfig.class, "requests", "size"));
requests.mark();
void startReport() {
ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(1, TimeUnit.SECONDS);
}
整合Spring
- 引入Maven依赖
<dependency>
<groupId>com.ryantenney.metrics</groupId>
<artifactId>metrics-spring</artifactId>
<version>3.1.3</version>
</dependency>
- 通过Java注解配置Metrics。
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Configuration;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;
@Configuration
@EnableMetrics
public class SpringConfiguringClass extends MetricsConfigurerAdapter {
@Override
public void configureReporters(MetricRegistry metricRegistry) {
// registerReporter allows the MetricsConfigurerAdapter to
// shut down the reporter when the Spring context is closed
registerReporter(ConsoleReporter
.forRegistry(metricRegistry)
.build())
.start(1, TimeUnit.MINUTES);
}
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({DelegatingMetricsConfiguration.class})
public @interface EnableMetrics {
// 默认false表示使用JDK动态代理,设置为true时表示使用CGLIB动态代理(当使用基于类的服务暴露方式时)
boolean exposeProxy() default false;
// 设置为true时,目标对象可以通过AopContext.currentProxy()访问封装它的代理
boolean proxyTargetClass() default false;
}
使用限制
因为Spring AOP中,只有声明为public
的方法可以被代理,所以@Timed
, @Metered
, @ExceptionMetered
以及 @Counted
在non-public
无法生效。
因为@Gauge
注解不涉及代理,所以它可以被应用在non-public
属性和方法上。
public class MetricsBeanPostProcessorFactory {
private MetricsBeanPostProcessorFactory() {
}
public static AdvisingBeanPostProcessor exceptionMetered(MetricRegistry metricRegistry, ProxyConfig proxyConfig) {
return new AdvisingBeanPostProcessor(ExceptionMeteredMethodInterceptor.POINTCUT, ExceptionMeteredMethodInterceptor.adviceFactory(metricRegistry), proxyConfig);
}
public static AdvisingBeanPostProcessor metered(MetricRegistry metricRegistry, ProxyConfig proxyConfig) {
return new AdvisingBeanPostProcessor(MeteredMethodInterceptor.POINTCUT, MeteredMethodInterceptor.adviceFactory(metricRegistry), proxyConfig);
}
public static AdvisingBeanPostProcessor timed(MetricRegistry metricRegistry, ProxyConfig proxyConfig) {
return new AdvisingBeanPostProcessor(TimedMethodInterceptor.POINTCUT, TimedMethodInterceptor.adviceFactory(metricRegistry), proxyConfig);
}
public static AdvisingBeanPostProcessor counted(MetricRegistry metricRegistry, ProxyConfig proxyConfig) {
return new AdvisingBeanPostProcessor(CountedMethodInterceptor.POINTCUT, CountedMethodInterceptor.adviceFactory(metricRegistry), proxyConfig);
}
public static GaugeFieldAnnotationBeanPostProcessor gaugeField(MetricRegistry metricRegistry) {
return new GaugeFieldAnnotationBeanPostProcessor(metricRegistry);
}
public static GaugeMethodAnnotationBeanPostProcessor gaugeMethod(MetricRegistry metricRegistry) {
return new GaugeMethodAnnotationBeanPostProcessor(metricRegistry);
}
public static CachedGaugeAnnotationBeanPostProcessor cachedGauge(MetricRegistry metricRegistry) {
return new CachedGaugeAnnotationBeanPostProcessor(metricRegistry);
}
public static MetricAnnotationBeanPostProcessor metric(MetricRegistry metricRegistry) {
return new MetricAnnotationBeanPostProcessor(metricRegistry);
}
public static HealthCheckBeanPostProcessor healthCheck(HealthCheckRegistry healthRegistry) {
return new HealthCheckBeanPostProcessor(healthRegistry);
}
}
除此此外,在一个方法中调用处于同一个类中的另一个带有Metrics注解的方法时,方法执行流程不会经过代理。
服务监控 | 彻底搞懂Dropwizard Metrics一篇就够了的更多相关文章
- 就是要让你搞懂Nginx,这篇就够了!
开源Linux 长按二维码加关注~ 作者:渐暖° 出处:blog.csdn.net/yujing1314/article/details/107000737 来源:公众号51CTO技术栈 Nginx ...
- 程序员要搞明白CDN,这篇应该够了
最近在了解边缘计算,发现我们经常听说的CDN也是边缘计算里的一部分.那么说到CDN,好像只知道它中文叫做内容分发网络.那么具体CDN的原理是什么?能够为用户在浏览网站时带来什么好处呢?解决这两个问题是 ...
- 线上服务的FGC问题排查,看这篇就够了!
线上服务的GC问题,是Java程序非常典型的一类问题,非常考验工程师排查问题的能力.同时,几乎是面试必考题,但是能真正答好此题的人并不多,要么原理没吃透,要么缺乏实战经验. 过去半年时间里,我们的广告 ...
- 架构师必须搞懂DNS【转】
DNS,全称Domain Name System,即域名系统,搞清楚,它不是DNF地下城与勇士. DNS是怎么来的,我们知道要访问一个服务器的资源可以通过IP的形式访问,但IP地址比较难记,也不方便读 ...
- 搞懂分布式技术28:微服务(Microservice)那点事
搞懂分布式技术28:微服务(Microservice)那点事 微服务(Microservice)那点事 肥侠 2016-01-13 09:46:53 浏览58371 评论15 分布式系统与计算 微服务 ...
- 微服务监控之二:Metrics+influxdb+grafana构建监控平台
系统开发到一定的阶段,线上的机器越来越多,就需要一些监控了,除了服务器的监控,业务方面也需要一些监控服务.Metrics作为一款监控指标的度量类库,提供了许多工具帮助开发者来完成自定义的监控工作. 使 ...
- 微服务监控之一:Metrics让微服务运行更透明
摘要 让微服务运行状态清晰可见. 嘉宾演讲视频回顾及PPT:http://t.cn/R8b6i85 Metrics是什么 直译是“度量”,不同的领域定义有所区别,在微服务领域中的定义: “对微服务的某 ...
- 搞懂分布式技术3:初探分布式协调服务zookeeper
搞懂分布式技术3:初探分布式协调服务zookeeper 1.Zookeepr是什么 Zookeeper是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现诸如数据发布/订阅,负载均衡, ...
- 面试都在问的微服务、服务治理、RPC、下一代微服务框架... 一文带你彻底搞懂!
文章每周持续更新,「三连」让更多人看到是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 单体式应用程序 与微服务相对的另一个概念是传统的单体式应用程序( ...
随机推荐
- Cyber Apocalypse 2021 pwn write up
Controller 考点是整数溢出和scanf函数的引发的栈溢出漏洞,泄露libc地址将返回地址覆盖成one_gadgets拿到shell. 1 from pwn import * 2 3 p = ...
- Windows 任务计划部署 .Net 控制台程序
Windows 搜索:任务计划程序 创建任务 添加任务名称 设置触发器:这里设置每10分钟执行一次 保存之后显示 此任务会从每天的 0:10:00 执行第一次后一直循环下去. 在操作选项卡下,选择启动 ...
- Python pyecharts绘制水球图
一.水球图Liquid.add()方法简介 Liquid.add()方法签名add(name, data, shape='circle', liquid_color=None, is_liquid_a ...
- CF173A Rock-Paper-Scissors 题解
Content 有 \(2\) 个人在玩石头剪刀布,已知他们的出手都有一定的规律,求 \(n\) 局之后两个人各输了几局. 数据范围:\(1\leqslant n\leqslant 2\times 1 ...
- 记一次Linux bash 命令行卡顿排查之警惕LD_PRELOAD环境变量
现象: 通过屏幕或者ssh登录Linux操作系统(本例:Ubuntu)后,执行ls 需要数秒才返回 strace -c ls 查看实际命令调用耗时并不长 对比和正常执行的主机命令执行时,加载的库文件差 ...
- Do PDB Files Affect Performance?
After a detour into Historical Debugging, it's time to come back to return to answering questions ab ...
- clickhouse配置登录密码
执行 PASSWORD=$(base64 < /dev/urandom | head -c8); echo "123456"; echo -n "123456&qu ...
- Apache Shiro使用官方自带的生成AES密钥
package test; import org.apache.shiro.codec.Base64; import javax.crypto.KeyGenerator; import javax.c ...
- 【LeetCode】1037. Valid Boomerang 解题报告(C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 中学数学题 日期 题目地址:https://leet ...
- 【LeetCode】703. Kth Largest Element in a Stream 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 小根堆 日期 题目地址:https://leetco ...