spring boot metrics信息推送开发
2018-07-28 06:12:33来源:博客园 阅读 ()
上一篇文章是关于 “spring boot +RabbitMQ +InfluxDB+Grafara监控实践” 主要讲spring boot应用新能监控信息的收集方案实践
实践是hystrix信息推送的mq而metrics信息需要扫描,文章的最后也有相应的思考metrics信息能不能是应用本身也推送到mq那?
本篇文章就实践关于metrics信息的推送实现
有了上面的思考之后我就回过头来去看hystrix是怎么实现推送的。经过一番跟踪之后找到了具体干活的task代码
有了这个代码就可以参考具体怎样实现metrics信息的推送了
但是还有一个问题就是metrics信息虽然暴露了url接口但是应用内我怎么获取那???
这里又引发了我们一探究竟的兴趣!。。。。。。继续看源码!!!!!!!!!!!
从spring boot启动展示的日志中我们可以发现线索,具体/metrics路径具体执行的是哪里
Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
从org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()这里我们发现了端倪
好的 我们就去这个包去找相关线索
好的我们找到了这个包往下看
终于找到他了这里我们就可以用定时器进行轮训调用了。基础准备已经ok,好了不多说了直接上写好的代码
package com.zjs.mic.metrics.stream; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.actuator.HasFeatures; import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClient; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.Output; import org.springframework.cloud.stream.config.BindingProperties; import org.springframework.cloud.stream.config.BindingServiceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.MessageChannel; import org.springframework.scheduling.annotation.EnableScheduling; @RefreshScope @Configuration @ConditionalOnClass({EnableBinding.class }) @ConditionalOnProperty(value = "metrics.stream.queue.enabled", matchIfMissing = true) @EnableConfigurationProperties @EnableScheduling @EnableBinding(MetricsStreamClient.class) public class MetricsStreamAutoConfiguration { @Autowired private BindingServiceProperties bindings; @Autowired private MetricsStreamProperties properties; @Autowired @Output(MetricsStreamClient.OUTPUT) private MessageChannel outboundChannel; @Autowired(required = false) private Registration registration; @Autowired MetricsMvcEndpoint mme; @Bean public HasFeatures metricsStreamQueueFeature() { return HasFeatures.namedFeature("Metrics Stream (Queue)", MetricsStreamAutoConfiguration.class); } @PostConstruct public void init() { BindingProperties outputBinding = this.bindings.getBindings() .get(MetricsStreamClient.OUTPUT); if (outputBinding == null) { this.bindings.getBindings().put(MetricsStreamClient.OUTPUT, new BindingProperties()); } BindingProperties output = this.bindings.getBindings() .get(MetricsStreamClient.OUTPUT); if (output.getDestination() == null) { output.setDestination(this.properties.getDestination()); } if (output.getContentType() == null) { output.setContentType(this.properties.getContentType()); } } @Bean public MetricsStreamTask metricsStreamTask(SimpleDiscoveryClient simpleDiscoveryClient) { ServiceInstance serviceInstance = this.registration; if (serviceInstance == null) { serviceInstance = simpleDiscoveryClient.getLocalServiceInstance(); } return new MetricsStreamTask(this.outboundChannel, serviceInstance, this.properties,this.mme); } }
package com.zjs.mic.metrics.stream; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("metrics.stream.queue") public class MetricsStreamProperties { private boolean enabled = true; private boolean prefixMetricName = true; private boolean sendId = true; private String destination = "springCloudMetricsStream"; private String contentType = "application/json"; private String pathTail = "mem.*|heap.*|threads.*|gc.*|nonheap.*|classes.*"; private long sendRate = 1000; private long gatherRate = 1000; private int size = 1000; public String getPathTail() { return pathTail; } public void setPathTail(String pathTail) { this.pathTail = pathTail; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean isPrefixMetricName() { return prefixMetricName; } public void setPrefixMetricName(boolean prefixMetricName) { this.prefixMetricName = prefixMetricName; } public boolean isSendId() { return sendId; } public void setSendId(boolean sendId) { this.sendId = sendId; } public String getDestination() { return destination; } public void setDestination(String destination) { this.destination = destination; } public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } public long getSendRate() { return sendRate; } public void setSendRate(long sendRate) { this.sendRate = sendRate; } public long getGatherRate() { return gatherRate; } public void setGatherRate(long gatherRate) { this.gatherRate = gatherRate; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } }
package com.zjs.mic.metrics.stream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint; import org.springframework.cloud.client.ServiceInstance; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.support.MessageBuilder; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.util.Assert; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; @EnableScheduling public class MetricsStreamTask { private final static Logger log = LoggerFactory.getLogger(MetricsStreamTask.class); private MessageChannel outboundChannel; private ServiceInstance registration; private MetricsStreamProperties properties; private MetricsMvcEndpoint mme; // Visible for testing final LinkedBlockingQueue<String> jsonMetrics; private final JsonFactory jsonFactory = new JsonFactory(); public MetricsStreamTask(MessageChannel outboundChannel, ServiceInstance registration, MetricsStreamProperties properties, MetricsMvcEndpoint mme) { Assert.notNull(outboundChannel, "outboundChannel may not be null"); Assert.notNull(registration, "registration may not be null"); Assert.notNull(properties, "properties may not be null"); Assert.notNull(mme, "properties may not be null"); this.outboundChannel = outboundChannel; this.registration = registration; this.properties = properties; this.jsonMetrics = new LinkedBlockingQueue<>(properties.getSize()); this.mme=mme; } // TODO: use integration to split this up? @Scheduled(fixedRateString = "${metrics.stream.queue.sendRate:1000}") public void sendMetrics() { log.info("推送metrics信息"); ArrayList<String> metrics = new ArrayList<>(); this.jsonMetrics.drainTo(metrics); if (!metrics.isEmpty()) { if (log.isTraceEnabled()) { log.trace("sending stream Metrics metrics size: " + metrics.size()); } for (String json : metrics) { // TODO: batch all metrics to one message try { // TODO: remove the explicit content type when s-c-stream can handle // that for us this.outboundChannel.send(MessageBuilder.withPayload(json) .setHeader(MessageHeaders.CONTENT_TYPE, this.properties.getContentType()) .build()); } catch (Exception ex) { if (log.isTraceEnabled()) { log.trace("failed sending stream Metrics metrics: " + ex.getMessage()); } } } } } @Scheduled(fixedRateString = "${metrics.stream.queue.gatherRate:1000}") public void gatherMetrics() { log.info("开始获取metrics信息"); try { StringWriter jsonString = new StringWriter(); JsonGenerator json = this.jsonFactory.createGenerator(jsonString); json.writeStartObject(); json.writeObjectField("instanceId",registration.getServiceId() + ":" + registration.getHost() + ":" + registration.getPort()); json.writeObjectField("type", "metrics"); json.writeObjectField("currentTime",System.currentTimeMillis()); @SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) mme.value(this.properties.getPathTail()); for (String str : map.keySet()) { json.writeObjectField(str, map.get(str)); } json.writeEndObject(); json.close(); // output to stream this.jsonMetrics.add(jsonString.getBuffer().toString()); } catch (Exception ex) { log.error("Error adding metrics metrics to queue", ex); } } }
package com.zjs.mic.metrics.stream; import org.springframework.cloud.stream.annotation.Output; import org.springframework.messaging.MessageChannel; public interface MetricsStreamClient { String OUTPUT = "metricsStreamOutput"; @Output(OUTPUT) MessageChannel metricsStreamOutput(); }
package com.zjs.mic.metrics.stream; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Import; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(MetricsStreamAutoConfiguration.class) @EnableConfigurationProperties({MetricsStreamProperties.class}) public @interface EnableMetricsStream { }
已经将上面的代码包装成注解打好包 在入口类加@EnableMetricsStream 注解就能生效
剩下的就是我们去mq接收信息传递到响应数据库中进行处理就行了
从而我们在“spring boot +RabbitMQ +InfluxDB+Grafara监控实践” 这篇文章中的图就变成下面这样了
好实践部分就到这里
总结思考
监控信息hystrix和metrics到底是拉取好还是主动推送好!一下简单分析:
拉取,对于被监控的应用来说值引用少量的包节省了推送信息的线程,基本没有什么开发量,对于一些严格权限控制的springboot应用,就需要额外开接口或者拉取进行权限验证很不方便
推送,应用主动推送应用相关的包和注解占用对应的线程资源,应用可以进行严格的权限控制不用对接口做例外不需要扫描程序开发。
我的结论是两者并存,不知道大家有没有什么其他想法可以说来听听!
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Spring系列.ApplicationContext接口 2020-06-11
- springboot2配置JavaMelody与springMVC配置JavaMelody 2020-06-11
- 给你一份超详细 Spring Boot 知识清单 2020-06-11
- SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 2020-06-11
- 掌握SpringBoot-2.3的容器探针:实战篇 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash