劍走偏鋒:使用阿里云SLS日志服務(wù)實(shí)現(xiàn)類似prometheus+grafana可視化系統(tǒng)監(jiān)控

歡迎關(guān)注我的github,以后所有文章源碼都會(huì)陸續(xù)更新上去

隨著微服務(wù)的流行,勢(shì)必線上服務(wù)數(shù)量會(huì)越來越多,對(duì)每一個(gè)服務(wù)的管控也變得越來越繁瑣,一個(gè)可視化的系統(tǒng)資源/性能監(jiān)控成為剛需。通常我們都會(huì)選擇一些開源的很常見的產(chǎn)品:prometheus+grafana幾乎是一種默認(rèn)選擇,實(shí)際使用下來個(gè)人感覺確實(shí)也是體驗(yàn)最好的。
不過我司在去年未部署這一套方案前,JAVA團(tuán)隊(duì)已經(jīng)有迫切需要可視化監(jiān)控和報(bào)警的需求(JVM內(nèi)存是否設(shè)置合理,GC花費(fèi)時(shí)間到底有多少,線程池大小和隊(duì)列是否夠用,數(shù)據(jù)庫連接池是否高效,hystrix是否觸發(fā)熔斷等等),沒有可視化,全都是靠猜。而正好我們有使用阿里云的SLS日志服務(wù)產(chǎn)品,對(duì)其有一定程度的了解,加上本身也算是一種時(shí)序性數(shù)據(jù)解決方案,特別適合做系統(tǒng)監(jiān)控。此篇文章只適用于已經(jīng)使用阿里云SLS日志服務(wù)的團(tuán)隊(duì)作為另外一種實(shí)現(xiàn)思路的參考,通常我還是會(huì)推薦prometheus+grafana。

認(rèn)識(shí)SLS

詳細(xì)的介紹建議大家直接閱讀官方文檔,這里只做以下四點(diǎn)說明

  1. 日志內(nèi)容 完整metric日志內(nèi)容(還有一些日志本身附加很有用的信息),以及豐富的字段索引設(shè)置

    image.png

  2. 查詢語法 非常豐富簡(jiǎn)單的類SQL的語法,用于篩選符合條件的日志內(nèi)容

    image.png

  3. 分析語法 大量的分析語法和函數(shù),用得上的用不上的都有(甚至還包括了機(jī)器學(xué)習(xí)語法和函數(shù))。。,主要是用于對(duì)篩選出來的日志進(jìn)行二次處理

    image.png

image.png
  1. 可視化圖表和告警 這是我們最需要的,默認(rèn)支持的已經(jīng)覆蓋我們目前的應(yīng)用場(chǎng)景了,后面會(huì)有真實(shí)線上服務(wù)可視化監(jiān)控截圖
    image.png

micrometer

  1. micrometer是一個(gè)非常短小精悍的基于JAVA實(shí)現(xiàn)的系統(tǒng)指標(biāo)監(jiān)控底層組件,spring cloud metric默認(rèn)就是使用micrometer,官方也提供了很多市面上流行的監(jiān)控系統(tǒng)實(shí)現(xiàn)方案(可以看到圖片里圈紅的influx和prometheus),那么我們要做的就是模仿實(shí)現(xiàn)一套基于阿里云SLS的解決方案

    image.png

  2. meter 主要就是以下6種類型

    image.png

SlsMeter

重頭戲來了,要想實(shí)現(xiàn)類似prometheus時(shí)序性數(shù)據(jù)收集功能,那么我得把各種類型的meter數(shù)據(jù)記錄在內(nèi)存中后,定期隔間時(shí)間推送給SLS日志服務(wù)器,然后通過查詢和分析語法即可到我們的目的,總體架構(gòu)圖如下:


image.png
  1. SlsMeter
/**
 * sls基礎(chǔ)計(jì)量類
 *
 * @author ty
 */
public class SlsMeter {
    private final String name;
    private final Map<String, String> tags;
    private final String type;
    private final long time;

