resilience4j ratelimiter模块 源码解析

resilience4j 源码解析

ratelimiter模块

@Ratelimiter

Resilience4jRatelimiter与我们常用的接口限流原理相似,但在实现上考虑了更多的情况,使得限流更加安全可靠。通常我们在Spring中使用@Ratelimiter注解,因为它天然与Spring集成。下面是其源码及一些解析:

	@Pointcut(value = "@within(rateLimiter) || @annotation(rateLimiter)", argNames = "rateLimiter")
    public void matchAnnotatedClassOrMethod(RateLimiter rateLimiter) {
        // Method used as pointcut
    }

    @Around(value = "matchAnnotatedClassOrMethod(rateLimiterAnnotation)", argNames = "proceedingJoinPoint, 		rateLimiterAnnotation")
    public Object rateLimiterAroundAdvice(ProceedingJoinPoint proceedingJoinPoint,
        //注意这里可能是null是因为@RateLimiter在类上的情况。
        @Nullable RateLimiter rateLimiterAnnotation) throws Throwable {
        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        String methodName = method.getDeclaringClass().getName() + "#" + method.getName();
        if (rateLimiterAnnotation == null) {
            //获取类上的注解
            rateLimiterAnnotation = getRateLimiterAnnotation(proceedingJoinPoint);
        }
        if (rateLimiterAnnotation == null) { //because annotations wasn't found
            return proceedingJoinPoint.proceed();
        }
        //spring el表达式的解析
        String name = spelResolver.resolve(method, proceedingJoinPoint.getArgs(), 									rateLimiterAnnotation.name());
        //获取rateLimiter,核心类
        io.github.resilience4j.ratelimiter.RateLimiter rateLimiter = getOrCreateRateLimiter(methodName, 			name);
        Class<?> returnType = method.getReturnType();
        //重点,将proceedingJoinPoint进行了增强。返回值CheckedSupplier是仿照Supplier的,你可以看作是一个可调用的函数
        final CheckedSupplier<Object> rateLimiterExecution =
                () -> proceed(proceedingJoinPoint, methodName, returnType, rateLimiter);
        //fallbackMethod增强,执行。
        return fallbackExecutor.execute(proceedingJoinPoint, method, rateLimiterAnnotation.fallbackMethod(), 		rateLimiterExecution);
    }

这段代码展示了@Ratelimiter的切点和环绕通知的定义。关键在于rateLimiterAroundAdvice方法中对方法的增强,其中使用了RateLimiter的核心类来实现。

核心方法 - proceed

我们接下看上面的重点proceed方法做了什么

	private Object proceed(ProceedingJoinPoint proceedingJoinPoint, String methodName,
        Class<?> returnType, io.github.resilience4j.ratelimiter.RateLimiter rateLimiter) throws Throwable {
        //rateLimiterAspectExtList是用户自定义处理器,由spring管理的bean,体现了resilience4j 的灵活
        if (rateLimiterAspectExtList != null && !rateLimiterAspectExtList.isEmpty()) {
            for (RateLimiterAspectExt rateLimiterAspectExt : rateLimiterAspectExtList) {
                if (rateLimiterAspectExt.canHandleReturnType(returnType)) {
                    return rateLimiterAspectExt
                        .handle(proceedingJoinPoint, rateLimiter, methodName);
                }
            }
        }
        //CompletionStage是异步任务的顶级接口,如果返回值是异步任务的话执行不一样,在此不讨论。
        if (CompletionStage.class.isAssignableFrom(returnType)) {
            return handleJoinPointCompletableFuture(proceedingJoinPoint, rateLimiter);
        }
        //做增强,看下面。
        return handleJoinPoint(proceedingJoinPoint, rateLimiter);
    }

	//handleJoinPoint中有多层嵌套,我们直接看最后的。
 	static <T> CheckedSupplier<T> decorateCheckedSupplier(RateLimiter rateLimiter, int permits,
                                                          CheckedSupplier<T> supplier) {
        return () -> {
            //等待Permission,后面有解析
            waitForPermission(rateLimiter, permits);
            try {
                //执行proceedingJoinPoint::proceed
                T result = supplier.get();
                rateLimiter.onResult(result);
                //返回
                return result;
            } catch (Exception exception) {
                rateLimiter.onError(exception);
                throw exception;
            }
        };
    }

