CircuitBreakerMetrics

熔断器度量指标,熔断器在工作中,熔断相关实际数据,均存储在此。

类图关系如下:

 

成员变量

private final int ringBufferSize;//熔断在CLOSED,HALF_OPEN状态下的环形区缓冲大小

private final RingBitSet ringBitSet;//存储请求通过或被熔断次数

private final LongAdder numberOfNotPermittedCalls;//请求被熔断的次数

RingBitSet

CircuitBreaker在CLOSED 或 HALF_OPEN状态时,成功调用会在bit位存0,失败的调用会存储1。Ring Bit Buffer具有(可配置的)固定大小。Ring Bit Buffer 原理类似于java.util.BitSet。BitSet使用long []数组来存储这些位,意味着BitSet只需要一个16个长(64位)的long型数组就可存储1024个请求的调用状态。

 

在计算失败率之前,环位缓冲器必须已满。

例如,如果环形缓冲区的大小为10,则必须至少有10次请求,然后才能计算失败率。如果只请求了9次,哪怕9次都失败,CircuitBreaker也不会切换至OPEN状态。

在等待一段时间后,CircuitBreaker状态从OPEN → HALF_OPEN,并允许请求调用以观察后续请求是否仍然不可用或已再次可用。CircuitBreaker使用另一个(可配置的)环位缓冲区来评估HALF_OPEN状态中的失败率。如果失败率高于配置的阈值,则状态将更改回OPEN。如果失败率低于或等于阈值,则状态变回CLOSED。
CircuitBreaker::onError检查是否应将异常记录为失败或应忽略。可以配置自定义Predicate,以确定是否应将异常记录为失败。默认将所有异常记录为失败。

CircuitBreaker支持重置为原始状态(circuitBreaker::reset),丢失所有指标并重置其Ring Bit Buffer。

 

 

从截图中可以看出,请求成功时,setNextBit返回值不变,请求失败时,setNextBit返回值+1,从而可以得出setNextBit返回的是失败次数的结论,且该方法thread-safe。

public synchronized int setNextBit(boolean value) {
    //调用次数+1
    increaseLength();
    index = (index + 1) % size;
    //更新位值
    int previous = bitSet.set(index, value);
    int current = value ? 1 : 0;
    cardinality = cardinality - previous + current;
    //失败请求对应的number
    return cardinality;
}

//通俗的可以理解成比如设置环形缓冲区长度为10,则前9次,单纯调用次数length + 1,第10次,length为0,后续不再增加调用次数
private void increaseLength() {
    if (notFull) {
        //计算至本次总调用次数
        int nextLength = length + 1;
        if (nextLength < size) {
            //容量没满,总调用次数+1
            length = nextLength;
        } else {
            length = size;
            notFull = false;
        }
    }
}

总结:

  • RingBitSet::length 表示总请求次数
  • RingBitSet::setNextBit:(更新RingBitSet::cardinality)表示失败次数
  • 请求成功次数 = RingBitSet::length - RingBitSet::cardinality

检查阀值

private float getFailureRate(int numberOfFailedCalls) {
    //当总调用次数未达到环形缓冲区size时,暂不进行熔断检查
    if (getNumberOfBufferedCalls() < ringBufferSize) {
        return -1.0f;
    }
    //失败率 = 失败次数/环形缓冲区size * 100%
    return numberOfFailedCalls * 100.0f / ringBufferSize;
}