源码坐标:package io.vertx.circuitbreaker.impl.CircuitBreakerImpl中内部类,是断路器Circuit Breaker中的循环计数器。
使用场景:Circuit Breaker通过统计时间窗口内的请求失败次数,如果超出阈值,则判定请求对象已无效,给予“熔断”。RollingCounter承担主要功能。
1.CircuitBreakerOptions设定阈值。
private static final int DEFAULT_FAILURES_ROLLING_WINDOW = 10000;
private long failuresRollingWindow = DEFAULT_FAILURES_ROLLING_WINDOW;
public CircuitBreakerOptions setFailuresRollingWindow(long failureRollingWindow) {
this.failuresRollingWindow = failureRollingWindow;
return this;
}
2.创建失败循环计数。
this.rollingFailures = new RollingCounter(options.getFailuresRollingWindow() / 1000, TimeUnit.SECONDS);
3.RollingCounter
public static class RollingCounter {
private Map<Long, Long> window;
private long timeUnitsInWindow;
private TimeUnit windowTimeUnit;
public RollingCounter(long timeUnitsInWindow, TimeUnit windowTimeUnit) {
this.windowTimeUnit = windowTimeUnit;
//创建一个有序Map,容量为时间区间,比如传入100,容量为101
//用来容纳时间区间内的次数
//---其实就是时间窗口
this.window = new LinkedHashMap<>((int) timeUnitsInWindow + 1);
this.timeUnitsInWindow = timeUnitsInWindow;
}
public void increment() {
//记录一次调用
long timeSlot = windowTimeUnit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
Long current = window.getOrDefault(timeSlot, 0L);
window.put(timeSlot, ++current);
//超出容量,删除最早那条
//---维持窗口大小
if (window.size() > timeUnitsInWindow) {
Iterator<Long> iterator = window.keySet().iterator();
if (iterator.hasNext()) {
window.remove(iterator.next());
}
}
}
public long count() {
//统计时间区间内调用次数
//---判定是否可以熔断
long windowStartTime = windowTimeUnit.convert(System.currentTimeMillis() - windowTimeUnit.toMillis(timeUnitsInWindow), TimeUnit.MILLISECONDS);
return window.entrySet().stream().filter(entry -> entry.getKey() >= windowStartTime).mapToLong(entry -> entry.getValue()).sum();
}
public void reset() {
window.clear();
}
}
4.当断则断
private synchronized void incrementFailures() {
rollingFailures.increment();
if (rollingFailures.count() >= options.getMaxFailures()) {
if (state != CircuitBreakerState.OPEN) {
open();
}
}
}
*LinkedHashMap简单理解为有顺序的HashMap,可以同时兼顾查值与按顺序删除操作,非常契合时间窗口的场景。