    public SlsMeter(String name, Map<String, String> tags, String type, long time) {
        this.name = name;
        this.tags = Collections.unmodifiableMap(tags);
        this.type = type;
        this.time = time;
    }

    public String getName() {
        return name;
    }

    public Map<String, String> getTags() {
        return tags;
    }

    public String getType() {
        return type;
    }

    public long getTime() {
        return time;
    }

    @Override
    public String toString() {
        return "SlsMeter{" +
                "name='" + name + '\'' +
                ", tags=" + tags +
                ", type='" + type + '\'' +
                ", time=" + time +
                '}';
    }
}
  • name 標(biāo)記收集指標(biāo)信息的唯一性,eg:jvm_memory_used,jvm_memory_max
  • tags 同一指標(biāo)信息會(huì)有不同維度,特別適合分組統(tǒng)計(jì),eg:id=>PS Eden Space,id=>PS Old Gen,通過tag就可以實(shí)現(xiàn)不同代內(nèi)存的使用情況
  • type meter類型,對(duì)應(yīng)micromerter的6種meter,只不過做了重新劃分
/**
 * 計(jì)量類型
 *
 * @author ty
 */
public enum MetricType {
    /**
     * {@link io.micrometer.core.instrument.Counter} AND {@link io.micrometer.core.instrument.FunctionCounter}
     */
    COUNTER("counter"),
    /**
     * {@link io.micrometer.core.instrument.Gauge} AND {@link io.micrometer.core.instrument.TimeGauge}
     */
    GAUGE("gauge"),
    /**
     * {@link io.micrometer.core.instrument.Timer} AND {@link io.micrometer.core.instrument.FunctionTimer}
     * AND {@link io.micrometer.core.instrument.DistributionSummary}
     */
    HISTOGRAM("histogram"),
    /**
     * {@link io.micrometer.core.instrument.LongTaskTimer}
     */
    LONG_TASK_TIMER("long_task_timer"),
    /**
     * unknown
     */
    UNKNOWN("unknown");
    private final String type;

    MetricType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}
  1. meter子類 全部繼承SlsMeter這個(gè)基類,實(shí)現(xiàn)不同的值類型計(jì)算,這里只截取一部分代碼,詳細(xì)代碼可以在我的codingman1990拉取
    image.png
/**
 * counter
 *
 * @author ty
 */
public class SlsCounter extends SlsMeter {
    private BigDecimal value;

    public SlsCounter(String name, Map<String, String> tags, String type, long time) {
        super(name, tags, type, time);
    }

    public BigDecimal getValue() {
        return value;
    }

    public void setValue(BigDecimal value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "SlsCounter{" +
                super.toString() +
                "value=" + value +
                '}';
    }
}
/**
 * meter
 *
 * @author ty
 */
public class SlsTimer extends SlsMeter {
    private BigDecimal sum;
    private long count;
    private BigDecimal mean;
    private BigDecimal upper;

    public SlsTimer(String name, Map<String, String> tags, String type, long time) {
        super(name, tags, type, time);
    }

    public BigDecimal getSum() {
        return sum;
    }

    public void setSum(BigDecimal sum) {
        this.sum = sum;
    }

    public long getCount() {
        return count;
    }

    public void setCount(long count) {
        this.count = count;
    }

    public BigDecimal getMean() {
        return mean;
    }

    public void setMean(BigDecimal mean) {
        this.mean = mean;
    }

    public BigDecimal getUpper() {
        return upper;
    }

    public void setUpper(BigDecimal upper) {
        this.upper = upper;
    }

    @Override
    public String toString() {
        return "SlsTimer{" +
                super.toString() +
                "sum=" + sum +
                ", count=" + count +
                ", mean=" + mean +
                ", upper=" + upper +
                '}';
    }
}
  1. SlsMeterRegistry 基于SLS實(shí)現(xiàn)的各項(xiàng)指標(biāo)數(shù)據(jù)注冊(cè)器,也可理解為指標(biāo)數(shù)據(jù)收集器,其實(shí)底層就是基于記錄文本日志實(shí)現(xiàn)的,等待SLS客戶端ilogtail收集上傳到遠(yuǎn)端日志服務(wù)器。核心代碼如下:
