springboot的HealthAggregator

对于系统服务的监控,tcp层通常是用heartbeat来进行,最简单的比如ping-pong。对于http层,来说springboot的actuator内置了/health的endpoint,很方便地规范了每个服务的健康状况的api,而且HealthIndicator可以自己去扩展,增加相关依赖服务的健康状态,非常灵活方便而且可扩展。

/health实例

{
  "status": "UP",
  "custom": {
    "status": "UNKNOWN",
    "custom": {
      "status": "UNKNOWN",
      "msg": "mock down to test aggregator"
    }
  },
  "diskSpace": {
    "status": "UP",
    "total": 249779191808,
    "free": 57925111808,
    "threshold": 10485760
  }
}

status枚举

    /**
     * Convenient constant value representing unknown state.
     */
    public static final Status UNKNOWN = new Status("UNKNOWN");

    /**
     * Convenient constant value representing up state.
     */
    public static final Status UP = new Status("UP");

    /**
     * Convenient constant value representing down state.
     */
    public static final Status DOWN = new Status("DOWN");

    /**
     * Convenient constant value representing out-of-service state.
     */
    public static final Status OUT_OF_SERVICE = new Status("OUT_OF_SERVICE");

/health的两个贴心点

对于多个HealthIndicator的status,spring boot默认对其进行aggregrate,然后计算最顶层的status字段的值,而且对于status是DOWN或者是OUT_OF_SERVICE的,返回的http的状态码是503,这对于应用监控系统来说真是大大的贴心啊,再总结一下:

  • 自动聚合多个HealthIndicator的status
  • 对于status是DOWN或者是OUT_OF_SERVICE的,返回503

这样应用监控系统一来就无需去解析返回结果,直接根据http的状态码就可以判断了,非常方便,太省心了有没有。

HealthAggregator

/**
 * Base {@link HealthAggregator} implementation to allow subclasses to focus on
 * aggregating the {@link Status} instances and not deal with contextual details etc.
 *
 * @author Christian Dupuis
 * @author Vedran Pavic
 * @since 1.1.0
 */
public abstract class AbstractHealthAggregator implements HealthAggregator {

    @Override
    public final Health aggregate(Map<String, Health> healths) {
        List<Status> statusCandidates = new ArrayList<Status>();
        for (Map.Entry<String, Health> entry : healths.entrySet()) {
            statusCandidates.add(entry.getValue().getStatus());
        }
        Status status = aggregateStatus(statusCandidates);
        Map<String, Object> details = aggregateDetails(healths);
        return new Health.Builder(status, details).build();
    }

    /**
     * Return the single 'aggregate' status that should be used from the specified
     * candidates.
     * @param candidates the candidates
     * @return a single status
     */
    protected abstract Status aggregateStatus(List<Status> candidates);

    /**
     * Return the map of 'aggregate' details that should be used from the specified
     * healths.
     * @param healths the health instances to aggregate
     * @return a map of details
     * @since 1.3.1
     */
    protected Map<String, Object> aggregateDetails(Map<String, Health> healths) {
        return new LinkedHashMap<String, Object>(healths);
    }

}

OrderedHealthAggregator#aggregateStatus

    @Override
    protected Status aggregateStatus(List<Status> candidates) {
        // Only sort those status instances that we know about
        List<Status> filteredCandidates = new ArrayList<Status>();
        for (Status candidate : candidates) {
            if (this.statusOrder.contains(candidate.getCode())) {
                filteredCandidates.add(candidate);
            }
        }
        // If no status is given return UNKNOWN
        if (filteredCandidates.isEmpty()) {
            return Status.UNKNOWN;
        }
        // Sort given Status instances by configured order
        Collections.sort(filteredCandidates, new StatusComparator(this.statusOrder));
        return filteredCandidates.get(0);
    }

可以看出是对status进行排序,然后取第一个的状态,其中statusOrder如下:

private List<String> statusOrder;

    /**
     * Create a new {@link OrderedHealthAggregator} instance.
     */
    public OrderedHealthAggregator() {
        setStatusOrder(Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN);
    }

排序方法

/**
     * {@link Comparator} used to order {@link Status}.
     */
    private class StatusComparator implements Comparator<Status> {

        private final List<String> statusOrder;

        StatusComparator(List<String> statusOrder) {
            this.statusOrder = statusOrder;
        }

        @Override
        public int compare(Status s1, Status s2) {
            int i1 = this.statusOrder.indexOf(s1.getCode());
            int i2 = this.statusOrder.indexOf(s2.getCode());
            return (i1 < i2 ? -1 : (i1 == i2 ? s1.getCode().compareTo(s2.getCode()) : 1));
        }

    }

即Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN优先级依次递减。status中一旦有出现DOWN的情况,整体的status就是DOWN,依次类推。

doc

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,569评论 18 139
  • 一、Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows、Linux和Uni...
    1b3bd36d9d21阅读 8,123评论 3 13
  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,311评论 0 23
  • 最近认识了一个朋友做逆向开发,稍微了解了一下,发现对于逆向开发很感兴趣,晚上下班回来也看了一些资料(其实是因...
    剑未佩妥阅读 417评论 0 2
  • 看了他的电影又看了纪录片,出了艳照门这件事之后对他打击很大,但同时也给他力量,在这8年的时间里他一直在寻找自己力求...
    小秋秋球球阅读 392评论 0 0