到这里我们就做完了增强。这个增强方法,会作为参数执行最后的语句。我们看看失败后是如何执行fallback的。

首先他会找注解中有没有fallback函数的定义。没有就不增强。有的话就执行

fallbackDecorators.decorate(fallbackMethod, primaryFunction).get();
//其中primaryFunction就是我们传进去的方法。官方将这个函数命名为decorate,是借鉴了装饰者模式的思想。
//下面看看怎么执行的
		return () -> {
            try {
                return supplier.get();
            } catch (IllegalReturnTypeException e) {
                throw e;
            } catch (Throwable throwable) {
                return fallbackMethod.fallback(throwable);
            }
        };
//将primaryFunction包了起来,出异常时就执行fallbackMethod。是不是很简单?

这就是@Ratelimiter 的工作原理。下面我们说说他是怎么限流的。

限流实现 - RateLimiter

acquirePermission 方法

RateLimiteracquirePermission方法是关键的限流实现:

	//AtomicRateLimiter实现
	@Override
    public boolean acquirePermission(final int permits) {
        //超时时间
        long timeoutInNanos = state.get().config.getTimeoutDuration().toNanos();
        //更新带有退避(back-off)机制的状态的方法
        State modifiedState = updateStateWithBackOff(permits, timeoutInNanos);
        //等待,返回是否等到了
        boolean result = waitForPermissionIfNecessary(timeoutInNanos, modifiedState.nanosToWait);
        //发送事件
        publishRateLimiterAcquisitionEvent(result, permits);
        return result;
    }

这段代码展示了如何实现RateLimiter的核心方法,其中包括了超时处理、状态更新以及等待许可。

其中的事件发布机制: publishRateLimiterAcquisitionEvent方法展示了在获取许可后,如何发布事件,这对于监控和日志记录非常重要。

updateStateWithBackOff方法
	//如果当前状态 prev 与计算出的下一个状态 next 相同,说明没有其他线程在之前修改过状态,这时就会设置新的状态并退出循环。否		则,继续循环,尝试更新状态。
	private State updateStateWithBackOff(final int permits, final long timeoutInNanos) {
        AtomicRateLimiter.State prev;
        AtomicRateLimiter.State next;
        do {
            prev = state.get();
            //这个方法的核心逻辑是根据当前的活动状态、许可数和超时时长计算下一个状态,确保在退避机制下正确管理许可。
            next = calculateNextState(permits, timeoutInNanos, prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

updateStateWithBackOff方法中,通过自旋方式不断尝试更新RateLimiter的状态,确保状态的一致性。

等待许可 - waitForPermission 方法

waitForPermissionIfNecessary方法调用了waitForPermission,但是waitForPermissionIfNecessary方法中,使用了parkNanos方法进行线程等待,这是一种有效控制线程等待时间的方式,有兴趣可以去看看

waitForPermission方法展示了如何等待许可的逻辑:

	private boolean waitForPermission(final long nanosToWait) {
        waitingThreads.incrementAndGet();
        long deadline = currentNanoTime() + nanosToWait;
        boolean wasInterrupted = false;
        while (currentNanoTime() < deadline && !wasInterrupted) {
            long sleepBlockDuration = deadline - currentNanoTime();
            parkNanos(sleepBlockDuration);
            wasInterrupted = Thread.interrupted();
        }
        waitingThreads.decrementAndGet();
        if (wasInterrupted) {
            currentThread().interrupt();
        }
        return !wasInterrupted;
    }

这段代码展示了在等待许可时的处理,其中使用了类似自旋的方式。

总结

Resilience4j的Ratelimiter模块通过简洁的代码实现了接口限流方法,为单体项目接口限流提供了一种可靠的选择。其实现原理清晰,通过注解和切面的方式,使得在Spring中的集成变得非常便捷。

关注湫湫喵~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值