/**
 * 阿里云日志服務(wù)meter采集
 *
 * @author ty
 */
public class SlsMeterRegistry extends StepMeterRegistry {
    @Override
    protected void publish() {
        createLoggerIfNecessary();
        this.getMeters().forEach(meter -> {
            SlsMeter slsMeter;
            if (meter instanceof Counter) {
                slsMeter = writeCounter((Counter) meter);
            } else if (meter instanceof FunctionCounter) {
                slsMeter = writeCounter((FunctionCounter) meter);
            } else if (meter instanceof Gauge) {
                slsMeter = writeGauge((Gauge) meter);
            } else if (meter instanceof Timer) {
                slsMeter = writeTimer((Timer) meter);
            } else if (meter instanceof FunctionTimer) {
                slsMeter = writeTimer((FunctionTimer) meter);
            } else if (meter instanceof DistributionSummary) {
                slsMeter = writeDistributionSummary((DistributionSummary) meter);
            } else if (meter instanceof LongTaskTimer) {
                slsMeter = writeLongTaskTimer((LongTaskTimer) meter);
            } else {
                slsMeter = writeUnknownMeter(meter);
            }
            log(slsMeter);
        });
    }
}

再加上具體的每一個(gè)Meter讀取轉(zhuǎn)化為我們想要的數(shù)據(jù)格式


image.png
  1. AutoConfiguration 使用spring boot永遠(yuǎn)少不了的自動(dòng)配置,依靠配置文件即可自動(dòng)開啟該功能
/**
 * sls集成micrometer自動(dòng)配置
 *
 * @author ty
 */
@Configuration
@AutoConfigureBefore({CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class})
@AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class)
@ConditionalOnProperty(prefix = "management.metrics.export.sls", name = "enabled", havingValue = "true")
@EnableConfigurationProperties(SlsProperties.class)
public class SlsMetricsExportAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public SlsConfig slsConfig(SlsProperties slsProperties) {
        return new SlsPropertiesConfigAdapter(slsProperties);
    }

    @Bean
    @ConditionalOnMissingBean
    public SlsMeterRegistry slsMeterRegistry(SlsConfig slsConfig, Clock clock) {
        return new SlsMeterRegistry(slsConfig, clock);
    }
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.epet.microservices.common.metrics.export.sls.SlsMetricsExportAutoConfiguration

效果展示

這里我把之前使用SLS實(shí)現(xiàn)的展示效果和現(xiàn)在使用Prometheus實(shí)現(xiàn)的效果放在一起對(duì)比(因?yàn)榻^大部分系統(tǒng)已經(jīng)遷移到prometheus,所以會(huì)有部分sls截圖無數(shù)據(jù)),可以發(fā)現(xiàn)每一項(xiàng)功能都是可以實(shí)現(xiàn)的,不過確實(shí)grafana展示效果更炫。

  1. 監(jiān)控總覽
    image.png

    image.png
  1. JVM
    image.png

    image.png
image.png

image.png
  1. Tomcat
    image.png
image.png
  1. ThreadPool
    image.png
image.png
  1. HikariCP
    image.png
image.png
  1. Hystrix
    image.png
image.png

結(jié)論

基于阿里云SLS日志服務(wù)是完全可實(shí)現(xiàn)和prometheus+grafana一致的可視化系統(tǒng)監(jiān)控功能,不過確實(shí)grafana看起來會(huì)更高大上一些,而且畢竟是開源,所以prometheus+grafana作為首選更合適。而文章提出的這種基于阿里云SLS日志服務(wù)實(shí)現(xiàn)的思路更適合一些本身已經(jīng)在使用這個(gè)產(chǎn)品的團(tuán)隊(duì),或者作為另外一種嘗試的野路子。詳細(xì)代碼可移步我的github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容