当前位置: 首页 > 后端技术 > Java

微服务性能监控系列——基于Metrics的实时监控系统

时间:2023-04-01 22:38:01 Java

原文链接Metrics是一个提供服务性能检测工具的Java类库。它提供了一个强大的性能指标工具库,用于衡量生产环境中关键组件的性能。测量类型Metrics提供以下基本测量类型:Gauge:用于提供自定义测量。Counter:计数器,本质上是一个java.util.concurrent.atomic.LongAdder。直方图:直方图数据。Meter:统计系统中某个事件的响应率,比如TPS、QPS。该指标的值直接反映了系统当前的处理能力。定时器:定时器是Meter和Histogram的组合,可以统计接口的请求率和响应时间。GaugeGauge是对物品价值的瞬时测量。我们可以通过实现Gauge接口,根据业务场景自定义指标。例如,要测量队列中等待的作业数:publicclassQueueManager{privatefinalQueuequeue;publicQueueManager(MetricRegistrymetrics,Stringname){this.queue=newQueue();//通过MetricRegistry的register方法注册Gaugemetrics.register(MetricRegistry.name(QueueManager.class,name,"size"),newGauge(){@OverridepublicIntegergetValue(){returnqueue.size();}});}}官方目前提供了以下几种Gauge实现:CounterCounter是一个常规的计数器,用于累加或者递减一个指标的值。Counter本质上是一个java.util.concurrent.atomic.LongAdder。在多个线程同时更新计数器的场景下,当并发量很大时,LongAdder的吞吐量要比AtomicLong高,当然也会消耗更多的空间资源。finalCounterevictions=registry.counter(name(SessionStore.class,"cache-evictions"));evictions.inc();evictions.inc(3);evictions.dec();evictions.dec(2);直方图直方图响应数据流中值的分布是怎样的。包含最小值、最大值、平均值、中值、p75、p90、p95、p98、p99和p999数据分布。privatefinalHistogramresponseSizes=metrics.histogram(name(RequestHandler.class,"response-sizes"));publicvoidhandleRequest(Requestrequest,Responseresponse){//等responseSizes.update(response.getContent().length);}直方图计算分位数的方法是先对整个数据集进行排序,然后取排序后数据集中特定位置的值(例如p99取倒序1%位置的值)。这种方法适用于小数据集或批处理系统,但不适用于需要高吞吐量和低延迟的服务。对于数据量大,系统对吞吐量和延迟要求高的场景,我们可以使用采样来获取数据。通过在程序运行过程中动态提取一小部分能代表系统实际运行情况的数据,实现对整个系统运行指标的近似测量,这种方法称为水库采样。Metrics中提供了多种Reservoir实现:MeterMeter用于衡量事件响应的平均速率,代表整个应用生命周期的总速率(总请求响应量/处理请求的总毫秒数,即每秒请求数)。此外,Meter还提供了1分钟、5分钟和15分钟的动态平均响应速度。finalMetergetRequests=registry.meter(name(WebProxy.class,"get-requests","requests"));getRequests.mark();getRequests.mark(requests.size());TimerTimer会测量响应率服务,以及服务响应时间的分布也会被统计。finalTimertimer=registry.timer(name(WebProxy.class,"get-requests"));finalTimer.Contextcontext=timer.time();try{//处理请求}finally{context.stop();}Reporters通过上述metrics监控服务指标后,我们可以通过Reporters报表导出测量结果。metrics-core模块实现了以下几种导出指标:ConsoleReporters定期向控制台发送服务指标数据。最终ConsoleReporterreporter=ConsoleReporter.forRegistry(registry).convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS).build();reporter.start(1,TimeUnit.MINUTES);文件追加服务指标数据。对于每个指标,将在指定目录中创建一个.csv文件,然后指标的最新数据将定期附加到每个文件(本例中为1s)。finalCsvReporterreporter=CsvReporter.forRegistry(registry).formatFor(Locale.US).convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS).build(newFile("~/projects/data/"));记者。开始(1,TimeUnit.SECONDS);JmxReporter通过JMXMBeans暴露了服务的各种指标,然后您可以使用VisualVM查看指标。不推荐用于生产环境。finalJmxReporterreporter=JmxReporter.forRegistry(registry).build();reporter.start();Slf4jReporterSlf4jReporter允许我们将服务的指标数据记录到日志文件中。最终Slf4jReporter记者=Slf4jReporter.forRegistry(注册表).outputTo(LoggerFactory.getLogger(“com.example.metrics”)).convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS).build();reporter.start(1,TimeUnit.MINUTES);如何使用直接依赖于Metrics的核心库,通过它提供的各种API来完成对服务指标数据的度量。引入Maven依赖io.dropwizard.metricsmetrics-core${metrics.version}创建MetricRegistry对象,它是Metrics类库的核心类,所有的应用指标都需要注册到MetricRegistry中。//实例化MetricsRegistryfinalMetricRegistrymetrics=newMetricRegistry();//打开ConsoleReporterstartConsoleReporter();Meterrequests=metrics.meter(name(MetricsConfig.class,"requests","size"));requests.mark();voidstartReport(){ConsoleReporterreporter=ConsoleReporter.forRegistry(metrics).convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS).build();reporter.start(1,TimeUnit.SECONDS);}整合Spring引入Maven依赖com.ryantenney.metricsmetrics-spring3.1.3通过Java注解配置Metrics。导入java.util.concurrent.TimeUnit;导入org.springframework.context.annotation.Configuration;导入com.codahale.metrics.ConsoleReporter;导入com.codahale.metrics.MetricRegistry;导入com.codahale.metrics.SharedMetricRegistries;导入com。ryantenney.metrics.spring.config.annotation.EnableMetrics;importcom.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;@Configuration@EnableMetricspublicclassSpringConfiguringClassextendsMetricsConfigurerAdapter{@OverridepublicvoidconfigureReporters(MetricRegistrymetricRegistry){//registerReporter允许MetricsConfigurerAdapter//在Spring上下文关闭时关闭reporterregisterReporter(ConsoleReporter.forRegistry(metricRegistry).build()).start(1,TimeUnit.MINUTES);}}@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Import({DelegatingMetricsConfiguration.class})public@interfaceEnableMetrics{//默认false表示使用JDK动态代理,设置为true表示使用CGLIB动态代理(当使用基于类的服务暴露方式时)booleanexposeProxy()defaultfalse;//设置为true,目标对象可以通过AopContext.currentProxy()访问封装它的代理booleanproxyTargetClass()defaultfalse;}使用限制因为在SpringAOP中,只能代理声明为public的方法,所以@Timed,@Metered、@ExceptionMetered和@Counted不能在非public生效,因为@Gauge注解不涉及代理,所以可以应用于非public的属性和方法。公共类MetricsBeanPostProcessorFactory{privateMetricsBeanPostProcessorFactory(){}publicstaticAdvisingBeanPostProcessorexceptionMetered(MetricRegistrymetricRegistry,ProxyConfigproxyConfig){returnnewAdvisingBeanPostProcessor(ExceptionMeteredMethodInterceptor.POINTCUT,ExceptionMeteredMethodInterceptor.adviceFactory(metricConfig)),代理(metricRegistry);}publicstaticAdvisingBeanPostProcessormetered(MetricRegistrymetricRegistry,ProxyConfigproxyConfig){}publicstaticAdvisingBeanPostProcessortimed(MetricRegistrymetricRegistry,ProxyConfigproxyConfig){returnnewAdvisingBeanPostProcessor(TimedMethodInterceptor.POINTCUT,TimedMethodInterceptor.adviceFactory(metricRegistry),proxyConfig);}publicstaticAdvisingBeanPostProcessor计数(MetricRegistrymetricRegistry,ProxyConfigproxyConfig){returnnewAdvisingBeanPostProcessor(CountedMethodInterceptor.POINTCUT,CountedMethodInterceptor.adviceFactory(metricRegistry),proxyConfig);}}publicstaticGaugeFieldAnnotationBeanPostProcessorgaugeField(MetricRegistrymetricRegistry){返回新的GaugeFieldAnnotationBeanPostProcessor(metricRegistry);}publicstaticGaugeMethodAnnotationBeanPostProcessorgaugeMethod(MetricRegistrymetricRegistry){返回新的GaugeMethodAnnotationBeanPostProcessor(metricRegistry);}publicstaticCachedGaugeAnnotationBeanPostProcessorcachedGauge(MetricRegistrymetricRegistry){返回新的CachedGaugeAnnotationBeanPostProcessor(metricRegistry);}publicstaticMetricAnnotationBeanPostProcessor指标(MetricRegistrymetricRegistry){返回新的MetricAnnotationBeanPostProcessor(metricRegistry);}公共静态HealthCheckBeanPostProcessorhealthCheck(HealthCheckRegistryhealthRegistry){返回新的HealthCheckBeanPostProcessor(healthRegistry);另外,在一个方法中调用同一个类中另一个带有Metrics注解的方法时,方法执行过程不会经过代理

最新推荐
猜你喜欢