为了账号安全,请及时绑定邮箱和手机立即绑定

spring boot metrics信息推送开发

标签:
SpringBoot

  上一篇文章是关于 “spring boot +RabbitMQ +InfluxDB+Grafara监控实践” 主要讲spring boot应用新能监控信息的收集方案实践

  实践是hystrix信息推送的mq而metrics信息需要扫描,文章的最后也有相应的思考metrics信息能不能是应用本身也推送到mq那?

  本篇文章就实践关于metrics信息的推送实现

 

  有了上面的思考之后我就回过头来去看hystrix是怎么实现推送的。经过一番跟踪之后找到了具体干活的task代码

  https://img1.sycdn.imooc.com//5b5b1de900014bdb04520141.jpg

  有了这个代码就可以参考具体怎样实现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()这里我们发现了端倪

  好的 我们就去这个包去找相关线索

  https://img1.sycdn.imooc.com//5b5b1df100019c0204700323.jpg

  好的我们找到了这个包往下看

https://img1.sycdn.imooc.com//5b5b1df700014cfd04850519.jpg

  终于找到他了这里我们就可以用定时器进行轮训调用了。基础准备已经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);
    }
}

复制代码

View Code

复制代码

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;
    }
}

复制代码

View Code

复制代码

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;


@EnableSchedulingpublic 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);
        }
    }

    

}

复制代码

View Code

复制代码

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();
}

复制代码

View Code

复制代码

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监控实践” 这篇文章中的图就变成下面这样了

https://img1.sycdn.imooc.com//5b5b1e050001482506900171.jpg

 

    好实践部分就到这里

  总结思考

    监控信息hystrix和metrics到底是拉取好还是主动推送好!一下简单分析:

    拉取,对于被监控的应用来说值引用少量的包节省了推送信息的线程,基本没有什么开发量,对于一些严格权限控制的springboot应用,就需要额外开接口或者拉取进行权限验证很不方便

    推送,应用主动推送应用相关的包和注解占用对应的线程资源,应用可以进行严格的权限控制不用对接口做例外不需要扫描程序开发。

  我的结论是两者并存,不知道大家有没有什么其他想法可以说来听听!

  原文出处:https://www.cnblogs.com/zhyg/p/9377406.html


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消