sentinel-源码是何如实现服务治理的

sentinel服务治理, 一般是使用@SentinelResource注解配置,
那么可以大胆猜想一下实现应该是AOP
接下来看源码来验证猜想

一、 pom引入sentinel依赖jar

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

二、 找到starter-alibaba-sentinel, 找到spring.factoried的SentinelAutoConfiguration类

在这里插入图片描述

三、 在SentinelAutoConfiguration类里, 我们看到了一个*Aspect的类 -> SentinelResourceAspect

@Aspect
public class SentinelResourceAspect extends AbstractSentinelAspectSupport {

    @Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)")
    public void sentinelResourceAnnotationPointcut() {
    }

    @Around("sentinelResourceAnnotationPointcut()")
    public Object invokeResourceWithSentinel(ProceedingJoinPoint pjp) throws Throwable {
        Method originMethod = resolveMethod(pjp);

        ...
        
        try {
            entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());
            // 对aop有了解的, 都知道pjp.proceed()是执行本身逻辑, 
            // 那么上面这一行SphU.entry 一定就是服务治理逻辑的那一层了
            Object result = pjp.proceed();
            return result;
        } catch (BlockException ex) {
            return handleBlockException(pjp, annotation, ex);
        } catch (Throwable ex) {
            Class<? extends Throwable>[] exceptionsToIgnore = annotation.exceptionsToIgnore();
            // The ignore list will be checked first.
            if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) {
                throw ex;
            }
            if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) {
                traceException(ex);
                return handleFallback(pjp, annotation, ex);
            }

            // No fallback function can handle the exception, so throw it out.
            throw ex;
        } finally {
            if (entry != null) {
                entry.exit(1, pjp.getArgs());
            }
        }
    }
}

四、 构建SlotChain链路

SphU entry

public static Entry entry(String name, int resourceType, EntryType trafficType, Object[] args)
    throws BlockException {
    // new CtSph().entryWithType
    return Env.sph.entryWithType(name, resourceType, trafficType, 1, args);
}

CtSph entryWithPriority

private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args) throws BlockException {
    Context context = ContextUtil.getContext();
    
    ...
	
	// 核心 链路模式
	// 构建服务治理一系列类的chain
	// 构建会触发DefaultSlotChainBuilder.build方法 如下
    ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);

    /*
     * Means amount of resources (slot chain) exceeds {@link Constants.MAX_SLOT_CHAIN_SIZE},
     * so no rule checking will be done.
     */
    if (chain == null) {
        return new CtEntry(resourceWrapper, null, context);
    }

    Entry e = new CtEntry(resourceWrapper, chain, context);
    try {
        chain.entry(context, resourceWrapper, null, count, prioritized, args);
    } catch (BlockException e1) {
        e.exit(count, args);
        throw e1;
    } catch (Throwable e1) {
        // This should not happen, unless there are errors existing in Sentinel internal.
        RecordLog.info("Sentinel unexpected exception", e1);
    }
    return e;
}
public class DefaultSlotChainBuilder implements SlotChainBuilder {

    @Override
    public ProcessorSlotChain build() {
        ProcessorSlotChain chain = new DefaultProcessorSlotChain();

        // 实例化所有实现了ProcessorSlot的类
        // 截图如下
        List<ProcessorSlot> sortedSlotList = SpiLoader.loadPrototypeInstanceListSorted(ProcessorSlot.class);
        for (ProcessorSlot slot : sortedSlotList) {
            if (!(slot instanceof AbstractLinkedProcessorSlot)) {
                RecordLog.warn("The ProcessorSlot(" + slot.getClass().getCanonicalName() + ") is not an instance of AbstractLinkedProcessorSlot, can't be added into ProcessorSlotChain");
                continue;
            }

            chain.addLast((AbstractLinkedProcessorSlot<?>) slot);
        }

        return chain;
    }
}

在这里插入图片描述
Slot中的@SpiOrder() 从小到大 构建出了一个SlotChain
流控 - FlowSlot
日志 - logSlot
统计 - StatisticSlot(相应时间等等)
系统cpu相关控制 - SystemSlot
服务降级 - DegradeSlot
权限 - AuthoritySlot

五、 逻辑方法的finally exit方法

看一个服务降级DegradeSlot的exit方法
onRequestComplete()

calss ExceptionCircuitBreaker

@Override
private void handleStateChangeWhenThresholdExceeded(Throwable error) {
    if (currentState.get() == State.OPEN) {
        return;
    }
    
    // HALF_OPEN 半开
    if (currentState.get() == State.HALF_OPEN) {
        // In detecting request
        if (error == null) {
        	//如果不报错 直接关闭断路器
            fromHalfOpenToClose();
        } else {
        	// 设置snapshotValue
            fromHalfOpenToOpen(1.0d);
        }
        return;
    }
    
    List<SimpleErrorCounter> counters = stat.values();
    long errCount = 0;
    long totalCount = 0;
    for (SimpleErrorCounter counter : counters) {
        errCount += counter.errorCount.sum();
        totalCount += counter.totalCount.sum();
    }
    if (totalCount < minRequestAmount) {
        return;
    }
    double curCount = errCount;
    if (strategy == DEGRADE_GRADE_EXCEPTION_RATIO) {
        // Use errorRatio
        curCount = errCount * 1.0d / totalCount;
    }
    // 错误率大于阈值 打开断路器
    if (curCount > threshold) {
        transformToOpen(curCount);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值