對於系統服務的監控,tcp層一般是用heartbeat來進行,最簡單的好比ping-pong。對於http層,來講springboot的actuator內置了/health的endpoint,很方便地規範了每一個服務的健康情況的api,並且HealthIndicator能夠本身去擴展,增長相關依賴服務的健康狀態,很是靈活方便並且可擴展。html
{ "status": "UP", "custom": { "status": "UNKNOWN", "custom": { "status": "UNKNOWN", "msg": "mock down to test aggregator" } }, "diskSpace": { "status": "UP", "total": 249779191808, "free": 57925111808, "threshold": 10485760 } }
/** * 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");
對於多個HealthIndicator的status,spring boot默認對其進行aggregrate,而後計算最頂層的status字段的值,並且對於status是DOWN或者是OUT_OF_SERVICE的,返回的http的狀態碼是503,這對於應用監控系統來講真是大大的貼心啊,再總結一下:spring
自動聚合多個HealthIndicator的statusapi
對於status是DOWN或者是OUT_OF_SERVICE的,返回503springboot
這樣應用監控系統一來就無需去解析返回結果,直接根據http的狀態碼就能夠判斷了,很是方便,太省心了有沒有。tcp
/** * 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); } }
@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以下:ide
private List<String> statusOrder; /** * Create a new {@link OrderedHealthAggregator} instance. */ public OrderedHealthAggregator() { setStatusOrder(Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN); }
排序方法spring-boot
/** * {@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,依次類推。ui
HealthAggregatorthis