Sentinel 流控执行流程源码详解(上)

前言

Sentinel是阿里开源的一个面向分布式服务架构的轻量级高可用流量控制组件。但是Sentinel源码中存在很多的bug,如果要用在生产环境中,就必须要熟悉Sentinel的源码。

Sentinel在微服务中的使用方式

添加 @SentinelResource
 @SentinelResource(value = "findOrderByUserId",
            blockHandlerClass = CommonBlockHandler.class,
            blockHandler = "handleException2")
    public R  findOrderByUserId(@PathVariable("id") Integer id) {
        return result;
    }
直接在Sentinel控制台配置相应的规则

在这里插入图片描述
这两种方式中第一种方式的实现方式很容易猜出来,大致使用的是AOP,实际源码的实现方式也是AOP,第二种方式不好猜,但是也能想得到,处理流控降级都是在请求的链路上,肯定用到的是springmvc的interceptor类似的东西。

源码分析

Sentinel的集成
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

熟悉Spring boot 的都知道,带有spring-cloud-starter类似的都是使用的spring boot的自动装配原理,因此直接找到spring-cloud-starter-alibaba-sentinel下的spring.factories。查看自动装配的都有哪些类。
在这里插入图片描述
很容易就能看到有一个SentinelAutoConfiguration,这个肯定就是自动配置的入口类,进入到SentinelAutoConfiguration,浏览一下整体类的内容,并不多,只是少许的几个Bean,查看bean的名字发现有一个SentinelResourceAspect ,很容易就能和上面的 @SentinelResource联想起来,如下所示:

	@Bean
	@ConditionalOnMissingBean
	public SentinelResourceAspect sentinelResourceAspect() {
		return new SentinelResourceAspect();
	}
Sentinel的Aop实现

接下来进入SentinelResourceAspect类中,发现SentinelResourceAspect类其实就是AOP的切面类,进入到@Around如下所示:

@Around("sentinelResourceAnnotationPointcut()")
    public Object invokeResourceWithSentinel(ProceedingJoinPoint pjp) throws Throwable {
        Method originMethod = resolveMethod(pjp);
		
        SentinelResource annotation = originMethod.getAnnotation(SentinelResource.class);
        if (annotation == null) {
            // Should not go through here.
            throw new IllegalStateException("Wrong state for SentinelResource annotation");
        }
        String resourceName = getResourceName(annotation.value(), originMethod);
        EntryType entryType = annotation.entryType();
        int resourceType = annotation.resourceType();
        Entry entry = null;
        try {
        	//在执行原生方法前进行Sentinel一系列的验证
            entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());
            //执行原生方法
            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) {
            //在执行原生方法后进行Sentinel一系列的统计相关方法
                entry.exit(1, pjp.getArgs());
            }
        }
    }

源码中很容易看的出来 Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);是进行Sentinel流控链路校验的地方,当然如果对Sentinel很熟悉的,都知道Sentinel在Spring项目中单独使用的时候使用的方法也是SphU.entry(),因此可以断定Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);就是我们要找的核心方法。
有上面可以知道Sentinel流控验证的核心方法时SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);,而Sentinel在集成过程中有两种方式,一种是注解,一种是拦截器,基于注解@SentinelResource我们已经分析过了,对应的执行流程如下:
在这里插入图片描述

Sentinel的Interceptor实现

同样查看Spring.factories可以看到SentinelWebAutoConfiguration类,如下所示:
在这里插入图片描述
进入SentinelWebAutoConfiguration中,查看源码,核心方法如下所示:
在这里插入图片描述
这里不多做讲解,熟悉SpringMVC的很容易明白实现原理,进入SentinelWebInterceptor,发现上面有一个抽象类AbstractSentinelInterceptor,这里使用抽象类的作用类似于模板设计模式,把很多相同的代码都抽离出来了,Sentinel很多地方都用到这样的方式,然后直接进入AbstractSentinelInterceptor,如下所示:在这里插入图片描述
都知道拦截器的核心方法是preHandle,postHandle,和afterCompletion。preHandle在调用方法前执行,到这里Sentinel流控执行之前的调用逻辑就完成了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值