Springboot Actuator之五:Springboot中的HealthAggregator、新增自定义Status
阅读原文时间:2021年08月11日阅读:1

springboot的actuator内置了/health的endpoint,很方便地规范了每个服务的健康状况的api,而且HealthIndicator可以自己去扩展,增加相关依赖服务的健康状态,非常灵活方便而且可扩展。

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

org.springframework.boot.actuate.health.Status.java

@JsonInclude(Include.NON_EMPTY)
public final class Status {

/\*\*  
 \* {@link Status} indicating that the component or subsystem is in an unknown state.  
 \*/  
public static final Status UNKNOWN = new Status("UNKNOWN");

/\*\*  
 \* {@link Status} indicating that the component or subsystem is functioning as  
 \* expected.  
 \*/  
public static final Status UP = new Status("UP");

/\*\*  
 \* {@link Status} indicating that the component or subsystem has suffered an  
 \* unexpected failure.  
 \*/  
public static final Status DOWN = new Status("DOWN");

/\*\*  
 \* {@link Status} indicating that the component or subsystem has been taken out of  
 \* service and should not be used.  
 \*/  
public static final Status OUT\_OF\_SERVICE = new Status("OUT\_OF\_SERVICE");

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

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

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

看看AbstractHealthAggregator.java的抽象类,其中对状态的聚合是abstract的。

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类,增加了 GIT_WARNING

public class OrderedHealthAggregator extends AbstractHealthAggregator {

private List<String> statusOrder;

public static final Status GIT\_WARNING = new Status("GIT\_WARNING", "警告:config-server连不上gitlab,请及时处理.");

/\*\*  
 \* Create a new {@link OrderedHealthAggregator} instance.  
 \*/  
public OrderedHealthAggregator() {  
    setStatusOrder(Status.DOWN, Status.OUT\_OF\_SERVICE, GIT\_WARNING,  Status.UP, Status.UNKNOWN);  
}

/\*\*  
 \* Set the ordering of the status.  
 \* @param statusOrder an ordered list of the status  
 \*/  
public void setStatusOrder(Status... statusOrder) {  
    String\[\] order = new String\[statusOrder.length\];  
    for (int i = 0; i < statusOrder.length; i++) {  
        order\[i\] = statusOrder\[i\].getCode();  
    }  
    setStatusOrder(Arrays.asList(order));  
}

/\*\*  
 \* Set the ordering of the status.  
 \* @param statusOrder an ordered list of the status codes  
 \*/  
public void setStatusOrder(List<String> statusOrder) {  
    Assert.notNull(statusOrder, "StatusOrder must not be null");  
    this.statusOrder = statusOrder;  
}

@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) {  
        //只识别Status.DOWN, Status.OUT\_OF\_SERVICE, GIT\_WARNING,  Status.UP, Status.UNKNOWN几种状态  
        if (this.statusOrder.contains(candidate.getCode())) {  
            filteredCandidates.add(candidate);  
        }  
    }  
    // If no status is given return UNKNOWN  
    if (filteredCandidates.isEmpty()) {  
        return Status.UNKNOWN;  
    }  
    //对多个结果状态的排序,按照各个状态在statusOrder集合中的位置排序  
    Collections.sort(filteredCandidates, new StatusComparator(this.statusOrder));

    //返回排在最上面的那个状态值  
    return filteredCandidates.get(0);  
}

/\*\*  
 \* {@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) {  
        //对多个结果状态的排序,按照各个状态在statusOrder集合中的位置排序  
        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, GIT_WARNING, Status.UP, Status.UNKNOWN优先级依次递减。status中一旦有出现DOWN的情况,整体的status就是DOWN,依次类推。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章