剑走偏锋:使用阿里云SLS日志服务实现类似prometheus+grafana可视化系统监控

欢迎关注我的github,以后所有文章源码都会陆续更新上去

随着微服务的流行,势必线上服务数量会越来越多,对每一个服务的管控也变得越来越繁琐,一个可视化的系统资源/性能监控成为刚需。通常我们都会选择一些开源的很常见的产品:prometheus+grafana几乎是一种默认选择,实际使用下来个人感觉确实也是体验最好的。
不过我司在去年未部署这一套方案前,JAVA团队已经有迫切需要可视化监控和报警的需求(JVM内存是否设置合理,GC花费时间到底有多少,线程池大小和队列是否够用,数据库连接池是否高效,hystrix是否触发熔断等等),没有可视化,全都是靠猜。而正好我们有使用阿里云的SLS日志服务产品,对其有一定程度的了解,加上本身也算是一种时序性数据解决方案,特别适合做系统监控。此篇文章只适用于已经使用阿里云SLS日志服务的团队作为另外一种实现思路的参考,通常我还是会推荐prometheus+grafana。

认识SLS

详细的介绍建议大家直接阅读官方文档,这里只做以下四点说明

  1. 日志内容 完整metric日志内容(还有一些日志本身附加很有用的信息),以及丰富的字段索引设置

    image.png

  2. 查询语法 非常丰富简单的类SQL的语法,用于筛选符合条件的日志内容

    image.png

  3. 分析语法 大量的分析语法和函数,用得上的用不上的都有(甚至还包括了机器学习语法和函数)。。,主要是用于对筛选出来的日志进行二次处理

    image.png

image.png
  1. 可视化图表和告警 这是我们最需要的,默认支持的已经覆盖我们目前的应用场景了,后面会有真实线上服务可视化监控截图
    image.png

micrometer

  1. micrometer是一个非常短小精悍的基于JAVA实现的系统指标监控底层组件,spring cloud metric默认就是使用micrometer,官方也提供了很多市面上流行的监控系统实现方案(可以看到图片里圈红的influx和prometheus),那么我们要做的就是模仿实现一套基于阿里云SLS的解决方案

    image.png

  2. meter 主要就是以下6种类型

    image.png

SlsMeter

重头戏来了,要想实现类似prometheus时序性数据收集功能,那么我得把各种类型的meter数据记录在内存中后,定期隔间时间推送给SLS日志服务器,然后通过查询和分析语法即可到我们的目的,总体架构图如下:


image.png
  1. SlsMeter
/**
 * sls基础计量类
 *
 * @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 标记收集指标信息的唯一性,eg:jvm_memory_used,jvm_memory_max
  • tags 同一指标信息会有不同维度,特别适合分组统计,eg:id=>PS Eden Space,id=>PS Old Gen,通过tag就可以实现不同代内存的使用情况
  • type meter类型,对应micromerter的6种meter,只不过做了重新划分
/**
 * 计量类型
 *
 * @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这个基类,实现不同的值类型计算,这里只截取一部分代码,详细代码可以在我的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实现的各项指标数据注册器,也可理解为指标数据收集器,其实底层就是基于记录文本日志实现的,等待SLS客户端ilogtail收集上传到远端日志服务器。核心代码如下:
/**
 * 阿里云日志服务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);
        });
    }
}

再加上具体的每一个Meter读取转化为我们想要的数据格式


image.png
  1. AutoConfiguration 使用spring boot永远少不了的自动配置,依靠配置文件即可自动开启该功能
/**
 * sls集成micrometer自动配置
 *
 * @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实现的展示效果和现在使用Prometheus实现的效果放在一起对比(因为绝大部分系统已经迁移到prometheus,所以会有部分sls截图无数据),可以发现每一项功能都是可以实现的,不过确实grafana展示效果更炫。

  1. 监控总览
    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

结论

基于阿里云SLS日志服务是完全可实现和prometheus+grafana一致的可视化系统监控功能,不过确实grafana看起来会更高大上一些,而且毕竟是开源,所以prometheus+grafana作为首选更合适。而文章提出的这种基于阿里云SLS日志服务实现的思路更适合一些本身已经在使用这个产品的团队,或者作为另外一种尝试的野路子。详细代码可移步我的github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349